Dev

Mejoras en la API de animaciones web en Chromium 84

Orquestando animaciones con promesas, mejoras de rendimiento con animaciones reemplazables, animaciones más suaves con modos compuestos y más.

Cuando se usa correctamente, Las animaciones mejoran la percepción y la memoria del usuario. de su marca, guíe las acciones del usuario y ayude a los usuarios a navegar por su aplicación, brindándoles contexto en un espacio digital.

los API de animaciones web es una herramienta que permite a los desarrolladores escribir animaciones imperativas con JavaScript. Fue escrito para respaldar las implementaciones de transición y animación CSS y permitir el desarrollo de efectos futuros, así como la composición y el tiempo de los efectos existentes.

Mientras Firefox y Safari ya han implementado el conjunto completo de especificaciones caracteristicas, Chromium 84 trae una gran cantidad de funciones previamente no admitidas para Chrome y Edge permitiendo la interoperabilidad entre navegadores.

waapi-timeline-4616611

La larga historia de la API de animaciones web en Chromium.

Empezando

Crear una animación a través de la API de animaciones web debería resultarle muy familiar si ha utilizado @keyframe reglas. Primero, deberá crear un objeto de fotograma clave. Que podria verse como esta en CSS:

@keyframes openAnimation {
0% {
transform: scale();
}
100% {
transform: scale(1);
}
}

se vería como esta en JavaScript:

const openAnimation = [
{ transform: 'scale(0)' },
{ transform: 'scale(1)' },
];

Donde establece los parámetros para la animación en CSS:

.modal {
animation: openAnimation 1s 1 ease-in;
}

establecerías en JS:

document.querySelector('.modal').animate(
openAnimation, {
duration: 1000,
iterations: 1,
easing: 'ease-in'
}
);

La cantidad de código es aproximadamente la misma, pero con JavaScript, obtienes un par de superpoderes que no tienes solo con CSS. Esto incluye la capacidad de secuenciar efectos y un mayor control de sus estados de juego.

Los nombres de propiedad con guiones se convierten en mayúsculas y minúsculas cuando se utilizan en fotogramas clave (p. Ej. background-color a backgroundColor)

Más allá element.animate()

Sin embargo, con la actualización, la API de animaciones web ya no está restringida a las animaciones creadas a través de element.animate(). También podemos manipular animaciones y transiciones CSS.

getAnimations() es un método que devuelve todas las animaciones de un elemento independientemente de si se creó mediante element.animate() o mediante reglas CSS (animación CSS o transición). A continuación, se muestra un ejemplo de cómo se ve esto:

Tú primero "get" los fotogramas clave de la transición para determinar de dónde estamos haciendo la transición. Luego, crea dos nuevas animaciones de opacidad, habilitando el efecto de fundido cruzado. Una vez que se completa el fundido cruzado, borra la copia.

Orquestando animaciones con promesas

