Améliorations de l'API Web Animations dans Chromium 84

Orchestration des animations avec des promesses, amélioration des performances avec des animations remplaçables, animations plus fluides avec les modes composites, etc.

Publié le 27 mai 2020

Lorsqu'elles sont utilisées correctement, les animations améliorent la perception et la mémorisation de votre marque par les utilisateurs, guident leurs actions et les aident à naviguer dans votre application, en fournissant du contexte dans un espace numérique.

L'API Web Animations est un outil qui permet aux développeurs d'écrire des animations impératives avec JavaScript. Il a été écrit pour soutenir à la fois les implémentations d'animation et de transition CSS, et permettre le développement de futurs effets, ainsi que la composition et la synchronisation des effets existants.

Alors que Firefox et Safari ont déjà implémenté l'ensemble des fonctionnalités de la spécification, Chromium 84 apporte de nombreuses fonctionnalités auparavant non compatibles à Chrome et Edge, ce qui permet une interopérabilité entre les navigateurs.

L'API Web Animations est apparue pour la première fois dans Chromium version 36, en juillet 2014. La spécification sera désormais complète dans la version 84, qui sera lancée en juillet 2020.
Longue histoire de l'API Web Animations dans Chromium.

Premiers pas

Si vous avez déjà utilisé des règles @keyframe, la création d'une animation à l'aide de l'API Web Animations devrait vous sembler très familière. Vous devez d'abord créer un objet de frame clé. Dans CSS, cela peut ressembler à ceci:

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

se présente comme suit en JavaScript :

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

Où vous définissez les paramètres d'animation en CSS:

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

Vous devez définir les valeurs suivantes en JS:

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

La quantité de code est à peu près la même, mais avec JavaScript, vous bénéficiez de quelques super-pouvoirs que vous n'avez pas avec le CSS seul. Cela inclut la possibilité de séquencer des effets et un contrôle accru de leurs états de lecture.

Plus de element.animate()

Toutefois, avec cette mise à jour, l'API Web Animations n'est plus limitée aux animations créées à l'aide de element.animate(). Nous pouvons également manipuler les animations et les transitions CSS.

getAnimations() est une méthode qui renvoie toutes les animations d'un élément, qu'il ait été créé à l'aide de element.animate() ou de règles CSS (animation ou transition CSS). Voici un exemple de ce à quoi cela peut ressembler:

Vous devez d'abord "get" les principaux points de la transition pour déterminer d'où nous partons. Vous créez ensuite deux animations d'opacité, ce qui active l'effet de fondu croisé. Une fois le fondu croisé terminé, supprimez la copie.

Comment orchestrer des animations avec des promesses

Dans Chromium 84, vous pouvez désormais utiliser deux méthodes avec des promesses: animation.ready et animation.finished.

  • animation.ready vous permet d'attendre que les modifications en attente prennent effet (c'est-à-dire de passer d'une méthode de contrôle de la lecture à une autre, comme la lecture et la mise en pause).
  • animation.finished permet d'exécuter du code JavaScript personnalisé une fois une animation terminée.

Poursuivons notre exemple et créons une chaîne d'animation orchestrée avec animation.finished. Ici, vous avez une transformation verticale (scaleY), suivie d'une transformation horizontale (scaleX), puis d'une modification de l'opacité d'un élément enfant:

Application de transformations et d'opacité à un élément modal qui s'ouvre. Voir la démonstration sur Codepen
const transformAnimation = modal.animate(openModal, openModalSettings);
transformAnimation.finished.then(() => { text.animate(fadeIn, fadeInSettings)});

Nous avons enchaîné ces animations à l'aide de animation.finished.then() avant d'exécuter le prochain ensemble d'animation de la chaîne. Les animations apparaissent ainsi dans l'ordre, et vous pouvez même appliquer des effets à différents éléments cibles avec différentes options définies (comme la vitesse et la facilité).

Dans CSS, cela serait fastidieux à recréer, en particulier lorsque vous appliquez des animations uniques, mais séquencées, à plusieurs éléments. Vous devez utiliser un @keyframe, déterminer les pourcentages de temps corrects pour placer les animations et utiliser animation-delay avant de déclencher les animations de la séquence.

Exemple: Lecture, mise en pause et retour arrière

Ce qui peut s'ouvrir doit se fermer. Heureusement, depuis Chromium 39, l'API Web Animations nous permet de lire, de mettre en pause et d'inverser nos animations.

Vous pouvez reprendre l'animation précédemment affichée et lui donner une animation inversée fluide en cliquant à nouveau sur le bouton à l'aide de .reverse(). Vous pouvez ainsi créer une interaction plus fluide et plus contextuelle pour notre modal.

Exemple d'ouverture et de fermeture d'une fenêtre modale en cliquant sur un bouton. Voir la démonstration sur Glitch

