Carousel en CSS con Mandatory y diapositivas en bloques de HTML

En algunas ocasiones necesitamos que cada diapositiva tenga HTML, en lugar de ser únicamente una imagen. Queremos añadir textos, títulos, etc. Es relativamente sencillo de construir gracias a CSS3 con un extra de JavaScript para automatizar el cambio entre ellas y su retardo. Entre sus características:

Demo

Código

El HTML es mínimo. Puedes añadir más diapositivas, o cambiar el HTML dentro del <article>. Solo debes mantener las clases en su lugar para que coincida con los selectores de JavaScript.

<section class="carousel">
  <div class="carousel__container">
    <article class="carousel__slider carousel__slider--1">
      <h1>Mi título 1</h1>
      <p>Mi HTML 1</p>
    </article>
    <article class="carousel__slider carousel__slider--2">
      <h1>Mi título 2</h1>
      <p>Mi HTML 2</p>
    </article>
    <article class="carousel__slider carousel__slider--3">
      <h1>Mi título 3</h1>
      <p>Mi HTML 3</p>
    </article>
  </div>
</section>

El CSS solo esta de ejemplo para maquetarlo mínimamente. Estiliza a tu gusto.

:root {
  --carousel-height: 20rem;
  --carousel-width: 40rem;
}
/* Oculta el scroll horizontal */
.carousel {
  height: var(--carousel-height);
  overflow: hidden;
  width: var(--carousel-width);
}

.carousel__container {
  scroll-snap-type: x mandatory;
  display: flex;
  overflow-x: auto;
}

.carousel__slider {
  height: var(--carousel-height);
  min-width: var(--carousel-width);
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center;
  scroll-snap-align: start;
}

.carousel__slider--1 {
  background-image: url("https://source.unsplash.com/featured/1000x400/?fish");
}

.carousel__slider--2 {
  background-image: url("https://source.unsplash.com/featured/1000x400/?cat");
}

.carousel__slider--3 {
  background-image: url("https://source.unsplash.com/featured/1000x400/?dog");
}

/* Estilos para la demo, pueden ser borrados */
.carousel__slider h1,
.carousel__slider p {
  color: white;
  text-shadow: 1px 1px 5px black;
}
/* Fin Estilos para la demo, pueden ser borrados */

Dentro del JavaScript te interesa revisar la variables.


// Variables
const SEGUNDOS_ENTRE_DIAPOSITIVAS = 2; // <---- IMPORTANTE
const CAROUSEL = document.querySelector(".carousel");
const SLIDERS = CAROUSEL.querySelectorAll(".carousel__slider");

// Funciones

async function autoPlay(posicionPartida = SLIDERS.length) {
  // Obtiene el siguiente indice
  const SIGUIENTE_POSICION =
    SLIDERS.length - 1 > posicionPartida ? posicionPartida + 1 : 0;
  // Mueve el scroll al siguiente slider
  SLIDERS[SIGUIENTE_POSICION].scrollIntoView({ block: "center" });
  // Retardo antes de volver a ejecutarse
  await new Promise((res) => {
    setTimeout(res, SEGUNDOS_ENTRE_DIAPOSITIVAS * 1000);
  });
  // Creamos un objeto IntersectionObserver
  observerCarousel = new IntersectionObserver((entries) => {
        // Comprobamos todas las intesecciones.
        entries.forEach((entry) => {
            // Si es observable, entra
            if (entry.isIntersecting) {
              // Activamos
              autoPlay(SIGUIENTE_POSICION)
            }
        });
    });

  // Añado a mi Observable que quiero observar. En este caso el carousel
  observerCarousel.observe(CAROUSEL);
}

// Ejecuta
autoPlay();


Ejemplo completo


<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Ejemplo</title>
    <style type="text/css" media="screen">
      :root {
        --carousel-height: 20rem;
        --carousel-width: 40rem;
      }
      /* Oculta el scroll horizontal */
      .carousel {
        height: var(--carousel-height);
        overflow: hidden;
        width: var(--carousel-width);
      }

      .carousel__container {
        scroll-snap-type: x mandatory;
        display: flex;
        overflow-x: auto;
      }

      .carousel__slider {
        height: var(--carousel-height);
        min-width: var(--carousel-width);
        background-repeat: no-repeat;
        background-size: cover;
        background-position: center;
        scroll-snap-align: start;
      }

      .carousel__slider--1 {
        background-image: url("https://source.unsplash.com/featured/1000x400/?fish");
      }

      .carousel__slider--2 {
        background-image: url("https://source.unsplash.com/featured/1000x400/?cat");
      }

      .carousel__slider--3 {
        background-image: url("https://source.unsplash.com/featured/1000x400/?dog");
      }

      /* Estilos para la demo, pueden ser borrados */
      .carousel__slider h1,
      .carousel__slider p {
        color: white;
        text-shadow: 1px 1px 5px black;
      }
      /* Fin Estilos para la demo, pueden ser borrados */
    </style>
</head>
<body>
  <section class="carousel">
    <div class="carousel__container">
      <article class="carousel__slider carousel__slider--1">
        <h1>Mi título 1</h1>
        <p>Mi HTML 1</p>
      </article>
      <article class="carousel__slider carousel__slider--2">
        <h1>Mi título 2</h1>
        <p>Mi HTML 2</p>
      </article>
      <article class="carousel__slider carousel__slider--3">
        <h1>Mi título 3</h1>
        <p>Mi HTML 3</p>
      </article>
    </div>
  </section>
  <script>
    // Variables
    const SEGUNDOS_ENTRE_SLIDERS = 2; // <---- IMPORTANT
    const CAROUSEL = document.querySelector(".carousel");
    const SLIDERS = CAROUSEL.querySelectorAll(".carousel__slider");
    let observerCarousel;

    // Funciones

    async function autoPlay(posicionPartida = SLIDERS.length) {
      // Elimina los IntersectionObserver para evitar que se reproduzca si no mira el usuario
      if(observerCarousel !== undefined) observerCarousel.unobserve(CAROUSEL)

      // Obtiene el siguiente indice
      const SIGUIENTE_POSICION =
        SLIDERS.length - 1 > posicionPartida ? posicionPartida + 1 : 0;
      // Mueve el scroll al siguiente slider
      SLIDERS[SIGUIENTE_POSICION].scrollIntoView({ block: "center" });
      // Retardo antes de volver a ejecutarse
      await new Promise((res) => {
        setTimeout(res, SEGUNDOS_ENTRE_SLIDERS * 1000);
      });
      // Ejecutamos el autoPlay únicamente cuando sea visible
      // Creamos un objeto IntersectionObserver
      observerCarousel = new IntersectionObserver((entries) => {
            // Comprobamos todas las intesecciones.
            entries.forEach((entry) => {
                // Si es observable, entra
                if (entry.isIntersecting) {
                  // Activamos
                  autoPlay(SIGUIENTE_POSICION)
                }
            });
        });

      // Añado a mi Observable que quiero observar. En este caso el carousel
      observerCarousel.observe(CAROUSEL);
    }

    // Ejecuta
    autoPlay();
  </script>
</body>
</html>

Si quieres un ejemplo sin bloques de HTML y mucho más simple: Sencillo carousel con controles y autoreproducción.

Este trabajo está bajo una licencia Attribution-NonCommercial-NoDerivatives 4.0 International.

¿Me invitas a un café?

Puedes usar el terminal.

ssh customer@andros.dev -p 5555

Escrito por Andros Fenollosa

agosto 21, 2021

5 min de lectura

Sigue leyendo