En Chromium 84, ahora tiene dos métodos que se pueden usar con promesas: animation.ready y animation.finished.

  • animation.ready le permite esperar a que los cambios pendientes surtan efecto (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.

Continuemos con nuestro ejemplo y creemos una cadena de animación orquestada con animation.finished. Aquí tienes una transformación vertical (scaleY), seguida de una transformación horizontal (scaleX), seguido de un cambio de opacidad en un elemento secundario:

Aplicar transformaciones y opacidad a un elemento modal de apertura. Ver demostración en Codepen

const transformAnimation = modal.animate(openModal, openModalSettings);
transformAnimation.finished.then(() => { text.animate(fadeIn, fadeInSettings)});

Hemos encadenado estas animaciones usando animation.finished.then() antes de ejecutar la siguiente animación establecida en la cadena. De esta manera, las animaciones aparecen en orden e incluso aplica efectos a diferentes elementos de destino con diferentes opciones establecidas (como velocidad y facilidad).

Dentro de CSS, esto sería complicado de recrear, especialmente cuando se aplican animaciones únicas pero secuenciadas a varios elementos. Tendrías que usar un @keyframe, clasifique los porcentajes de tiempo correctos para colocar las animaciones y utilice animation-delay antes de activar las animaciones en la secuencia.

Ejemplo: reproducir, pausar e invertir

¡Lo que puede abrirse, debería cerrarse! Afortunadamente, desde Cromo 39, la API de animaciones web nos ha proporcionado la capacidad de reproducir, pausar y revertir nuestras animaciones.

Puede tomar la animación anterior y darle una animación suave e invertida cuando haga clic en el botón nuevamente usando .reverse(). De esta manera, puede crear una interacción más suave y contextual para nuestro modal.

Un ejemplo de apertura y cierre modal al hacer clic en un botón. Ver demostración en Glitch

Lo que puede hacer es crear dos animaciones pendientes de reproducción (openModaly una transformación de opacidad en línea), y luego pause una de las animaciones, retrasándola hasta que la otra termine. A continuación, puede utilizar las promesas para esperar a que se terminen antes de jugar. Finalmente, puede verificar si hay una bandera establecida y luego invertir cada animación.

Ejemplo: interacciones dinámicas con fotogramas clave parciales

Ejemplo de redireccionamiento, donde un clic del mouse ajusta la animación a una nueva ubicación. Ver demostración en Glitch

selector.animate([{transform: `translate(${x}px, ${y}px)`}], 
{duration: 1000, fill: 'forwards'});

En este ejemplo, solo hay un fotograma clave y no hay una posición de inicio especificada. Este es un ejemplo de uso fotogramas clave parciales. El controlador del mouse hace algunas cosas aquí: establece una nueva ubicación final y activa una nueva animación. La nueva posición inicial se infiere de la posición subyacente actual.

Se pueden activar nuevas transiciones mientras las existentes aún se están ejecutando. Esto significa que la transición actual se interrumpe y se crea una nueva.

Mejoras de rendimiento con animaciones reemplazables

Al crear animaciones basadas en eventos, como en 'mousemove', se crea una nueva animación cada vez, 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, donde las animaciones terminadas se marcan como reemplazables y se eliminan automáticamente si se reemplazan por otra animación terminada. Considere el siguiente ejemplo:

Un rastro de cometa se anima cuando se mueve el mouse. Ver demostración en Glitch

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 el rastro del cometa y crea una animación para este nuevo punto. El navegador ahora sabe eliminar las animaciones antiguas (lo que permite el reemplazo) cuando:

  1. La animación está terminada.
  2. Hay una o más animaciones más altas en el orden compuesto que también están terminadas.
  3. Las nuevas animaciones están animando las mismas propiedades.

Puede ver exactamente cuántas animaciones se están reemplazando contando un contador con cada animación eliminada, usando anim.onremove para activar el contador.

Hay algunos métodos adicionales para llevar su control de animación aún más lejos:

  • animation.replaceState() proporciona un medio para rastrear si una animación está activa, persistente o eliminada.
  • animation.commitStyles() actualiza el estilo de un elemento en función del estilo subyacente junto con todas las animaciones del elemento en el orden compuesto.
  • animation.persist() marca una animación como no reemplazable.

animation.commitStyles() y animation.persist() se usan comúnmente con modos de composición, como “agregar”. Consulte la demostración de modos compuestos a continuación para verlos en acción.

Animaciones más suaves con modos compuestos

Con la API de animaciones web, ahora puede establecer el modo compuesto de sus animaciones, lo que significa que pueden ser aditivas o acumulativas, además del modo predeterminado de “reemplazar”. 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'.

Al componer animaciones, un desarrollador puede escribir efectos breves y distintos y verlos combinados. En el siguiente ejemplo, estamos aplicando un fotograma clave de rotación y escala a cada cuadro, y el único ajuste es el modo compuesto, agregado como una opción:

Una demostración que muestra los modos compuestos predeterminados, agregar y acumular. Ver demostración en Glitch

Por defecto 'replace' modo compuesto, la animación final reemplaza la propiedad de transformación y termina en rotate(360deg) scale(1.4). por 'add', compuesto agrega la rotación y multiplica la escala, lo que resulta en un estado final de rotate(720deg) scale(1.96). 'accumulate' combina las transformaciones, dando como resultado rotate(720deg) scale(1.8). Para obtener más información sobre las complejidades de estos modos compuestos, consulte Las enumeraciones CompositeOperation y CompositeOperationOrAuto de la especificación de animaciones web.

Echemos un vistazo a un ejemplo de elemento de la interfaz de usuario:

Un menú desplegable hinchable que tiene dos animaciones compuestas aplicadas. Ver demostración en Glitch

Aquí dos top las animaciones están compuestas. La primera es una macro-animación, que mueve el menú desplegable a la altura completa del propio menú como un efecto de deslizamiento desde la parte superior de la página, y la segunda, una micro-animación, aplica un pequeño rebote cuando golpea el fondo. Utilizando la 'add' el modo compuesto permite una transición más suave.

const dropDown = menu.animate(
[
{ top: `${-menuHeight}px`, easing: 'ease-in' },
{ top: }
], { 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' });
});

¿Qué sigue para la API de animaciones web?

Todas estas son adiciones emocionantes a las capacidades de animaciones en los navegadores actuales, e incluso más adiciones están por llegar. Consulte estas especificaciones futuras para obtener más información sobre lo que viene a continuación:

Quizás te interesa >>>  Se mejoró el estilo predeterminado del modo oscuro con la propiedad CSS de esquema de color y la metaetiqueta correspondiente