animation-direction y el easing que se da la vuelta
Los cuatro valores de direction, cómo se numeran las iteraciones, y el detalle que casi nadie ve: una curva de aceleración se convierte en una de frenado al reproducir hacia atrás.
animation-direction parece la propiedad más simple de las ocho: cuatro palabras clave, dos de ellas evidentes. Pero decide dos cosas a la vez que la gente separa mentalmente sin motivo: en qué sentido se recorren los keyframes y en qué sentido se recorre la curva de temporización. Reproducir una animación hacia atrás no es reproducir la misma animación con los valores invertidos; es reproducirla con los valores y la curva invertidos, y eso cambia lo que ves.
- Determinar el sentido de cada iteración con los cuatro valores de
direction. - Explicar por qué
alternatereduce a la mitad los keyframes que tienes que escribir. - Predecir cómo se transforma un
ease-inen una iteración invertida. - Elegir entre
normalyalternatesegún el tipo de bucle.
Los cuatro valores y el índice de iteración
Las iteraciones se numeran desde cero. Con esa convención, los cuatro valores se definen sin ambigüedad:
| valor | iteraciones pares | iteraciones impares |
|---|---|---|
normal |
hacia adelante | hacia adelante |
reverse |
hacia atrás | hacia atrás |
alternate |
hacia adelante | hacia atrás |
alternate-reverse |
hacia atrás | hacia adelante |
“Hacia adelante” significa recorrer los keyframes de 0% a 100%; “hacia atrás”, de 100% a 0%. Con reverse no hay nada que alternar: todas las iteraciones van hacia atrás, y el elemento salta del 0% al 100% al empezar cada nueva iteración.
alternate-reverse no es un valor decorativo. Sirve exactamente cuando quieres el mismo vaivén que alternate pero empezando por el otro extremo, algo que aparece de forma natural al desfasar elementos: dos listas idénticas, una con alternate y otra con alternate-reverse, se mueven en oposición de fase perfecta sin tocar ni un retardo.
El número de iteraciones fraccionario interactúa con esto. Con alternate e iteration-count: 2.5, las iteraciones 0 y 1 se completan —adelante y atrás— y la iteración 2 va hacia adelante pero se corta en el 50%. El elemento se detiene en mitad del recorrido, no en un extremo.
Escribir la mitad de los keyframes
El valor práctico de alternate es que te ahorra la vuelta. Una animación de ida y vuelta con normal necesita tres puntos y una simetría que tienes que mantener a mano:
/* Con normal: hay que escribir la vuelta y mantenerla simetrica */
@keyframes vaiven-normal {
0% { transform: translateX(0); }
50% { transform: translateX(120px); }
100% { transform: translateX(0); }
}
.a { animation: vaiven-normal 2s ease-in-out infinite; }
/* Con alternate: la vuelta la hace la propiedad */
@keyframes vaiven-alt {
from { transform: translateX(0); }
to { transform: translateX(120px); }
}
.b { animation: vaiven-alt 1s ease-in-out infinite alternate; }
Las dos versiones producen el mismo periodo de dos segundos, pero la segunda tiene la mitad de keyframes y no puede desincronizarse: si cambias el destino a 200px, la vuelta se ajusta sola. En la primera versión tendrías que acordarte de tocar dos declaraciones, y la clase de bug que se genera al olvidarlo es un movimiento que no vuelve del todo a su sitio y va derivando.
Hay un caso donde normal es obligatorio: cuando el movimiento no es reversible. Una rotación continua de 0 a 360 grados con alternate no gira, oscila. Un desplazamiento cíclico de un fondo con alternate va y viene en vez de fluir. La regla es que alternate sirve para movimientos de vaivén y normal para movimientos circulares o de bucle sin costura, y en el segundo caso el 0% y el 100% tienen que ser visualmente idénticos para que la unión no se vea.
La curva también se invierte
Este es el matiz que no está en ningún tutorial. Cuando una iteración se reproduce hacia atrás, no solo se recorren los valores en orden inverso: la función de temporización se aplica en sentido inverso. Un ease-in, que arranca lento y acelera, se convierte en una iteración invertida en algo que arranca rápido y frena. Visualmente es un ease-out.
@keyframes subir { from { transform: translateY(0); } to { transform: translateY(-100px); } }
.globo { animation: subir 1s ease-in infinite alternate; }
La subida arranca despacio y acelera. La bajada arranca rápida y frena al llegar abajo. No es lo que se esperaría de un objeto cayendo, y es la causa de que muchas animaciones de vaivén se sientan “al revés” sin que nadie sepa decir por qué. La curva correcta para un vaivén simétrico es una simétrica: ease-in-out, o una cúbica cuyos puntos de control sean espejo el uno del otro.
Lo mismo pasa con los animation-timing-function declarados dentro de keyframes. Un tramo con su curva propia mantiene su curva en la iteración invertida, aplicada al revés. Cuando compongas una animación con curvas por tramo pensada para alternate, prueba las dos direcciones antes de dar el ajuste por bueno: la mitad de las veces la vuelta necesita una curva distinta y eso obliga a escribir la vuelta a mano con normal.
animation-direction no altera qué keyframe cuenta como el primero y cuál como el último en el sentido de los offsets, pero sí altera cuál se usa para el relleno. Con direction: reverse, el animation-fill-mode: backwards aplica durante el retardo el valor del keyframe del 100%, no el del 0%, porque la animación va a empezar por ahí. Y con alternate y un número par de iteraciones, forwards congela el valor del 0%, porque la última iteración termina ahí. Ese es el motivo de un bug que se ve mucho: alguien pone alternate e iteration-count: 2 con forwards esperando que el elemento se quede en su estado final, y se queda en el inicial. La forma correcta de razonarlo es olvidar los porcentajes: backwards aplica el valor que la animación produciría en su primer instante y forwards el que produjo en su último instante. Con esa definición no hay que recordar ninguna tabla, y funciona igual para iteraciones fraccionarias, donde el valor congelado no corresponde a ningún keyframe escrito.
Direction y el desfase de una lista
Al combinar direction con retardos negativos aparece el efecto que hace que las listas desfasadas se vean bien o mal. Con normal, el tiempo local de cada elemento es simplemente el módulo de la duración de ciclo, así que un desfase constante produce un frente que recorre la lista en una dirección clara. Con alternate, el desfase mete a unos elementos en iteraciones pares y a otros en impares, y la lista deja de tener un frente para pasar a tener elementos moviéndose en sentidos opuestos.
Ninguno de los dos resultados es incorrecto: son efectos distintos. Una ola necesita normal con keyframes simétricos. Un conjunto de elementos “respirando” de forma orgánica y desordenada se consigue precisamente con alternate y desfases que no dividan la duración. Elegir es elegir entre orden y textura, y conviene hacerlo a propósito en vez de descubrirlo.
Monta el globo de arriba con ease-in y alternate, y al lado el mismo elemento con dos animaciones encadenadas por animation-name que usen ease-in para subir y ease-in de verdad para bajar, escribiendo la vuelta a mano con normal. Compara la sensación de peso: en el primero el objeto flota, en el segundo cae.