[ Web Proxy ]
URL:
Viewing: https://developer.mozilla.org/es/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API [Back]  [Original]

Usar la API de Animaciones Web - API web | MDN

Esta pgina ha sido traducida del ingls por la comunidad. Aprende ms y nete a la comunidad de MDN Web Docs.

View in English Always switch to English

Usar la API de Animaciones Web

La API de Animaciones Web nos permite crear animaciones y controlar su reproduccin con JavaScript. Este artculo te pondr en el buen camino con demostraciones y tutoriales divertidos protagonizados por Alicia en el pas de las maravillas.

En este artculo

Conoce la API de Animaciones Web

La API de Animaciones Web abre el motor de animacin del navegador a los desarrolladores y a su manipulacin con JavaScript. Esta API se dise para servir de base tanto a las implementaciones de las animaciones CSS como a las de las transiciones CSS, y deja la puerta abierta a futuros efectos de animacin. Es una de las formas ms eficientes de animar en la web, ya que permite que el navegador haga sus propias optimizaciones internas sin trucos, imposiciones ni Window.requestAnimationFrame().

Con la API de Animaciones Web, podemos llevar las animaciones interactivas de las hojas de estilo a JavaScript, separando la presentacin del comportamiento. Ya no necesitamos depender de tcnicas que recargan el DOM, como escribir propiedades CSS y aadir clases a los elementos para controlar la direccin de la reproduccin. Y, a diferencia del CSS puro y declarativo, JavaScript tambin nos permite establecer dinmicamente valores, desde propiedades hasta duraciones. Para crear bibliotecas de animacin personalizadas y animaciones interactivas, la API de Animaciones Web puede ser la herramienta perfecta. Veamos lo que puede hacer!

Esta pgina contiene una serie de ejemplos que usan la API de Animaciones Web, inspirados en Alicia en el pas de las maravillas. Estos ejemplos los cre y comparte amablemente Rachel Nabors. La serie completa de ejemplos est disponible en CodePen; aqu presentamos los que son relevantes para nuestra documentacin.

Escribir animaciones CSS con la API de Animaciones Web

Una de las formas ms conocidas de empezar a aprender la API de Animaciones Web es partir de algo con lo que la mayora de los desarrolladores web ya han trabajado: las animaciones CSS. Las animaciones CSS tienen una sintaxis conocida que se presta muy bien para hacer demostraciones.

La versin en CSS

Esta es una animacin de cada escrita en CSS, que muestra a Alicia cayendo por la madriguera del conejo que lleva al pas de las maravillas:

Observa que el fondo se mueve, Alicia gira y su color cambia con un desfase respecto a su giro. En este tutorial nos vamos a centrar solo en Alicia. Puedes ver el cdigo fuente completo haciendo clic en "Play" en el bloque de cdigo. Este es el CSS simplificado que controla la animacin de Alicia:

css
#alice {
  animation: alice-tumbling infinite 3s linear;
}

@keyframes alice-tumbling {
  0% {
    color: black;
    transform: rotate(0) translate3d(-50%, -50%, 0);
  }
  30% {
    color: #431236;
  }
  100% {
    color: black;
    transform: rotate(360deg) translate3d(-50%, -50%, 0);
  }
}

Esto cambia el color de Alicia y la rotacin de su transformacin a lo largo de 3 segundos, a un ritmo constante (lineal), y se repite de forma infinita. En el bloque @keyframes podemos ver que, al 30 % de cada ciclo (hacia los 0,9 segundos), el color de Alicia cambia de negro a un burdeos intenso, y vuelve al negro al final del ciclo.

Pasarla a JavaScript

Ahora intentemos crear la misma animacin con la API de Animaciones Web.

Representar los fotogramas clave

Lo primero que necesitamos es crear un objeto de fotogramas clave que corresponda a nuestro bloque @keyframes de CSS:

js
const aliceTumbling = [
  { transform: "rotate(0) translate3d(-50%, -50%, 0)", color: "black" },
  { color: "#431236", offset: 0.3 },
  { transform: "rotate(360deg) translate3d(-50%, -50%, 0)", color: "black" },
];

