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.

Kevin Ellis
Kevin Ellis

Publié le 27 mai 2020

Lorsqu'elles sont utilisées correctement, les animations améliorent la perception et la mémoire des utilisateurs concernant votre marque, 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 étayer les implémentations de transitions et d'animations CSS, et permettre le développement d'effets futurs, ainsi que la composition et la temporisation d'effets existants.

Même si Firefox et Safari ont déjà implémenté l'ensemble de leurs fonctionnalités, Chromium 84 apporte de nombreuses fonctionnalités auparavant non compatibles avec Chrome et Edge, ce qui permet l'interopérabilité entre 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 identique, mais avec JavaScript, vous bénéficiez de deux superpouvoirs dont vous ne disposez pas uniquement avec le CSS. Cela inclut la possibilité de séquencer des effets et un meilleur contrôle de leur état de lecture.

Au-delà 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 utiliser ("get") les images clés de la transition pour déterminer son point de départ. Ensuite, vous créez deux animations d'opacité pour activer l'effet de fondu enchaîné. Une fois le fondu enchaîné terminé, vous supprimez la copie.

Organiser 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 avec 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 chaîné ces animations à l'aide de animation.finished.then() avant d'exécuter l'ensemble d'animation suivant dans la chaîne. De cette façon, les animations apparaissent dans l'ordre, et vous appliquez même 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 lorsque vous cliquez à 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 lancer la lecture. Enfin, vous pouvez vérifier si un indicateur est défini, puis inverser chaque animation.

Exemple: Interactions dynamiques avec des images clés partielles

Exemple de reciblage : un clic de souris ramène 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. Dans ce cas, le gestionnaire de la souris définit un nouvel emplacement 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 bille 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 situées à un niveau supérieur dans l'ordre composite 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 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 composites 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 des 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', l'élément composite ajoute la rotation et multiplie l'échelle, ce qui donne l'é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 :