W3docs

Animations JavaScript

Apprenez les animations JavaScript avec requestAnimationFrame, les fonctions d'easing, le chaînage, la Web Animations API et les bonnes pratiques de performance et d'accessibilité.

Les animations JavaScript offrent un moyen dynamique d'améliorer l'expérience utilisateur sur les pages web. Des effets subtils aux mouvements complexes, maîtriser les animations JavaScript peut considérablement rehausser l'interactivité et l'attrait visuel de vos projets. Ce guide complet vous proposera une exploration approfondie des animations JavaScript, incluant les concepts fondamentaux, les techniques essentielles et des exemples pratiques pour vous aider à devenir compétent dans la création d'animations engageantes.

Introduction aux animations JavaScript

Les animations JavaScript manipulent les éléments du Document Object Model (DOM) pour créer des effets visuels. Elles permettent de déplacer, redimensionner et modifier des éléments en réponse aux interactions de l'utilisateur ou automatiquement au fil du temps. En comprenant les principes et techniques de base, vous pouvez créer des animations à la fois performantes et visuellement attrayantes.

Pourquoi utiliser JavaScript pour les animations ?

Les animations JavaScript offrent un contrôle et une flexibilité supérieurs par rapport aux animations CSS. Elles permettent des séquences et des interactions plus complexes, rendant possible la création d'effets hautement personnalisés. Les animations JavaScript peuvent être contrôlées dynamiquement et sont souvent nécessaires lorsque vous avez besoin de répondre aux saisies de l'utilisateur ou de vous intégrer à d'autres fonctionnalités JavaScript.

En règle générale :

  • Privilégiez CSS (transition/@keyframes) pour les changements d'état simples et déclaratifs tels que les survols, les fondus et les bascules. Le navigateur optimise ceux-ci sur un thread de composition séparé, ce qui en fait généralement le choix le plus performant. Voir CSS animations.
  • Privilégiez JavaScript lorsque l'animation dépend de données, de gestes de l'utilisateur, de physique ou d'une logique que CSS ne peut pas exprimer — par exemple, suivre la souris, se positionner sur des positions dynamiques ou enchaîner de nombreuses étapes avec des conditions de branchement.

Pour l'option JavaScript la moins contraignante, la Web Animations API intégrée (décrite ci-dessous) vous offre des performances de qualité CSS avec un contrôle impératif, tandis que requestAnimationFrame vous donne un contrôle total image par image lorsque vous en avez besoin.

Concepts de base des animations JavaScript

Avant de plonger dans des techniques spécifiques, il est essentiel de comprendre quelques concepts de base qui sous-tendent les animations JavaScript :

  1. Images par seconde (FPS) : Le taux auquel les images d'animation sont affichées. Un FPS plus élevé produit des animations plus fluides.
  2. Fonctions d'easing : Ces fonctions contrôlent l'accélération et la décélération des animations, ajoutant un mouvement naturel.
  3. Fonctions de timing : Déterminent la durée et le délai des animations.
  4. Keyframes : Définissent les états de début, de fin et intermédiaires d'une animation.

requestAnimationFrame vs. setInterval

Avant que requestAnimationFrame n'existe, les animations étaient pilotées par setInterval et setTimeout, exécutant un callback toutes les quelques millisecondes. Cette approche présente deux problèmes : l'intervalle n'est pas synchronisé avec le taux de rafraîchissement de l'écran (provoquant des images perdues ou doublées), et le timer continue à se déclencher même lorsque l'onglet est en arrière-plan, gaspillant le CPU et la batterie.

requestAnimationFrame(callback) résout les deux. Le navigateur appelle votre callback juste avant le prochain rendu — généralement environ 60 fois par seconde, en correspondance avec l'affichage — et s'arrête automatiquement lorsque l'onglet est masqué. Le callback reçoit un argument timestamp haute résolution, que vous utilisez pour calculer la progression basée sur le temps réel écoulé plutôt que de supposer un taux d'images fixe.

// setInterval: fixed timer, not synced to the screen, runs in background tabs
let pos = 0;
const id = setInterval(() => {
  pos += 2;
  if (pos >= 200) clearInterval(id);
}, 16);