Aqu usamos un array que contiene varios objetos. Cada objeto representa un fotograma clave del CSS original. Sin embargo, a diferencia de CSS, a la API de Animaciones Web no hace falta indicarle explcitamente en qu porcentaje de la animacin debe aparecer cada fotograma clave. La API divide automticamente la animacin en partes iguales segn el nmero de fotogramas clave que le des. Esto significa que un objeto de fotogramas clave con tres fotogramas reproducir el del medio al 50 % de cada ciclo de la animacin, salvo que se indique lo contrario.

Cuando queremos establecer explcitamente el desfase de un fotograma clave respecto a los dems, podemos especificar un desfase directamente en el objeto, separado de la declaracin por una coma. En el ejemplo anterior, para asegurarnos de que el color de Alicia cambie al 30 % (y no al 50 %), le damos offset: 0.3.

Por ahora, se deben especificar al menos dos fotogramas clave (que representan el estado inicial y el final de la secuencia de animacin). Si tu lista de fotogramas clave tiene una sola entrada, Element.animate() puede lanzar un DOMException NotSupportedError en algunos navegadores hasta que se actualicen.

En resumen, los fotogramas clave se distribuyen de forma uniforme de manera predeterminada, salvo que especifiques un desfase en alguno. Prctico, verdad?

Representar las propiedades de temporizacin

Tambin tendremos que crear un objeto con las propiedades de temporizacin que corresponda a los valores de la animacin de Alicia:

js
const aliceTiming = {
  duration: 3000,
  iterations: Infinity,
};

Notars algunas diferencias con respecto a cmo se representan los valores equivalentes en CSS:

  • Para empezar, la duracin se indica en milisegundos y no en segundos: 3000, no 3s. Al igual que setTimeout() y Window.requestAnimationFrame(), la API de Animaciones Web solo acepta milisegundos.
  • La otra cosa que notars es que se usa iterations, no iteration-count.

Nota: Hay varias pequeas diferencias entre la terminologa de las animaciones CSS y la de Web Animations. Por ejemplo, Web Animations no usa la cadena "infinite", sino la palabra clave de JavaScript Infinity. Y en lugar de timing-function usamos easing. Aqu no indicamos ningn valor de easing porque, a diferencia de las animaciones CSS, donde la animation-timing-function predeterminada es ease, en la API de Animaciones Web la funcin de aceleracin predeterminada es linear, que es justo lo que queremos.

Juntar las piezas

Ahora es el momento de juntar ambos con el mtodo Element.animate():

js
document.getElementById("alice").animate(aliceTumbling, aliceTiming);

Y listo: la animacin empieza a reproducirse:

El mtodo animate() se puede llamar en cualquier elemento del DOM que se pueda animar con CSS. Y se puede escribir de varias formas. En lugar de crear objetos para los fotogramas clave y las propiedades de temporizacin, podramos pasar sus valores directamente, as:

js
document.getElementById("alice").animate(
  [
    { transform: "rotate(0) translate3d(-50%, -50%, 0)", color: "black" },
    { color: "#431236", offset: 0.3 },
    { transform: "rotate(360deg) translate3d(-50%, -50%, 0)", color: "black" },
  ],
  {
    duration: 3000,
    iterations: Infinity,
  },
);

Es ms, si solo quisiramos especificar la duracin de la animacin y no sus iteraciones (de forma predeterminada, las animaciones se repiten una vez), podramos pasar solo los milisegundos:

js
document.getElementById("alice").animate(
  [
    { transform: "rotate(0) translate3d(-50%, -50%, 0)", color: "black" },
    { color: "#431236", offset: 0.3 },
    { transform: "rotate(360deg) translate3d(-50%, -50%, 0)", color: "black" },
  ],
  3000,
);

Controlar la reproduccin con play(), pause(), reverse() y updatePlaybackRate()

Aunque podemos escribir animaciones CSS con la API de Animaciones Web, donde la API resulta realmente til es en la manipulacin de la reproduccin de la animacin. La API de Animaciones Web ofrece varios mtodos tiles para controlar la reproduccin. Veamos cmo pausar y reproducir animaciones en el ejemplo "Sigue al conejo blanco":

