Skip links

Animación lineal secuencial () con N elementos

asumiendo que tienes N Elementos que tienen la misma animación y deben animarse secuencialmente. El primero, luego el segundo, y así sucesivamente hasta llegar al último, luego regresa al principio. Estoy seguro de que sabes de lo que estoy hablando y que puede resultar complicado conseguir este efecto. Debe definir fotogramas clave complejos, calcular retrasos, hacer que funcionen para una cantidad específica de elementos, etc.

Déjame decirte: usando CSS moderno, podemos lograr esto fácilmente con unas pocas líneas de código, ¡y funciona para cualquier cantidad de proyectos!

La siguiente demostración está actualmente limitada a Chrome y Edge, pero también funcionará en otros navegadores. sibling-index() y sibling-count() Las funciones obtienen un soporte más amplio. Puede realizar un seguimiento del soporte de Firefox en: Boleto #1953973 y el estado de WebKit Número 471.

En la demostración anterior, Los elementos se animan secuencialmente. Los fotogramas clave son como un simple to Los marcos cambian el color de fondo y la escala de los elementos:

@keyframes x {
  to {
    background: #F8CA00;
    scale: .8;
  }
}

Puede agregar o eliminar tantos elementos como desee y todo funcionará sin problemas. Genial, ¿verdad? Este efecto se logra mediante este extraño y complicado código:

.container > * {
  --_s: calc(100%*(sibling-index() - 1)/sibling-count());
  --_e: calc(100%*(sibling-index())/sibling-count());

  animation: 
    x calc(var(--d)*sibling-count()) infinite 
    linear(0, 0 var(--_s), 1, 0 var(--_e), 0);
}

Da un poco de miedo y es difícil de entender, pero lo explicaré contigo para que entiendas la lógica detrás de esto.

CSS linear() Función

Cuando trabajamos con animaciones, podemos definir funciones de sincronización (también llamadas funciones de aceleración). Podemos utilizar valores de palabras clave predefinidos, p. linear, ease, ease-inEspera – o steps() Definir animaciones discretas. además cubic-bezier().

Pero tenemos una característica más nueva y poderosa para agregar a esa lista: linear().

de Especificación:

La función de flexibilización lineal es Función de relajación Interpolar linealmente entre punto de control. Cada punto de control es un par de números, asociados con un Ingrese el valor de progreso a un Valor de progreso de salida.

animation-timing-function: linear Crear interpolación lineal entre dos puntos – comenzar y final animado – al mismo tiempo linear() La función nos permite definir cualquier número de puntos y realizar una interpolación «lineal» entre dos puntos consecutivos.

Es un poco confuso al principio, pero una vez que empezamos a usarlo, las cosas se vuelven más claras. Comencemos con el primer valor, que no es más que equivalente. linear valor.

linear(0 0%, 1 100%)

Tenemos dos puntos, cada uno definido con dos valores (progreso de «salida» y progreso de «entrada»). El progreso de «salida» es la animación (es decir, lo que se define dentro de los fotogramas clave) y el progreso de «entrada» es el tiempo.

Consideremos el siguiente código:

.box {
  animation: move 2s linear(0 0%, 1 100%);
}

@keyframes move {
  0%   {translate: 0px }
  100% {translate: 80px}
}

En este caso queremos 0 animado (translate: 0px) existir t=0% (en otras palabras, 0% de 2sentonces 0s) y 1 animado (translate: 80px) existir t=100% (Esto es 100% de 2sentonces 2s). Entre estos puntos realizamos una interpolación lineal.

Podemos usar números en lugar de porcentajes, lo que significa que también es válido lo siguiente:

linear(0 0, 1 1)

Pero te recomiendo que te ciñas a la notación porcentual para evitar confusiones con el primer valor (que también es un número). este 0% y 100% están implícitos, por lo que podemos eliminarlos y simplemente usar lo siguiente:

linear(0, 1)

Agreguemos un tercer punto:

linear(0, 1, 0)

Como puedes ver, no he definido ningún progreso de «entrada» (valores que representan porcentajes de tiempo) ya que no son obligatorios; sin embargo, presentarlos es lo primero para comprender qué está haciendo la función.