// requestAnimationFrame: synced to repaint, pauses in background tabs
function frame(timestamp) {
  // use timestamp to drive the animation
  requestAnimationFrame(frame);
}
requestAnimationFrame(frame);

Utilisez requestAnimationFrame pour tout ce qui met à jour les visuels à chaque image.

Exemple simple d'animation JavaScript

Commençons par un exemple simple où nous animons un carré se déplaçant sur l'écran.

<!DOCTYPE html>
<html>
<head>
  <style>
    #square {
      width: 50px;
      height: 50px;
      background-color: red;
      position: absolute;
      left: 0;
      top: 50px;
    }
  </style>
</head>
<body>
  <div id="square"></div>
  <script>
    const square = document.getElementById('square');
    let pos = 0;

    function move() {
      if (pos < window.innerWidth - 50) {
        pos += 2;
        square.style.transform = 'translateX(' + pos + 'px)';
        requestAnimationFrame(move);
      }
    }

    move();
  </script>
</body>
</html>

Cet exemple illustre une animation de base où un carré rouge se déplace du côté gauche de l'écran vers la droite. L'animation utilise la fonction requestAnimationFrame, qui assure un mouvement fluide en synchronisant l'animation avec le taux de rafraîchissement de l'affichage. La fonction move met à jour la position du carré de manière incrémentale et se rappelle continuellement jusqu'à ce que le carré atteigne le bord de la fenêtre.

Info

Bien que les animations JS nécessitent des mises à jour fréquentes des styles, préférez transform et opacity pour éviter de déclencher des recalculs de mise en page.

Techniques avancées dans les animations JavaScript

Utilisation des fonctions d'easing

Les fonctions d'easing rendent les animations plus naturelles en faisant varier la vitesse de l'animation. Elles attendent généralement une valeur de progression normalisée entre 0 et 1. Voici un exemple utilisant une fonction d'easing pour animer le carré :

<!DOCTYPE html>
<html>
<head>
  <style>
    #square {
      width: 50px;
      height: 50px;
      background-color: blue;
      position: absolute;
      left: 0;
      top: 50px;
    }
  </style>
</head>
<body>
  <div id="square"></div>
  <script>
    const square = document.getElementById('square');
    let start = null;
    const duration = 2000; // Animation duration in milliseconds

    function easeOutQuad(t) {
      return t * (2 - t);
    }

    function animate(timestamp) {
      if (!start) start = timestamp;
      let elapsed = timestamp - start;
      let progress = Math.min(elapsed / duration, 1);
      let easedProgress = easeOutQuad(progress);

      square.style.transform = 'translateX(' + (window.innerWidth - 50) * easedProgress + 'px)';

      if (progress < 1) {
        requestAnimationFrame(animate);
      }
    }

    requestAnimationFrame(animate);
  </script>
</body>
</html>

Cet exemple améliore l'animation simple en incorporant une fonction d'easing appelée easeOutQuad. Les fonctions d'easing créent des animations d'apparence plus naturelle en ajustant la vitesse de l'élément animé au fil du temps. Dans ce cas, le carré bleu se déplace de gauche à droite, commençant rapidement et ralentissant à l'approche de la fin. La durée de l'animation est fixée à 2000 millisecondes, et la position du carré est mise à jour en fonction de la progression avec easing.

Chaînage des animations

Le chaînage des animations vous permet d'exécuter plusieurs animations de manière séquentielle. Voici un exemple d'un carré qui se déplace d'abord vers la droite, puis vers le bas :

<!DOCTYPE html>
<html>
<head>
  <style>
    #square {
      width: 50px;
      height: 50px;
      background-color: green;
      position: absolute;
      left: 0;
      top: 0;
    }
  </style>
</head>
<body>
  <div id="square"></div>
  <script>
    const square = document.getElementById('square');
    let xPos = 0;
    let yPos = 0;

    function moveRight() {
      if (xPos < window.innerWidth - 50) {
        xPos += 2;
        square.style.transform = 'translateX(' + xPos + 'px)';
        requestAnimationFrame(moveRight);
      } else {
        xPos = 0;
        yPos = 0; // Explicitly reset yPos before downward phase
        square.style.transform = 'translateX(0px)';
        requestAnimationFrame(moveDown);
      }
    }

    function moveDown() {
      if (yPos < window.innerHeight - 50) {
        yPos += 2;
        square.style.transform = 'translateY(' + yPos + 'px)';
        requestAnimationFrame(moveDown);
      } else {
        yPos = 0; // Reset for repeated cycles
        requestAnimationFrame(moveRight);
      }
    }

    moveRight();
  </script>