En este ejemplo, el conejo blanco tiene una animacin que lo hace bajar por una madriguera. Solo se activa cuando el usuario hace clic en l.

Pausar y reproducir animaciones

Podemos animar al conejo con el mtodo animate(), como siempre:

js

El mtodo Element.animate() se ejecuta inmediatamente despus de llamarlo. Para evitar que el pastel se coma solo antes de que el usuario haya tenido la oportunidad de hacer clic en l, llamamos a Animation.pause() justo despus de definirlo, as:

js

Nota: Tambin puedes definir rabbitDownAnimation con el constructor Animation(), que no empieza a reproducirse hasta que llamas a play().

Ahora podemos usar el mtodo Animation.play() para ejecutarla cuando queramos. En concreto, queremos vincularla a una accin de clic. Podemos lograrlo as:

js

Cuando un usuario hace clic o toca al conejo con el dedo, ahora podemos llamar a downHeGoes para reproducir todas las animaciones.

Otros mtodos tiles

Adems de pausar y reproducir, podemos usar los siguientes mtodos de Animation:

Veamos primero playbackRate: un playbackRate negativo hace que una animacin se reproduzca al revs. En A travs del espejo, Alicia viaja a un mundo donde tiene que correr para quedarse en el mismo sitio, y correr el doble de rpido para avanzar! En el ejemplo de la carrera de la Reina Roja, Alicia y la Reina Roja corren para quedarse en el mismo sitio:

Como los nios pequeos se cansan con facilidad, a diferencia de las piezas de ajedrez autmatas, Alicia va cada vez ms despacio. Podemos lograrlo aplicando una disminucin progresiva al playbackRate de su animacin. Usamos updatePlaybackRate() en lugar de establecer playbackRate directamente, porque as la actualizacin es fluida:

js
setInterval(() => {
  // Asegurarse de que la velocidad de reproduccin nunca baje de 0,4
  if (redQueenAlice.playbackRate > 0.4) {
    redQueenAlice.updatePlaybackRate(redQueenAlice.playbackRate * 0.9);
  }
  adjustBackgroundPlayback();
}, 1000);

Pero animarlas haciendo clic o tocando la pantalla hace que aceleren, porque se multiplica su playbackRate:

js
function goFaster() {
  // Pero puedes acelerarlas haciendo clic o tocando la pantalla.
  redQueenAlice.updatePlaybackRate(redQueenAlice.playbackRate * 1.1);
  adjustBackgroundPlayback();
}

document.addEventListener("click", goFaster);
document.addEventListener("touchstart", goFaster);

Los elementos del fondo tambin tienen un playbackRate que cambia al hacer clic o tocar. Sus velocidades de reproduccin se derivan de la de Alicia, como se muestra a continuacin. Qu pasa si haces que Alicia y la Reina Roja corran el doble de rpido? Y si dejas que vayan ms despacio?

js
/* Alicia se cansa con mucha facilidad!
  Cada pocos segundos, reducimos su velocidad de reproduccin para que vayan un poco ms lento.
*/
const sceneries = [
  foreground1Movement,
  foreground2Movement,
  background1Movement,
  background2Movement,
];

function adjustBackgroundPlayback() {
  // Si Alicia y la Reina Roja corren a una velocidad de 0,81,2,
  // el fondo no se mueve.
  // Pero si bajan de 0,8, el fondo se desliza hacia atrs
  if (redQueenAlice.playbackRate < 0.8) {
    sceneries.forEach((anim) => {
      anim.updatePlaybackRate(-redQueenAlice.playbackRate / 2);
    });
  } else if (redQueenAlice.playbackRate > 1.2) {
    sceneries.forEach((anim) => {
      anim.updatePlaybackRate(redQueenAlice.playbackRate / 2);
    });
  } else {
    sceneries.forEach((anim) => {
      anim.updatePlaybackRate(0);
    });
  }
}
adjustBackgroundPlayback();

Conservar los estilos de la animacin

Al animar elementos, un caso de uso habitual es conservar el estado final de la animacin una vez terminada. Un mtodo que a veces se usa para esto es establecer el modo de relleno de la animacin en forwards. Sin embargo, no se recomienda usar los modos de relleno para conservar el efecto de una animacin de forma indefinida, por dos motivos:

  • El navegador tiene que mantener el estado de la animacin mientras sigue activa, as que la animacin sigue consumiendo recursos aunque ya no est animando. Ten en cuenta que esto se atena en parte porque el navegador elimina automticamente las animaciones de relleno.
  • Los estilos que aplican las animaciones tienen una mayor precedencia en la cascada que los estilos especificados, por lo que puede ser difcil sobrescribirlos cuando hace falta.

Una mejor opcin es usar el mtodo Animation.commitStyles(). Este mtodo escribe los valores calculados de los estilos actuales de la animacin en el atributo style de su elemento de destino, y a partir de ah se pueden volver a aplicar estilos al elemento con normalidad.

Eliminacin automtica de animaciones de relleno

Es posible activar una gran cantidad de animaciones en el mismo elemento. Si son indefinidas (es decir, con relleno hacia delante), esto puede generar una lista de animaciones enorme, lo que podra provocar una fuga de memoria. Por este motivo, los navegadores eliminan automticamente las animaciones de relleno cuando las reemplazan otras ms nuevas, salvo que el desarrollador indique explcitamente que se conserven.

Las animaciones se eliminan cuando se cumplen todas las condiciones siguientes:

  • La animacin tiene relleno (su fill es forwards si se reproduce hacia delante, backwards si se reproduce hacia atrs, o both).
  • La animacin ha terminado. (Ten en cuenta que, debido al fill, seguir teniendo efecto).
  • La lnea de tiempo de la animacin es montonamente creciente. (Esto siempre se cumple con DocumentTimeline; otras lneas de tiempo, como scroll-timeline, pueden avanzar hacia atrs).
  • La animacin no est controlada por un marcado declarativo, como CSS.
  • Todos los efectos de estilo del AnimationEffect de la animacin estn sobrescritos por otra animacin que tambin cumple todas las condiciones anteriores. (Normalmente, cuando dos animaciones establecen la misma propiedad de estilo del mismo elemento, la creada en ltimo lugar sobrescribe a la otra).

Las cuatro primeras condiciones garantizan que, sin la intervencin del cdigo JavaScript, el efecto de la animacin nunca cambiar ni terminar. La ltima condicin garantiza que la animacin nunca afectar realmente al estilo de ningn elemento, porque ha sido reemplazada por completo.

Cuando la animacin se elimina automticamente, se dispara su evento remove.

Para evitar que el navegador elimine automticamente las animaciones, llama al mtodo persist() de la animacin.

La propiedad replaceState de la animacin valdr removed si la animacin se elimin, persisted si llamaste a persist() en la animacin, o active en cualquier otro caso.

Obtener informacin de las animaciones

Imagina otras formas en las que podramos usar playbackRate, como mejorar la accesibilidad para los usuarios con trastornos vestibulares permitindoles ralentizar las animaciones de todo un sitio. Eso es imposible de hacer con CSS sin recalcular las duraciones en cada regla CSS, pero con la API de Animaciones Web podramos usar el mtodo Document.getAnimations para recorrer todas las animaciones de la pgina y reducir a la mitad su playbackRate, as:

js
document.getAnimations().forEach((animation) => {
  animation.updatePlaybackRate(animation.playbackRate * 0.5);
});

Con la API de Animaciones Web, basta con cambiar una pequea propiedad!

Otra cosa difcil de lograr solo con animaciones CSS es crear dependencias de valores proporcionados por otras animaciones. Por ejemplo, en el ejemplo del juego "Alicia crece y encoge", quizs hayas notado algo raro en la duracin del pastel:

js
document.getElementById("eat-me-sprite").animate([], {
  duration: aliceChange.effect.getComputedTiming().duration / 2,
});

Para entender lo que pasa aqu, veamos la animacin de Alicia:

js
const aliceChange = document
  .getElementById("alice")
  .animate(
    [
      { transform: "translate(-50%, -50%) scale(.5)" },
      { transform: "translate(-50%, -50%) scale(2)" },
    ],
    {
      duration: 8000,
      easing: "ease-in-out",
      fill: "both",
    },
  );

