Primeros pasos con la API de animación web de JavaScript

Agregar animaciones a las interfaces web hace que las páginas y las aplicaciones se sientan más receptivas e interactivas. Un menú lateral que se desliza suavemente fuera de la vista brinda una experiencia de usuario mucho mejor que un menú que simplemente desaparece cuando lo cierra.

Hasta ahora, la creación de animaciones web se realizaba mediante transiciones CSS, fotogramas clave CSS o una biblioteca externa como Animate.css o Velocity. Gracias a una nueva API nativa de JavaScript, ahora podemos animar libremente cualquier elemento HTML sin tener que abandonar nuestro archivo .js.

Creación de animaciones

Para mostrar la genialidad de la nueva API, construyamos un ejemplo súper simple, una vez a la antigua usanza CSS, luego con animaciones web de JavaScript.

El editor a continuación contiene dos divs HTML que, cuando se hace clic en ellos, se mueven hacia la derecha y luego cambian de color. El cuadrado se anima a través del código CSS>@keyframes y el círculo a través de la API de animaciones web.

<h4>Click on the shapes to animate them.</h4>

<p>CSS keyframes</p>
<div id="square"></div>

<p>JS Web Animation API</p>
<div id="circle"></div>
#square,
#circle {
    width: 100px;
    height: 100px;
    margin: 10px 10px 30px;
    background-color: #2196F3;
}

#circle {
    border-radius: 50%;
}

.animate {
    animation-name: move-and-change-color;   
    animation-duration: 0.4s;
    animation-fill-mode: forwards;
}

@keyframes move-and-change-color {
    0% {
        transform: translateX(0);
    }

    80% {
        transform: translateX(100px);
        background-color: #2196F3;
    }

    100% {
        transform: translateX(100px);
        background-color: #EF5350;
    }
}
var square = document.getElementById('square');

square.addEventListener('click', function() {
    square.className += " animate";
});

var moveAndChangeColor = [
    { 
        transform: 'translateX(0)',
        background: '#2196F3'    // blue
    },
    { 
        offset: 0.8,
        transform: 'translateX(100px)', 
        background: '#2196F3'    // blue
    },
    {
        transform: 'translateX(100px)',
        background: '#EF5350'    // red
    }
];

var circle = document.getElementById('circle');

circle.addEventListener('click', function() {
    circle.animate(moveAndChangeColor, {
        duration: 400,
        fill: 'forwards'
    });
});

La animación de código>@keyframes debería ser familiar para la mayoría de los desarrolladores, así que veamos eso primero.

El enfoque CSS

Nuestra animación CSS se define en un bloque de código>@keyframes que representa una línea de tiempo de todas las transiciones. Una vez que tenemos nuestra coreografía definida, podemos asignarla a un selector a través de la propiedad de animación y sus opciones.

.animate {
    animation-name: move-and-change-color;   
    animation-duration: 0.4s;
    animation-fill-mode: forwards;
}

@keyframes move-and-change-color {
    0% {
        transform: translateX(0);
    }

    80% {
        transform: translateX(100px);
        background-color: #2196F3;
    }

    100% {
        transform: translateX(100px);
        background-color: #EF5350;
    }
}

Queremos que la animación comience con la interacción del usuario, por lo que también tendremos que crear un detector de eventos al hacer clic que agregue una clase CSS al elemento deseado:

var square = document.getElementById('square');

square.addEventListener('click', function() {
    square.className += " animate";
});

Aunque funciona bastante bien, el enfoque de CSS parece bastante poco intuitivo, ya que definimos lo que sucede en las hojas de estilo, pero en realidad lo iniciamos en JavaScript. También tenemos un control muy limitado sobre la animación una vez que se ha invocado. Ambos problemas se pueden resolver cambiando a la API de animación web.

El enfoque de JavaScript

Podemos describir nuestra animación de JavaScript usando casi exactamente las mismas transiciones que usamos en el ejemplo de CSS:

var moveAndChangeColor = [
    { 
        transform: 'translateX(0)',
        background: '#2196F3'    // blue
    },
    { 
        offset: 0.8,
        transform: 'translateX(100px)', 
        background: '#2196F3'    // blue
    },
    {
        transform: 'translateX(100px)',
        background: '#EF5350'    // red
    }
];

Cada objeto de la matriz representa un estado de la animación. Los estados se distribuyen uniformemente en el tiempo (3 estados - 0 %, 50 %, 100 %) a menos que cambiemos el tiempo usando el offset opción, como hemos hecho con el estado medio.

Después de haber definido nuestra matriz de animación, podemos invocarla usando el método animate(). Toma como segundo argumento un objeto con las mismas opciones que la propiedad de animación CSS, aunque con nombres ligeramente diferentes (por ejemplo, animation-fill-mode es fill , animation-iteration-count es iteration , etc.).

var circle = document.getElementById('circle');

circle.addEventListener('click', function() {
    circle.animate(moveAndChangeColor, {
        duration: 400,
        fill: 'forwards'
    });
});

Como puede ver, el enfoque de JavaScript está mucho más organizado con la animación almacenada en una variable y el animate() método utilizado para invocarlo cuando lo necesitemos.

Control de animaciones

La API de animación web también permite controlar fácilmente la reproducción de una animación de varias maneras. El animate() El método devuelve un objeto Animación que podemos guardar en una variable y usar para referirnos a esa animación más adelante.

var animation = elem.animate(transitions, options);

La interfaz nos proporciona los siguientes métodos:

  • pause() - Congela la animación en su estado actual.
  • play() - Reanuda la animación o la reinicia si ha terminado.
  • reverse() - Reproduce las transiciones hacia atrás.
  • finish() - Va al final de la animación (o al principio si se invierte).
  • cancel() - Detiene la reproducción y vuelve al estado inicial.

A continuación se muestra una pequeña demostración con un indicador de carga que se repite infinitamente. Tenemos botones de configuración para los diferentes eventos para que puedas probarlos:

var spinner = document.getElementById('spinner');
var spinnerAnimation = spinner.animate([
    {
        transform: 'rotate(0)'
    },
    {
        transform: 'rotate(359deg)'
    }
], {
    duration: 1000,
    iterations: Infinity
});

document.getElementById('pause').addEventListener('click', function() { 
  spinnerAnimation.pause();
});
document.getElementById('play').addEventListener('click', function() { 
  spinnerAnimation.play(); 
});
document.getElementById('reverse').addEventListener('click', function() { 
  spinnerAnimation.reverse(); 
});
document.getElementById('cancel').addEventListener('click', function() { 
  spinnerAnimation.cancel(); 
});
<div id="spinner"></div>

<p>Try controlling the animation:</p>
<button id="pause">Pause</button>
<button id="play">Play</button>
<button id="reverse">Reverse</button>
<button id="cancel">Cancel</button>
#spinner {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 3px solid #e2e2e2;
    border-top-color: #186aab;
    margin: 50px;
}

Oyentes de propiedades y eventos

El objeto Animation devuelto desde animate() tiene varias propiedades útiles que nos dan acceso a opciones como la hora actual, la velocidad de reproducción y otras. Aunque algunas son de solo lectura, la mayoría de las propiedades se pueden usar como setters y getters.

Puede ver el código JS en el editor a continuación para tener una idea de cómo funcionan. Para obtener la lista completa de propiedades, visite MDN.

var spinner = document.getElementById('spinner');
var spinnerAnimation = spinner.animate([
    {
        transform: 'rotate(0)'
    },
    {
        transform: 'rotate(359deg)'
    }
], {
    duration: 1000,
    iterations: Infinity
});

document.getElementById('half').addEventListener('click', function() { 
  spinnerAnimation.playbackRate = 0.5; 
});
document.getElementById('normal').addEventListener('click', function() { 
  spinnerAnimation.playbackRate = 1; 
});
document.getElementById('double').addEventListener('click', function() { 
  spinnerAnimation.playbackRate = 2; 
});
document.getElementById('triple').addEventListener('click', function() { 
  spinnerAnimation.playbackRate = 3; 
});
<div id="spinner"></div>

<p>Set Playback Speed:</p>
<button id="half">0.5</button>
<button id="normal">Normal</button>
<button id="double">2</button>
<button id="triple">3</button>
#spinner {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 3px solid #e2e2e2;
    border-top-color: #186aab;
    margin: 50px;
}

Además de eso, la API de animación web nos proporciona dos controladores de eventos útiles para cuando la animación finaliza o se cancela:

spinnerAnimation.addEventListener('finish', function() {
    // Animation has completed or .finish() has been called.
    doSomething();
});

spinnerAnimation.addEventListener('cancel', function() {
    // Animation has been canceled.    
    doSomething();
});

Soporte y rendimiento

La mayoría de las funciones de animación web están disponibles gratuitamente en Chrome y Firefox, con implementaciones de Edge y Safari en funcionamiento (caniuse). También hay un polyfill de código abierto bien mantenido que se puede usar mientras se espera la cobertura completa del navegador.

Cuando se trata de rendimiento, no debería haber ninguna diferencia en comparación con las transiciones CSS regulares, ya que los navegadores usan el mismo motor para ambos. Si te limitas a animar solo las propiedades que no causan redibujados, como transform y opacity , las animaciones deben mantener una velocidad constante de 60 fps.

Conclusión

La API de animación web brinda a los desarrolladores una forma nueva e increíble de crear y controlar animaciones web usando nada más que JavaScript puro. Para las animaciones que se invocan en la interacción del usuario u otros eventos dinámicos, esta es una gran noticia, ya que toda la animación se puede realizar en el código del controlador, sin tener que saltar a un archivo CSS para las transiciones reales.

Este artículo cubrió la mayoría de las funciones de la nueva API, pero si desea obtener más información, aquí hay un par de excelentes recursos que recomendamos:

  • Uso de la API de animaciones web en MDN
  • Animatelo:una revisión de Animate.css con la API de animación web
  • Hablemos de la API de animaciones web:un tutorial de cinco partes de Daniel C. Wilson