El primer valor siempre está en 0% El último valor siempre está en 100%.

linear(0 0%, 1, 0 100%)

El valor será 50% es el punto medio. Cuando un punto de control carece de su progreso de «entrada», tomamos el valor medio entre dos puntos adyacentes. Si está familiarizado con los degradados, descubrirá que se aplica la misma lógica a las escalas de color.

linear(0 0%, 1 50%, 0 100%)

Más fácil de leer, ¿verdad? ¿Puedes explicar qué hace? Tómate unos minutos para pensarlo antes de continuar.

¿sabía? ¡Estoy seguro de que lo hiciste!

Así es como se descompone:

  1. empezamos desde translate: 0px existir t=0s (0% de 2s).
  2. Luego pasamos a translate: 80px existir t=1s (50% de 2s).
  3. Luego volvemos a translate: 0px existir t=2s (100% de 2s).

La mayoría de funciones de cronometraje sólo nos permiten avanzar, pero linear() Podemos movernos en ambas direcciones tantas veces como necesitemos. Por eso esta característica es tan poderosa. Usando fotogramas clave «simples» puedes tener animaciones «complejas».

Puedo hacer lo mismo usando los siguientes fotogramas clave:

@keyframes move {
  0%, 100% { translate: 0px }
  50% { translate: 80px }
}

Sin embargo, si quiero una animación diferente, no puedo actualizar el valor porcentual dinámicamente. No hay forma de controlar los fotogramas clave usando CSS, por lo que necesito definir nuevos fotogramas clave cada vez que necesito una nueva animación. pero con linear()solo necesito un fotograma clave.

En la demostración a continuación, todos los elementos usan los mismos fotogramas clave, ¡pero tienen animaciones completamente diferentes!

añadir retraso linear()

Ahora sabemos más linear()pasemos a los principales trucos de nuestro efecto. No olvides que la idea es crear una animación continua con un número determinado (N) elemento. Cada elemento debe animarse y luego «esperar» hasta que todos los demás elementos hayan terminado de animarse antes de comenzar de nuevo. Este tiempo de espera puede considerarse un retraso.

La forma intuitiva de hacer esto es la siguiente:

@keyframes move {
  0%, 50% { translate: 0px }
  100% { translate: 80px }
}

Especificamos el mismo valor. 0% y 50%;así que no pasa nada en el medio 0% y 50%. Tenemos retrasos, pero como dije antes, no podemos controlar esos porcentajes usando CSS. En cambio, podemos expresar lo mismo usando linear():

linear(0 0%, 0 50%, 1 100%)

Los dos primeros puntos de control tienen el mismo progreso de «salida». El primero está ubicado en 0% El segundo en ese momento. 50% tiempo, por lo que no sucede nada «visualmente» durante la primera mitad de la animación. ¡Creamos un retraso sin actualizar los fotogramas clave!

@keyframes move {
  0% { translate: 0px }
  100% { translate: 80px }
}

Agreguemos otro punto para volver al estado inicial:

linear(0 0%, 0 50%, 1 75%, 0 100%)

O simplemente:

linear(0, 0 50%, 1, 0)

Genial, ¿verdad? Podemos crear animaciones complejas utilizando un conjunto simple de fotogramas clave. No sólo eso, también podemos ajustar linear() Función. ¡Esto es lo que haremos para que cada elemento obtenga una animación secuencial!

animación completa

Volvamos a nuestra primera animación y usemos la anterior. linear() El valor que hicimos antes. Empezaremos con dos elementos.

Nada sorprendente todavía. Ambos elementos tienen exactamente la misma animación, por lo que se animan de la misma manera al mismo tiempo. Ahora, actualicemos linear() La función le da al primer elemento el efecto contrario: la primera mitad se anima y luego la segunda mitad se retrasa.

linear(0, 1, 0 50%, 0)

Esto efectivamente invierte el valor anterior:

¡Entonces! ¡Hemos creado una animación continua que contiene dos elementos! ¿Estás empezando a hacerte una idea? El objetivo es hacer lo mismo con cualquier número (N) elemento. Por supuesto, no asignaremos diferentes linear() El valor de cada elemento: lo haremos mediante programación.