La animacin de Alicia la hace pasar de la mitad de su tamao al doble de su tamao a lo largo de 8 segundos. Despus la pausamos:

js
aliceChange.pause();

Si la hubiramos dejado pausada al principio de su animacin, empezara con la mitad de su tamao completo, como si ya se hubiera bebido toda la botella! Queremos colocar el "cabezal de reproduccin" de su animacin en el medio, para que ya vaya por la mitad. Podramos hacerlo estableciendo su Animation.currentTime en 4 segundos, as:

js
aliceChange.currentTime = 4000;

Pero, mientras trabajamos en esta animacin, es posible que cambiemos mucho la duracin de la animacin de Alicia. No sera mejor establecer su currentTime de forma dinmica, para no tener que hacer dos actualizaciones a la vez? De hecho, podemos hacerlo haciendo referencia a la propiedad Animation.effect de aliceChange, que devuelve un objeto con todos los detalles de los efectos activos sobre Alicia:

js
aliceChange.currentTime = aliceChange.effect.getComputedTiming().duration / 2;

effect nos permite acceder a los fotogramas clave y las propiedades de temporizacin de la animacin: aliceChange.effect.getComputedTiming() apunta al objeto de temporizacin de Alicia, que contiene su duration. Podemos dividir su duracin a la mitad para obtener el punto medio de la lnea de tiempo de su animacin y darle as su altura normal. Ahora podemos invertir y reproducir su animacin en cualquier direccin para hacerla ms pequea o ms grande!

Y podemos hacer lo mismo al establecer las duraciones del pastel y de la botella:

js
const drinking = document
  .getElementById("liquid")
  .animate([{ height: "100%" }, { height: "0" }], {
    fill: "forwards",
    duration: aliceChange.effect.getComputedTiming().duration / 2,
  });
drinking.pause();

Ahora las tres animaciones estn vinculadas a una sola duracin, que podemos cambiar fcilmente desde un nico lugar.

Tambin podemos usar la API de Animaciones Web para averiguar el tiempo actual de la animacin. El juego termina cuando se acaba el pastel o se vaca la botella. La escena final que ven los jugadores depende de lo avanzada que estaba Alicia en su animacin: si creci demasiado y ya no cabe por la puerta diminuta, o si se hizo demasiado pequea y no alcanza la llave para abrirla. Podemos saber si est en el extremo grande o pequeo de su animacin obteniendo el currentTime de su animacin y dividindolo por su activeDuration:

js
const endGame = () => {
  // obtener la posicin del cabezal de reproduccin de la lnea de tiempo de Alicia
  const alicePlayhead = aliceChange.currentTime;
  const aliceTimeline = aliceChange.effect.getComputedTiming().activeDuration;

  // detener la animacin de Alicia y las dems
  stopPlayingAlice();

  // segn el tercio en el que caiga
  const aliceHeight = alicePlayhead / aliceTimeline;

  if (aliceHeight <= 0.333) {
    // Alicia se hizo ms pequea!
    // 
  } else if (aliceHeight >= 0.666) {
    // Alicia se hizo ms grande!
    // 
  } else {
    // Alicia no cambi de forma significativa
    // 
  }
};

Callbacks y promesas

Las animaciones y las transiciones CSS tienen sus propios detectores de eventos, y tambin es posible usarlos con la API de Animaciones Web:

  • onfinish es el manejador del evento finish y se puede activar manualmente con finish().
  • oncancel es el manejador del evento cancel y se puede activar con cancel().

Aqu establecemos los callbacks del pastel, la botella y Alicia para que llamen a la funcin endGame:

js
// Cuando se acaba el pastel o la botella
nommingCake.onfinish = endGame;
drinking.onfinish = endGame;

// Alicia llega al final de su animacin
aliceChange.onfinish = endGame;

Mejor an, la API de Animaciones Web tambin ofrece una promesa finished que se resuelve cuando la animacin termina, o se rechaza si se cancela.

Conclusin

Estas son las funciones bsicas de la API de Animaciones Web. A estas alturas ya deberas estar listo para "bajar por la madriguera del conejo" de las animaciones en el navegador y para escribir tus propios experimentos de animacin!

Vase tambin


Web Proxy Viewer  |  New URL  |  Original Page