Comienza a usar animaciones basadas en desplazamientos en CSS

1. Antes de comenzar

Las animaciones basadas en desplazamientos te permiten controlar la reproducción de una animación en función de la posición en un contenedor de desplazamientos. Esto significa que a medida que te desplazas hacia arriba o hacia abajo, la animación se arrastra hacia delante o hacia atrás. Además, con esta función también puedes controlar una animación según la posición de un elemento dentro de su contenedor de desplazamiento. De esta forma, puedes crear efectos interesantes como imágenes de fondo con paralaje, imágenes que se revelan a medida que se visualizan y barras de progreso para desplazarse.

En Chrome 114 se agregó la compatibilidad con un conjunto de clases de JavaScript y propiedades de CSS que te permiten crear fácilmente animaciones declarativas basadas en desplazamientos. Estas APIs nuevas funcionan en conjunto con las APIs de Web Animations y CSS Animations.

En este codelab, aprenderás a crear animaciones basadas en desplazamientos mediante CSS. Una vez que lo termines, comprenderás las numerosas propiedades nuevas de CSS que ofrece esta excelente función, como scroll-timeline, view-timeline, animation-timeline y animation-range.

Qué aprenderás

  • Cómo crear un efecto de fondo con paralaje mediante un cronograma de desplazamiento en CSS
  • Cómo crear una barra de progreso mediante un cronograma de desplazamiento en CSS
  • Cómo crear un efecto de revelación de imagen mediante un cronograma de visualización en CSS
  • Cómo orientarse a los diferentes tipos de intervalos de un cronograma de visualización en CSS

Requisitos

Tener una de las siguientes combinaciones de dispositivos:

  • Una versión reciente de Chrome (114 o posterior) en ChromeOS, macOS o Windows
  • Conocimientos básicos sobre HTML
  • Conocimiento fundamental sobre CSS, particularmente relacionados con animaciones en CSS

2. Prepárate

Todo lo que necesitas para este proyecto se encuentra disponible en un repositorio de GitHub. Para comenzar, clona el código y ábrelo en tu entorno de desarrollo favorito.

  1. Abre una nueva pestaña del navegador y ve a https://github.com/googlechromelabs/io23-scroll-driven-animations-codelab.
  2. Clona el repositorio.
  3. Abre el código en tu IDE preferido.
  4. Ejecuta npm install para instalar las dependencias.
  5. Ejecuta npm start y visita http://localhost:3000/.
  6. Como alternativa, si no tienes instalado npm, abre el archivo src/index.html en Chrome.

3. Aprende sobre los cronogramas de animaciones

De forma predeterminada, una animación que se adjunta a un elemento se ejecuta en el cronograma del documento. Esto significa que cuando se carga la página, la animación avanza conforme avanza el tiempo. En eso consiste el cronograma predeterminado para animaciones y, hasta el día de hoy, era el único al que se podía acceder.

Con las animaciones basadas en desplazamientos, obtienes acceso a los siguientes dos tipos nuevos de cronogramas:

  • Cronograma del progreso del desplazamiento
  • Cronograma del progreso de la visualización

En CSS, estos cronogramas se pueden adjuntar a una animación mediante la propiedad animation-timeline. Descubre el significado de estos nuevos cronogramas y sus diferencias.

Cronograma del progreso del desplazamiento

Consiste en un cronograma de animación vinculado al progreso en la posición de desplazamiento de un contenedor de desplazamiento, conocido como puerto o barra de desplazamiento, a lo largo de un eje determinado. Convierte la posición de un intervalo de desplazamiento en un porcentaje de progreso dentro de un cronograma.

La posición inicial de desplazamiento representa un progreso del 0% y la posición final representa un progreso del 100%. En la siguiente visualización, observa que el progreso aumenta del 0% al 100% a medida que te desplazas por la barra de desplazamiento.

Cronograma del progreso de la visualización

Este tipo de cronograma se vincula al progreso relativo de un elemento particular dentro de un contenedor de desplazamiento. Al igual que en un cronograma del progreso del desplazamiento, se realiza el seguimiento del avance de una barra de desplazamiento. Pero, difieren en que es la posición relativa de un objeto dentro de ese cronograma lo que determina el progreso. Esta situación se compara con IntersectionObserver, que hace un seguimiento de la visibilidad de un elemento en la barra de desplazamiento. Si el elemento no se visualiza en la barra de desplazamiento, no hay una intersección. Si es visible en la barra de desplazamiento, incluso para la parte más pequeña, hay una intersección.

Un cronograma del progreso de visualización comienza desde el momento en el que un objeto comienza a cruzarse con la barra de desplazamiento y termina cuando deja de hacerlo. En la siguiente visualización, observa que el progreso comienza en 0% cuando el objeto ingresa al contenedor de desplazamiento y llega al 100% cuando sale de él.

De forma predeterminada, una animación vinculada al cronograma del progreso de visualización se adjunta a todo su intervalo. Esta comienza desde el momento en el que el objeto ingresa al puerto de desplazamiento y finaliza cuando sale de él.

También es posible vincularla a una parte específica del cronograma del progreso de visualización especificando el intervalo al que se debe adjuntar. Por ejemplo, solo cuando el objeto ingresa en la barra de desplazamiento. En la siguiente visualización, el progreso comienza en 0% cuando el objeto ingresa al contenedor de desplazamiento, pero ya alcanza el 100% desde el momento en que se conecta por completo.

Los posibles intervalos de cronogramas de visualización a los que te puedes orientar son cover, contain, entry, exit, entry-crossing y exit-crossing. Estos se explican más adelante en este codelab, pero si quieres obtener la información de inmediato, utiliza la herramienta ubicada en https://goo.gle/view-timeline-range-tool para descubrir lo que representa cada intervalo.

4. Crea un efecto de fondo con paralaje

El primer efecto que se debe agregar a la página es uno de efecto de fondo con paralaje sobre la imagen de fondo principal. A medida que te desplazas por la página, la imagen de fondo se debería mover, aunque a una velocidad diferente. Para lograrlo, recurre al cronograma del progreso del desplazamiento.

Sigue estos dos pasos para implementar esta práctica:

  1. Crea una animación que desplace la posición de la imagen de fondo.
  2. Vincula la animación al progreso de desplazamiento del documento.

Crea la animación

  1. Para crear la animación, usa un conjunto regular de fotogramas clave. En él, mueve la posición del fondo de 0% a 100% de forma vertical de la siguiente forma:

src/styles.css

@keyframes move-background {
  from {
    background-position: 50% 0%;
  }
  to {
    background-position: 50% 100%;
  }
}
  1. Ahora adjunta estos fotogramas clave al elemento del cuerpo:

src/styles.css

body {
  animation: 1s linear move-background;
}

Con este código, la animación move-background se agrega al elemento del cuerpo. Su propiedad animation-duration se define en un segundo y utiliza una aceleración linear.

La forma más sencilla para crear un cronograma del progreso del desplazamiento es usar la función scroll(). De esta forma, se crea un cronograma anónimo del progreso del desplazamiento que puedes configurar como el valor de la propiedad animation-timeline.

La función scroll() acepta los argumentos <scroller> y <axis>.

Los valores aceptados para el argumento <scroller> son los siguientes:

  • nearest. Utiliza el contenedor de desplazamiento principal más cercano (configuración predeterminada).
  • root. Utiliza el viewport del documento como el contenedor de desplazamiento.
  • self. Utiliza el elemento como contenedor de desplazamiento.

Los valores aceptados para el argumento <axis> son los siguientes:

  • block. Utiliza la medida de progreso junto con el eje de bloque del contenedor de desplazamiento (configuración predeterminada).
  • inline. Utiliza la medición del progreso junto con el eje de intercalado del contenedor de desplazamiento.
  • y. Utiliza la medida de progreso junto con el eje y del contenedor de desplazamiento.
  • x. Utiliza la medida de progreso junto con el eje x del contenedor de desplazamiento.

Para vincular la animación al desplazador raíz en el eje de bloque, los valores que se deben pasar a scroll() son root y block: scroll(root block).

  • Configura scroll(root block) como el valor de la propiedad animation-timeline en el cuerpo. Además, dado que no tiene sentido expresar un animation-duration en segundos, configura la duración en auto. Si no especificas un animation-duration, se usará el valor predeterminado auto.

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(root block);
}

