Orquestación de animaciones con promesas, mejoras de rendimiento con animaciones reemplazables, animaciones más fluidas con modos compuestos y mucho más.
Fecha de publicación: 27 de mayo de 2020
Cuando se usan correctamente, las animaciones mejoran la percepción y la memoria de tu marca, guían las acciones de los usuarios y los ayudan a navegar por tu aplicación, lo que proporciona contexto en un espacio digital.
La API de Web Animations es una herramienta que permite a los desarrolladores escribir animaciones imperativas con JavaScript. Se escribió para respaldar las implementaciones de animación y transición de CSS y permitir que se desarrollen efectos futuros, así como que se compongan y se programen los efectos existentes.
Si bien Firefox y Safari ya implementaron el conjunto completo de funciones de las especificaciones, Chromium 84 agrega una gran cantidad de funciones que antes no se admitían en Chrome y Edge, lo que permite la interoperabilidad entre navegadores.
Cómo comenzar
Crear una animación con la API de Web Animations debería resultarte muy familiar si usaste reglas @keyframe
. Primero, debes crear un objeto de fotogramas clave. Podría verse así en CSS:
@keyframes openAnimation {
0% {
transform: scale(0);
}
100% {
transform: scale(1);
}
}
se vería así en JavaScript:
const openAnimation = [
{ transform: 'scale(0)' },
{ transform: 'scale(1)' },
];
Dónde estableces los parámetros para la animación en CSS:
.modal {
animation: openAnimation 1s 1 ease-in;
}
que configurarías en JS:
document.querySelector('.modal').animate(
openAnimation, {
duration: 1000, // 1s
iterations: 1, // single iteration
easing: 'ease-in' // easing function
}
);
La cantidad de código es aproximadamente la misma, pero con JavaScript, obtienes algunas funciones adicionales que no tienes solo con CSS. Esto incluye la capacidad de secuenciar efectos y un mayor control de sus estados de reproducción.
Más allá de element.animate()
Sin embargo, con la actualización, la API de Web Animations ya no se limita a las animaciones creadas con element.animate()
. También podemos manipular las animaciones y transiciones de CSS.
getAnimations()
es un método que muestra todas las animaciones de un elemento, independientemente de si se creó con element.animate()
o con reglas de CSS (animación o transición de CSS). Este es un ejemplo de cómo se ve:
Primero, "get"
los fotogramas clave de la transición para determinar de dónde estamos haciendo la transición. Luego, creas dos animaciones de opacidad nuevas, lo que habilita el efecto de atenuación cruzada. Una vez que se complete la transición, borra la copia.
Cómo organizar animaciones con promesas
En Chromium 84, ahora tienes dos métodos que se pueden usar con promesas: animation.ready
y animation.finished
.
animation.ready
te permite esperar a que se apliquen los cambios pendientes (es decir, cambiar entre métodos de control de reproducción, como reproducir y pausar).animation.finished
proporciona un medio para ejecutar código JavaScript personalizado cuando se completa una animación.
Continuando con nuestro ejemplo, crea una cadena de animación orquestada con animation.finished
. Aquí, tienes una transformación vertical (scaleY
), seguida de una transformación horizontal (scaleX
) y, luego, un cambio de opacidad en un elemento secundario:
const transformAnimation = modal.animate(openModal, openModalSettings);
transformAnimation.finished.then(() => { text.animate(fadeIn, fadeInSettings)});
Encadenamos estas animaciones con animation.finished.then()
antes de ejecutar el siguiente conjunto de animaciones en la cadena. De esta manera, las animaciones aparecen en orden y hasta aplicas efectos a diferentes elementos de destino con diferentes opciones configuradas (como velocidad y facilidad).
En CSS, sería engorroso volver a crear esto, en especial cuando se aplican animaciones únicas, pero secuenciadas, a varios elementos. Deberás usar un @keyframe
, ordenar los porcentajes de tiempo correctos para colocar las animaciones y usar animation-delay
antes de activar las animaciones en la secuencia.
Ejemplo: Reproducir, pausar y revertir
Lo que se puede abrir, debe cerrarse. Por suerte, desde Chromium 39, la API de Web Animations nos permite reproducir, pausar y revertir nuestras animaciones.
Puedes tomar la animación que se mostró anteriormente y darle una animación suave y revertida cuando vuelvas a hacer clic en el botón con .reverse()
. De esta manera, puedes crear una interacción más fluida y contextual para nuestro elemento modal.
Lo que puedes hacer es crear dos animaciones pendientes de reproducción (openModal
y una transformación de opacidad intercalada) y, luego, pausar una de las animaciones y retrasarla hasta que termine la otra. Luego, puedes usar promesas para esperar a que cada una termine antes de reproducir. Por último, puedes verificar si se configuró una marca y, luego, invertir cada animación.
Ejemplo: Interacciones dinámicas con fotogramas clave parciales
selector.animate([{transform: `translate(${x}px, ${y}px)`}],
{duration: 1000, fill: 'forwards'});
En este ejemplo, solo hay un fotograma clave y no se especifica una posición de inicio. Este es un ejemplo del uso de fotogramas clave parciales. El controlador del mouse hace algunas acciones: establece una nueva ubicación de destino y activa una nueva animación. La nueva posición de inicio se infiere de la posición subyacente actual.
Las transiciones nuevas se pueden activar mientras las existentes aún se están ejecutando. Esto significa que se interrumpe la transición actual y se crea una nueva.
Mejoras de rendimiento con animaciones reemplazables
Cuando se crean animaciones basadas en eventos, como en 'mousemove'
, se crea una animación nueva cada vez, lo que puede consumir memoria rápidamente y degradar el rendimiento. Para abordar este problema, se introdujeron animaciones reemplazables en Chromium 83, lo que permite la limpieza automática, en la que las animaciones terminadas se marcan como reemplazables y se quitan automáticamente si se reemplazan por otra animación terminada. Consulta el siguiente ejemplo:
elem.addEventListener('mousemove', evt => {
rectangle.animate(
{ transform: translate(${evt.clientX}px, ${evt.clientY}px) },
{ duration: 500, fill: 'forwards' }
);
});
Cada vez que se mueve el mouse, el navegador vuelve a calcular la posición de cada bola en la estela del cometa y crea una animación para este nuevo punto. El navegador ahora sabe quitar las animaciones anteriores (habilita el reemplazo) en los siguientes casos:
- La animación terminó.
- Hay una o más animaciones más altas en el orden compuesto que también están terminadas.
- Las animaciones nuevas animan las mismas propiedades.
Para ver exactamente cuántas animaciones se reemplazan, puedes sumar un contador con cada animación quitada y usar anim.onremove
para activarlo.
Existen algunas propiedades y métodos adicionales para llevar tu control de animación aún más lejos:
animation.replaceState
proporciona un medio para hacer un seguimiento de si una animación está activa, persiste o se quita.animation.commitStyles()
actualiza el estilo de un elemento según el estilo subyacente junto con todas las animaciones del elemento en el orden compuesto.animation.persist()
marca una animación como no reemplazable.
Animaciones más fluidas con modos compuestos
Con la API de Web Animations, ahora puedes establecer el modo compuesto de tus animaciones, lo que significa que pueden ser aditivos o acumulativos, además del modo predeterminado de "reemplazo". Los modos compuestos permiten a los desarrolladores escribir animaciones distintas y tener control sobre cómo se combinan los efectos. Ahora se admiten tres modos compuestos: 'replace'
(el modo predeterminado), 'add'
y 'accumulate'
.
Cuando se combinan animaciones, un desarrollador puede escribir efectos cortos y distintos, y verlos combinados. En el siguiente ejemplo, aplicamos una keyframe de rotación y escala a cada cuadro, y el único ajuste es el modo compuesto, que se agrega como opción:
En el modo compuesto 'replace'
predeterminado, la animación final reemplaza la propiedad de transformación y termina en rotate(360deg) scale(1.4)
. Para 'add'
, el compuesto agrega la rotación y multiplica la escala, lo que genera un estado final de rotate(720deg) scale(1.96)
. 'accumulate'
combina las transformaciones, lo que genera rotate(720deg) scale(1.8)
. Para obtener más información sobre las complejidades de estos modos compuestos, consulta Las enumeraciones CompositeOperation y CompositeOperationOrAuto de la especificación de animaciones web.
Observa el siguiente ejemplo de elemento de la IU:
Aquí, se combinan dos animaciones top
. La primera es una macroanimación, que mueve el menú desplegable por toda la altura del menú como un efecto de deslizamiento desde la parte superior de la página, y la segunda, una microanimación, aplica un pequeño rebote cuando llega a la parte inferior. El uso del modo compuesto 'add'
permite una transición más fluida.
const dropDown = menu.animate(
[
{ top: `${-menuHeight}px`, easing: 'ease-in' },
{ top: 0 }
], { duration: 300, fill: 'forwards' });
dropDown.finished.then(() => {
const bounce = menu.animate(
[
{ top: '0px', easing: 'ease-in' },
{ top: '10px', easing: 'ease-out' },
{ ... }
], { duration: 300, composite: 'add' });
});
Novedades de la API de Web Animations
Todas estas son incorporaciones emocionantes a las capacidades de animación de los navegadores actuales, y aún hay más en camino. Consulta estas especificaciones futuras para obtener más información sobre lo que sucederá a continuación: