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

Brendan Kenny
Brendan Kenny

La animación en la Web solía ser parte de JavaScript, pero a medida que el mundo se trasladaba al mundo móvil, las animaciones se trasladaron a CSS para la sintaxis declarativa y las optimizaciones que los navegadores pudieron realizar con ella. Como siempre tu objetivo es de 60 fps en dispositivos móviles, tiene sentido no salir nunca de lo que los navegadores saben cómo mostrar de manera eficiente.

Cada vez hay más herramientas que hacen que las animaciones basadas en JavaScript sean más eficientes, pero lo más importante es una unificación de las animaciones imperativas y declarativas , en las que la decisión de escribir tus animaciones se basa en el código más claro, no en lo que es posible de una forma y no en la otra.

Web Animations están disponibles para responder 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 exclusivamente en JavaScript y hacer que se ejecute de la misma manera que cualquier animación o transición CSS (de hecho, a partir de Chrome 34, el mismo motor de animaciones web controla todos estos métodos).

La sintaxis es simple, y sus partes deberían resultarte conocidas 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 errores incómodos que antes tuvimos que resolver para lograr una animación fluida y sin bloqueos.

Por ejemplo, en el caso de Santa Tracker del año pasado, queríamos que la nieve cayera de forma continua, por lo que decidimos animarla con CSS para que se hiciera de manera tan eficiente.

Sin embargo, quisimos elegir la posición horizontal de la nieve de forma dinámica según la pantalla y los eventos que sucedían en la escena misma y, 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 realmente estábamos corriendo. Esto significaba que teníamos que usar transiciones de CSS, ya que crear una animación CSS en el tiempo de ejecución se vuelve complejo rápidamente (y cientos de copos de nieve significa cientos de reglas de estilo nuevas).

Por eso, adoptamos el siguiente enfoque, que debería resultarte 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 "esperar un fotograma". Para iniciar correctamente una transición, el navegador debe reconocer que el elemento se encuentra en la posición de inicio. Existen varias formas de hacerlo. Una de las formas más comunes es leer desde 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 la transición a la posición final. Si usas este método, podrás felicitarte por tu conocimiento superior de los componentes internos del navegador y, al mismo tiempo, sentirte desagradable con cada combinación de teclas.

Por el contrario, la llamada a element.animate() equivalente no podría ser más clara, ya que indicaba exactamente lo que se pretendía:

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 equivalentes de CSS, las animaciones web se pueden iterar y retrasar:

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 inicie más especificación de Web Animations. Tanto las animaciones creadas con JavaScript y CSS tendrán un elemento AnimationPlayers asociados, lo que les permitirá combinarse sin inconvenientes 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 hayan intentado crear un sistema de animación basado en animaciones o transiciones CSS en el pasado, las animaciones web siempre activan un evento una vez 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 envía en Chrome 36. Pasamos a la versión beta hoy. Si deseas probarlo, trabaja con la implementación nativa en Chrome 36. Sin embargo, existe un polyfill de Web Animations, que aporta una parte mucho más grande de la especificación completa de Web Animations a cualquiera de los navegadores modernos y perdurables.

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

Envíanos tu opinión

En realidad, sin embargo, esta es una vista previa de lo que está por venir y se lanzará específicamente para recibir comentarios de los desarrolladores de inmediato. Aún no estamos seguros de si alcanzamos todos los casos de uso o si limpiamos todos los bordes de las APIs actuales para la animación. La única forma de que sepamos y hagamos esto realmente es que los desarrolladores lo prueben y nos digan lo que piensan.

Los comentarios en 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 pública-fx.

Actualización de octubre de 2014: Chrome 39 incorpora varios métodos adicionales relacionados con el control de la reproducción, como play(), pause() y reverse(). También admite saltar a un punto específico en el cronograma de una animación mediante la propiedad currentTime. Puedes ver esta función en acción en esta nueva demostración.

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