Como la barra de desplazamiento raíz también es el elemento de desplazamiento superior más cercano para el elemento del cuerpo, puedes utilizar un valor de nearest:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(nearest block);
}

Dado que nearest y block son valores predeterminados, puedes elegir omitirlos. En ese caso, el código se puede simplificar a la siguiente opción:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll();
}

Verifica tus cambios

Si no tuviste inconvenientes, te debería aparecer lo siguiente:

Si no es así, verifica la rama solution-step-1 del código.

5. Crea una barra de progreso para la galería de imágenes

En la página hay un carrusel horizontal que necesita una barra de progreso para indicar qué foto se está viendo en ese momento.

La marca del carrusel se ve así:

src/index.html

<div class="gallery">
  <div class="gallery__scrollcontainer" style="--num-images: 3;">
    <div class="gallery__progress"></div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
  </div>
</div>

Los fotogramas clave para la barra de progreso ya están ubicados y se ven así:

src/styles.css

@keyframes adjust-progress {
  from {
    transform: scaleX(calc(1 / var(--num-images)));
  }
  to {
    transform: scaleX(1);
  }
}

Esta animación se debe adjuntar al elemento .gallery__progress mediante un cronograma del progreso del desplazamiento. Como se muestra en el paso anterior, puedes lograr esto creando un cronograma anónimo del progreso del desplazamiento con la función scroll():

src/styles.css

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  animation-timeline: scroll(nearest inline);
}

Una forma alternativa para definir el cronograma del progreso de desplazamiento es usar uno que tenga nombre. Es un proceso un poco más detallado, pero puede ser útil cuando no te orientas a una barra de desplazamiento superior o a la barra de desplazamiento raíz, o cuando la página utiliza múltiples cronogramas. De esta forma, puedes identificar un cronograma del progreso del desplazamiento por el nombre que le asignaste.

Para crear un cronograma del progreso del desplazamiento con nombre en un elemento, configura la propiedad CSS de scroll-timeline-name en el contenedor de desplazamiento en un valor de tu preferencia.

Dado que la galería se desplaza de forma horizontal, también necesitas definir la propiedad scroll-timeline-axis. Los valores permitidos son los mismos del argumento <axis> de scroll().

Finalmente, para vincular la animación al cronograma del progreso del desplazamiento, define la propiedad animation-timeline en el elemento que se debe animar con el mismo valor que el identificador que se usó para scroll-timeline-name.

  • Cambia el archivo styles.css para incluir lo siguiente:

src/styles.css

.gallery__scrollcontainer {
  /* Create the gallery-is-scrolling timeline */
  scroll-timeline-name: gallery-is-scrolling;
  scroll-timeline-axis: inline;
}

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  /* Set gallery-is-scrolling as the timeline */
  animation-timeline: gallery-is-scrolling;
}

Verifica tus cambios

Si no tuviste inconvenientes, te debería aparecer lo siguiente:

Si no es así, verifica la rama solution-step-2 del código.

6. Anima las imágenes de la galería a medida que ingresan y salen del puerto de desplazamiento

Configura un cronograma anónimo del progreso de visualización

Un efecto atractivo que puedes agregar es mostrar de forma gradual las imágenes de la galería a medida que se visualizan. Para hacerlo, puedes usar un cronograma del progreso de visualización.

Para crear un cronograma del progreso de visualización, usa la función view(). Los argumentos que acepta son <axis> y <view-timeline-inset>.

  • El valor <axis> es el mismo que se utiliza para el cronograma del progreso de desplazamiento y define los ejes a los que se les hace seguimiento.
  • Con <view-timeline-inset>, puedes especificar un intervalo (positivo o negativo) que te permitirá ajustar los límites para definir si se considera que un elemento está en la vista.
  • Los fotogramas clave ya están ubicados, por lo que solo debes adjuntarlos. Para hacerlo, crea un cronograma del progreso de visualización en cada elemento .gallery__entry.

src/styles.css

