Web Animations: element.animate() ahora está en Chrome 36.

La animación en la Web alguna vez fue un dominio de JavaScript, pero a medida que el mundo se mudó a los dispositivos móviles, las animaciones se trasladaron a CSS por la sintaxis declarativa y las optimizaciones que los navegadores pudieron hacer con ella. Dado que tu objetivo siempre es lograr 60 fps en dispositivos móviles, tiene sentido no salirse nunca de lo que los navegadores saben mostrar de manera eficiente.

Cada vez aparecen más herramientas para hacer que las animaciones impulsadas por JavaScript sean más eficientes, pero el Santo Grial es una unificación de animaciones declarativas e imperativas , en la que la decisión de cómo escribir tus animaciones se basa en el código más claro, no en lo que es posible en una forma y no en la otra.

Las animaciones web son una respuesta a esa llamada, y la primera parte llegó a Chrome 36 en forma de element.animate(). Esta nueva función te permite crear una animación solo en JavaScript y hacer que se ejecute con la misma eficiencia que cualquier animación o transición de CSS (de hecho, a partir de Chrome 34, el mismo motor de animaciones web impulsa todos estos métodos).

La sintaxis es simple y sus partes deberían resultarte familiares si alguna vez escribiste una transición o animación de CSS:

element.animate([
    {cssProperty: value0},
    {cssProperty: value1},
    {cssProperty: value2},
    //...
], {
    duration: timeInMs,
    iterations: iterationCount,
    delay: delayValue
});

La mayor ventaja de esta nueva función es la eliminación de muchos pasos incómodos que antes debíamos realizar para obtener una animación fluida y sin interrupciones.

A modo de ejemplo, para el Localizador de Santa del año pasado, queríamos que la nieve cayera de forma continua y decidimos animarla a través de CSS para que se pudiera hacer de manera eficiente.

Sin embargo, queríamos elegir la posición horizontal de la nieve de forma dinámica en función de la pantalla y los eventos que se desarrollan en la escena. Por supuesto, la altura de la caída de la nieve (la altura de la ventana del navegador del usuario) no se conocería hasta que se ejecutara. Esto significaba que realmente teníamos que usar transiciones de CSS, ya que la creación de una animación de CSS durante el tiempo de ejecución se vuelve compleja rápidamente (y cientos de copos de nieve significan cientos de reglas de diseño nuevas).

Por lo tanto, adoptamos el siguiente enfoque, que debería ser familiar:

snowFlake.style.transform = 'translate(' + snowLeft + 'px, -100%)';
// wait a frame
snowFlake.offsetWidth;
snowFlake.style.transitionProperty = 'transform';
snowFlake.style.transitionDuration = '1500ms';
snowFlake.style.transform = 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)';

La clave está en ese comentario "espera un fotograma". Para iniciar una transición de forma correcta, el navegador debe confirmar que el elemento está en la posición inicial. Existen varias formas de hacerlo. Una de las formas más comunes es leer de una de las propiedades del elemento que obliga al navegador a calcular el diseño, lo que garantiza que sepa que el elemento tiene una posición inicial antes de realizar la transición a la posición final. El uso de este método te permite felicitarte por tu conocimiento superior de los elementos internos del navegador y, al mismo tiempo, sentirte sucio con cada vez que presionas una tecla.

En cambio, la llamada element.animate() equivalente no podría ser más clara, ya que indica exactamente lo que se desea:

snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);

Hay muchas más opciones. Al igual que con sus contrapartes de CSS, las animaciones web se pueden retrasar y iterar:

snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], {
    duration: 1500,
    iterations: 10,
    delay: 300
});

AnimationPlayer

En realidad, element.animate() muestra un objeto AnimationPlayer, que será cada vez más importante a medida que se lancen más especificaciones de animaciones web. Tanto las animaciones creadas con JavaScript como las de CSS tendrán AnimationPlayers asociados, lo que les permitirá combinarse sin problemas de formas útiles e interesantes.

Sin embargo, por ahora, AnimationPlayer solo tiene dos funciones, ambas muy útiles. Puedes cancelar una animación en cualquier momento con AnimationPlayer.cancel():

var player = snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
// less than 1500ms later...changed my mind
player.cancel();

Y, para alivio de todos los que intentaron crear un sistema de animación en torno a animaciones o transiciones de CSS en el pasado, las animaciones web siempre activan un evento cuando terminan:

var player = snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
player.onfinish = function(e) {
    console.log('per aspera ad terra!');
}

Probar

Todo esto se lanzará en Chrome 36, que pasará a la versión beta hoy. Si quieres probarlo, trabaja con la implementación nativa en Chrome 36. Sin embargo, hay un polyfill de animaciones web, que incluye una parte mucho más grande de la especificación completa de animaciones web en cualquiera de los navegadores modernos y de actualización continua.

Hay disponible una demostración del efecto de nieve para que pruebes la versión nativa de element.animate() y el polyfill.

Envíanos tu opinión

Sin embargo, esta es una vista previa de lo que está por venir y se lanza específicamente para obtener comentarios de los desarrolladores de inmediato. Aún no sabemos si cubrimos todos los casos de uso o si limamos todos los problemas de las APIs actuales para la animación. La única forma de que sepamos si esto es correcto es que los desarrolladores lo prueben y nos cuenten qué piensan.

Por supuesto, los comentarios sobre esta publicación son valiosos, y los comentarios sobre el estándar en sí se pueden enviar a los grupos de trabajo de CSS y SVG a través de la lista de distribución public-fx.

Actualización de octubre de 2014: Chrome 39 agrega compatibilidad con varios métodos adicionales relacionados con el control de la reproducción, como play(), pause() y reverse(). También admite el salto a un punto específico en la línea de tiempo de una animación a través de la propiedad currentTime. Puedes ver esta funcionalidad en acción en esta nueva demostración.

Gracias a Addy Osmani y Max Heinritz por su ayuda con esta publicación.