</body>
</html>

Cet exemple illustre le chaînage des animations en déplaçant un carré vert d'abord vers la droite, puis vers le bas. La fonction moveRight déplace le carré vers la droite jusqu'à ce qu'il atteigne le bord de la fenêtre. Une fois qu'il atteint le bord droit, yPos est explicitement remis à 0 avant que moveDown ne soit appelé. Cette exécution séquentielle, combinée à une gestion correcte de l'état pour les cycles répétés, montre comment créer des séquences d'animation plus complexes en enchaînant plusieurs animations.

Animer plusieurs propriétés

Animer plusieurs propriétés simultanément peut créer des effets plus complexes et visuellement attrayants. Voici un exemple qui modifie à la fois la position et la couleur :

<!DOCTYPE html>
<html>
<head>
  <style>
    #square {
      width: 50px;
      height: 50px;
      background-color: purple;
      position: absolute;
      left: 0;
      top: 0;
    }
  </style>
</head>
<body>
  <div id="square"></div>
  <script>
    const square = document.getElementById('square');
    let pos = 0;

    function changeColor(progress) {
      let red = Math.floor(255 * progress);
      let green = Math.floor(255 * (1 - progress));
      return `rgb(${red}, ${green}, 0)`;
    }

    function animate() {
      if (pos < window.innerWidth - 50) {
        pos += 2;
        let progress = pos / (window.innerWidth - 50);
        square.style.transform = 'translateX(' + pos + 'px)';
        square.style.backgroundColor = changeColor(progress);
        requestAnimationFrame(animate);
      }
    }

    animate();
  </script>
</body>
</html>

Cet exemple anime à la fois la position et la couleur de fond d'un carré violet. Lorsque le carré se déplace de gauche à droite, sa couleur passe du rouge au vert. La fonction changeColor calcule la couleur en fonction de la progression de l'animation, créant un effet de dégradé. Cela démontre comment animer plusieurs propriétés simultanément, ajoutant de la complexité et de l'intérêt visuel aux animations.

La Web Animations API

Écrire manuellement une boucle requestAnimationFrame vous donne un contrôle total, mais pour la plupart des animations basées sur une timeline, le navigateur dispose déjà d'un moteur intégré : la Web Animations API (WAAPI). L'appel à element.animate(keyframes, options) exécute l'animation hors du thread principal lorsque c'est possible (comme CSS), vous offrant ainsi une lecture fluide sans avoir à écrire vous-même une boucle d'images. Il retourne également un objet Animation que vous pouvez mettre en pause, inverser, déplacer ou attendre.

<!DOCTYPE html>
<html>
<head>
  <style>
    #box {
      width: 50px;
      height: 50px;
      background-color: teal;
      position: absolute;
      left: 0;
      top: 50px;
    }
  </style>
</head>
<body>
  <div id="box"></div>
  <script>
    const box = document.getElementById('box');

    const animation = box.animate(
      [
        { transform: 'translateX(0)', opacity: 1 },
        { transform: 'translateX(300px)', opacity: 0.3 }
      ],
      {
        duration: 2000,
        easing: 'ease-out',
        fill: 'forwards'
      }
    );

    // The returned object gives you imperative control:
    animation.finished.then(() => console.log('done'));
    // animation.pause();  animation.reverse();  animation.currentTime = 1000;
  </script>
</body>
</html>