@keyframes animate-in {
  from {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  to {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
}

Limita el intervalo de un cronograma del progreso de visualización

Si guardas el CSS y cargas la página, verás que los elementos se muestran gradualmente, pero el resultado no es óptimo, ya que comienzan con una opacidad 0 cuando están fuera del campo de visualización y solo llegan a una opacidad 1 cuando ya salieron por completo.

Esto sucede porque el intervalo predeterminado de un cronograma del progreso de visualización está en su máxima expresión, lo que se conoce como el intervalo cover.

  1. Para orientarse solo al intervalo entry del objeto, utiliza la propiedad de CSS animation-range de modo que puedas aplicar límites para el momento de ejecución de la animación.

src/styles.css

.gallery__entry {
  animation: linear fade-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry 0% entry 100%;
}

La animación ahora se ejecuta desde entry 0% (el objeto está a punto de ingresar en la barra de desplazamiento) hasta entry 100% (el objeto ingresó por completo a la barra de desplazamiento).

Estos son los intervalos posibles de cronogramas de visualización:

  • cover. Representa el intervalo completo del cronograma del progreso de visualización.
  • entry. Representa el intervalo durante el cual el cuadro principal ingresa al intervalo de visibilidad del progreso de visualización.
  • exit. Representa el intervalo durante el cual el cuadro principal sale del intervalo de visibilidad del progreso de visualización.
  • entry-crossing. Representa el intervalo durante el cual el cuadro principal cruza el límite del borde final.
  • exit-crossing. Representa el intervalo durante el cual el cuadro principal cruza el límite del borde inicial.
  • contain. Representa el intervalo durante el cual el cuadro principal está completamente contenido en su intervalo de visibilidad del progreso de visualización dentro del puerto de desplazamiento, o lo cubre por completo. Esto depende de si el objeto es más alto o bajo que la barra de desplazamiento.

Usa la herramienta ubicada en https://goo.gle/view-timeline-range-tool para ver lo que representa cada intervalo y cómo afectan los porcentajes a las posiciones iniciales y finales.

  1. Debido a que los intervalos de inicio y final son los mismos en este caso, y se utilizan los desplazamientos predeterminados, simplifica animation-range a un solo nombre de intervalo de animación:

src/styles.css

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry;
}
  • Para atenuar las imágenes a medida que salen de la barra de desplazamiento, puedes seguir los mismos pasos para la animación de entrada, pero en un intervalo diferente.

src/styles.css

@keyframes animate-out {
  from {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  to {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in, linear animate-out;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry, exit;
}

Los fotogramas clave animate-in se aplicarán al intervalo entry y los fotogramas clave animate-out al intervalo exit.

Verifica tus cambios

Si no tuviste inconvenientes, te debería aparecer lo siguiente:

Si no es así, verifica la rama solution-step-3 del código.

7. Anima las imágenes de la galería a medida que ingresan y salen del puerto de desplazamiento con un conjunto de fotogramas clave

Caso correspondiente a un conjunto de fotogramas clave

En lugar de adjuntar dos animaciones a diferentes intervalos, es posible crear un conjunto de fotogramas clave que ya contenga la información del intervalo.

Los fotogramas clave se verán de la siguiente forma:

@keyframes keyframes-name {
  range-name range-offset {
    ...
  }
  range-name range-offset {
    ...
  }
}
  1. Combina los fotogramas clave para la aparición y atenuación graduales de la siguiente forma:

src/styles.css

@keyframes animate-in-and-out {
  entry 0% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  entry 90% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }

  exit 10% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  exit 100% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}
  1. Si la información del intervalo se incluye en los fotogramas clave, no es necesario que especifiques el animation-range de forma independiente. Adjunta los fotogramas clave como la propiedad animation.

src/styles.css

.gallery__entry {
  animation: linear animate-in-and-out both;
  animation-duration: auto;
  animation-timeline: view(inline);
}

Verifica tus cambios

Si no tuviste inconvenientes, deberías obtener el mismo resultado del paso anterior. Si no es así, verifica la rama solution-step-4 del código.

8. ¡Felicitaciones!

Terminaste este codelab y ahora sabes cómo crear cronogramas del progreso del desplazamiento y la visualización en CSS.

Más información

Recursos