Primero, dibujemos un diagrama para entender qué estamos haciendo con los dos elementos.

Dos diagramas cuadrados uno al lado del otro muestran las líneas de los dos primeros términos. Es el mismo pico ascendente, solo que se mueve a lo largo del eje x al comparar los gráficos.

Mientras un elemento espera, otro elemento se anima. Podemos identificar dos rangos. Imaginemos la misma situación usando tres elementos.

Los tres gráficos cuadrados de derecha a izquierda muestran líneas para los primeros tres términos. Es el mismo pico ascendente, solo que se mueve a lo largo del eje x al comparar los gráficos.

Esta vez necesitamos tres rangos. Cada elemento se anima en un ámbito y espera en dos ámbitos. ¿Ves este patrón? para N elementos que necesitamos N alcance, y linear() La función tendrá la siguiente sintaxis:

linear(0, 0 S, 1, 0 E, 0)

este comenzar y final igual 0que es el estado inicial de la animación, entonces tenemos una animación entre S y E. Un elemento esperará 0% llegar Sanimación de S llegar Eluego espera de nuevo E llegar 100%. El tiempo de animación es igual a 100%/Nlo que significa E - S = 100%/N.

El primer elemento está en el primer rango (0 * 100%/N), el segundo elemento en el segundo rango (1 * 100%/N), el tercer elemento en el tercer rango (2 * 100%/N), etc. S igual:

S = (i - 1) * 100%/N

…Dónde i es el índice del elemento.

Ahora, puedes preguntar, cómo ¿a nosotros? el valor obtenido N y i? La respuesta es simple, solo usa sibling-count()y sibling-index() ¡Función! Nuevamente, actualmente son compatibles con los navegadores Chromium, pero podemos esperar que se implementen en otros navegadores en el futuro.

S = calc(100%*(sibling-index() - 1)/sibling-count())

y:

E = S + 100%/N
E = calc(100%*sibling-index()/sibling-count())

¡Escribimos todo esto con un buen CSS y listo!

.box {
  --d: .5s; /* animation duration */
  --_s: calc(100%*(sibling-index() - 1)/sibling-count());
  --_e: calc(100%*(sibling-index())/sibling-count());

  animation: x calc(var(--d)*sibling-count()) infinite linear(0, 0 var(--_s), 1, 0 var(--_e), 0);
}
@keyframes x {
  to {
    background: #F8CA00;
    scale: .8;
  }
}

Usé una variable (--d) para controlar la duración, pero esto no es obligatorio. Quiero poder controlar cuánto tiempo tarda cada elemento en animarse. Por eso luego lo multiplico por N.

Ahora todo lo que queda es definir tu animación. Añade tantos elementos como quieras y observa los resultados. ¡No más fotogramas clave complicados y valores mágicos!

notas: Por razones desconocidas (probablemente un error), es necesario registrar la variable usando @property.

Más cambios

Podemos ampliar la idea básica para crear más variaciones. Por ejemplo, en lugar de tener que esperar a que un elemento termine completamente su animación, el siguiente elemento ya puede iniciar su propia animación.

Esta vez yo defino N + 1 Rango, cada elemento está animado dentro de dos rangos. El primer elemento se animará en el primer y segundo rango, mientras que el segundo elemento se animará en el segundo y tercer rango; entonces las dos animaciones se superponen en el segundo rango, y así sucesivamente.

No dedicaré mucho tiempo a explicar este caso, ya que es solo uno de los muchos ejemplos que creamos, así que te dejaré analizar el código como un pequeño ejercicio. Aquí tienes otro artículo del que puedes aprender.

en conclusión

este linear() Las funciones se introducen principalmente para crear Flexibilización compleja como rebote y elasticidad.pero combinado con otras características modernas, abre muchas posibilidades. Con este artículo tenemos una pequeña visión general de su potencial. Digo «pequeña» porque podemos ir más allá y crear animaciones más complejas, ¡así que estad atentos para más artículos!

Leave a comment

Home
Account
Cart
Search
¡Hola! ¡Pregúntame lo que quieras!
Explore
Drag