Le premier argument est un tableau de keyframes (chacun étant un objet de propriétés CSS) ; le second définit duration, easing, et des comportements comme fill (conserver l'état final), iterations, direction, et delay. Comme easing accepte les mêmes valeurs cubic-bezier() et mots-clés que CSS, vous n'avez souvent pas besoin d'écrire vous-même les calculs d'easing.

Préférez la WAAPI lorsque votre animation est une timeline fixe de changements de propriétés. Réservez une boucle manuelle requestAnimationFrame pour les cas où chaque image dépend d'une entrée en direct ou d'un état calculé — comme la physique, le glisser-déposer, ou des valeurs qui ne sont pas connues à l'avance.

Arrêter et inverser des animations

Une boucle requestAnimationFrame continue à tourner jusqu'à ce que vous arrêtiez de planifier de nouvelles images. Pour en annuler une immédiatement, sauvegardez l'ID que retourne requestAnimationFrame et passez-le à cancelAnimationFrame :

let rafId;

function loop(timestamp) {
  // ...update visuals...
  rafId = requestAnimationFrame(loop);
}

rafId = requestAnimationFrame(loop);

// Later, e.g. on a button click or when the element is removed:
cancelAnimationFrame(rafId);

Annulez toujours les animations en cours avant de retirer leurs éléments du DOM, sinon la boucle continue à muter un nœud détaché et génère du travail inutile à chaque image. Avec la Web Animations API, les équivalents sont simplement animation.cancel(), animation.pause(), et animation.reverse().

Accessibilité : respecter la réduction de mouvement

Des mouvements importants ou rapides peuvent provoquer des nausées, des vertiges ou des migraines chez certains utilisateurs. Les systèmes d'exploitation exposent une préférence « réduire le mouvement », et vous devriez la respecter. En JavaScript, lisez-la avec matchMedia et désactivez l'animation ou passez directement à l'état final :

const prefersReducedMotion = window.matchMedia(
  '(prefers-reduced-motion: reduce)'
).matches;

if (prefersReducedMotion) {
  // Skip the animation: apply the final state instantly
  square.style.transform = 'translateX(300px)';
} else {
  requestAnimationFrame(animate);
}

Cette vérification unique rend vos interfaces à la fois plus inclusives et plus agréables pour les utilisateurs qui choisissent de désactiver le mouvement.

Optimisation des performances des animations JavaScript

Pour garantir des animations fluides et efficaces, suivez ces conseils d'optimisation des performances :

  1. Utilisez requestAnimationFrame : Cette méthode se synchronise avec le taux de rafraîchissement de l'affichage, offrant des animations plus fluides.
  2. Minimisez les manipulations du DOM : Regroupez les mises à jour du DOM pour réduire les recalculs de mise en page et les re-rendus. Préférez transform et opacity pour les changements de position afin de tirer parti de l'accélération GPU.
  3. Optimisez le CSS : Utilisez des propriétés CSS accélérées par GPU comme transform et opacity.
  4. Limitez la fréquence des événements : Réduisez la fréquence des événements tels que resize ou scroll en utilisant des techniques de throttling ou de debouncing.
  5. Arrêtez les animations correctement : Utilisez cancelAnimationFrame pour arrêter les animations lorsqu'elles ne sont plus nécessaires. Stockez l'ID de l'animation et appelez cancelAnimationFrame(id) pour éviter les fuites mémoire. Exemple :
    let animationId = requestAnimationFrame(animate);
    // ... later ...
    cancelAnimationFrame(animationId);
  6. Évitez le layout thrashing : Ne lisez pas les propriétés de mise en page (par ex. offsetWidth, getBoundingClientRect) à l'intérieur de la boucle d'animation, car cela force le navigateur à recalculer les styles en milieu d'image et peut causer des saccades.
Info

Vous pouvez également créer des animations avec du CSS seul (sans JavaScript), ce qui conduira généralement à de meilleures performances. Voir CSS animations.

Conclusion

Maîtriser les animations JavaScript implique de comprendre les principes de base, d'implémenter des techniques avancées et d'optimiser les performances. En suivant ce guide, vous pouvez créer des animations engageantes et réactives qui améliorent l'expérience utilisateur. Expérimentez avec différentes fonctions d'easing, le chaînage et les animations de propriétés pour libérer tout le potentiel de JavaScript dans vos projets web.

Pour aller plus loin, explorez ces sujets connexes :

Pratique

Pratique
Quelles méthodes et fonctions sont couramment utilisées dans les animations JavaScript ?
Quelles méthodes et fonctions sont couramment utilisées dans les animations JavaScript ?
Was this page helpful?