Vous pouvez créer deux animations en attente de lecture (openModal et une transformation d'opacité intégrée), puis mettre en pause l'une des animations, en la retardant jusqu'à ce que l'autre soit terminée. Vous pouvez ensuite utiliser des promesses pour attendre la fin de chaque tâche avant de lire. Enfin, vous pouvez vérifier si un indicateur est défini, puis inverser chaque animation.

Exemple: Interactions dynamiques avec des clés-images partielles

Exemple de retargeting, où un clic de souris ajuste l'animation à un nouvel emplacement. Voir la démonstration sur Glitch
selector.animate([{transform: `translate(${x}px, ${y}px)`}],
    {duration: 1000, fill: 'forwards'});

Dans cet exemple, il n'y a qu'un seul frame clé et aucune position de début n'est spécifiée. Voici un exemple d'utilisation de keyframes partiels. Le gestionnaire de souris effectue plusieurs actions: il définit un nouvel emplacement de fin et déclenche une nouvelle animation. La nouvelle position de départ est déduite de la position sous-jacente actuelle.

Vous pouvez déclencher de nouvelles transitions pendant que les transitions existantes sont en cours d'exécution. Cela signifie que la transition en cours est interrompue et qu'une nouvelle est créée.

Amélioration des performances avec les animations remplaçables

Lorsque vous créez des animations basées sur des événements, comme sur 'mousemove', une nouvelle animation est créée à chaque fois, ce qui peut rapidement utiliser de la mémoire et dégrader les performances. Pour résoudre ce problème, des animations remplaçables ont été introduites dans Chromium 83, ce qui permet un nettoyage automatique. Les animations terminées sont signalées comme remplaçables et supprimées automatiquement si elles sont remplacées par une autre animation terminée. Prenons l'exemple suivant :

Une traînée de comète s'anime lorsque la souris se déplace. Voir la démonstration sur Glitch
elem.addEventListener('mousemove', evt => {
  rectangle.animate(
    { transform: translate(${evt.clientX}px, ${evt.clientY}px) },
    { duration: 500, fill: 'forwards' }
  );
});

Chaque fois que la souris bouge, le navigateur recalcule la position de chaque boule dans la traînée de la comète et crée une animation vers ce nouveau point. Le navigateur sait désormais supprimer les anciennes animations (ce qui permet le remplacement) dans les cas suivants:

  1. L'animation est terminée.
  2. Une ou plusieurs animations plus élevées dans l'ordre de la composition sont également terminées.
  3. Les nouvelles animations animent les mêmes propriétés.

Vous pouvez voir exactement combien d'animations sont remplacées en comptabilisant un compteur pour chaque animation supprimée, à l'aide de anim.onremove pour déclencher le compteur.

Vous pouvez utiliser d'autres propriétés et méthodes pour contrôler encore plus votre animation:

  • animation.replaceState permet de savoir si une animation est active, persistante ou supprimée.
  • animation.commitStyles() met à jour le style d'un élément en fonction du style sous-jacent, ainsi que toutes les animations de l'élément dans l'ordre composite.
  • animation.persist() marque une animation comme non remplaçable.

Animations plus fluides avec les modes composites

Avec l'API Web Animations, vous pouvez désormais définir le mode composite de vos animations. Cela signifie qu'elles peuvent être additives ou cumulatives, en plus du mode par défaut "remplacement". Les modes composites permettent aux développeurs d'écrire des animations distinctes et de contrôler la combinaison des effets. Trois modes de composition sont désormais acceptés: 'replace' (mode par défaut), 'add' et 'accumulate'.

Lorsque vous composez des animations, un développeur peut écrire des effets courts et distincts, et les voir combinés. Dans l'exemple suivant, nous appliquons une clé-image de rotation et d'échelle à chaque boîte, le seul ajustement étant le mode composite, ajouté en tant qu'option:

Démonstration montrant les modes de composition par défaut, d'addition et d'accumulation. Voir la démonstration sur Glitch

Dans le mode de composable 'replace' par défaut, l'animation finale remplace la propriété de transformation et se termine à rotate(360deg) scale(1.4). Pour 'add', la composition ajoute la rotation et multiplie l'échelle, ce qui donne un état final de rotate(720deg) scale(1.96). 'accumulate' combine les transformations, ce qui donne rotate(720deg) scale(1.8). Pour en savoir plus sur les subtilités de ces modes composites, consultez les énumérations CompositeOperation et CompositeOperationOrAuto de la spécification Web Animations.

Examinez l'exemple d'élément d'interface utilisateur suivant:

Menu déroulant rebondissant auquel deux animations composées sont appliquées. Voir la démonstration sur Glitch

Ici, deux animations top sont composées. La première est une macro-animation, qui déplace le menu déroulant sur toute la hauteur du menu lui-même sous la forme d'un effet de glissement depuis le haut de la page. La seconde, une micro-animation, applique un léger rebond lorsqu'il atteint le bas. L'utilisation du mode composite 'add' permet une transition plus fluide.

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

Étapes suivantes pour l'API Web Animations

Il s'agit d'ajouts passionnants aux fonctionnalités d'animation des navigateurs actuels, et d'autres nouveautés sont en cours de développement. Consultez ces futures spécifications pour en savoir plus sur les nouveautés à venir: