Mouvement

  • Utilisez clip-path et mask-image pour des révélations géométriques personnalisées et des fondus enchaînés fluides.
  • Utilisez les animations basées sur le défilement (animation-timeline: scroll()) pour les effets non essentiels liés au défilement au lieu des écouteurs JS.
  • Utilisez les transitions de vue pour animer facilement les transitions entre des états de mise en page complexes.

Performances

  • Privilégiez l'animation de opacity et transform (y compris les propriétés de transformation individuelles, par exemple translate au lieu de left/right/top/bottom) pour vous assurer que les animations restent sur le thread du compositeur.
  • Utilisez transition-behavior: allow-discrete, @starting-style et (pour les éléments de la couche supérieure comme <dialog> ou [popover]) overlay pour animer de manière native les états d'entrée et de sortie discrets. Consultez Animer l'entrée et la sortie d'un élément et Animer des éléments vers et depuis la couche supérieure.
.popover-reveal {
  /* Transition discrete display and top-layer overlay alongside opacity */
  transition:
    opacity ease-out,
    display,
    overlay;
  transition-duration: 0.2s;
  transition-behavior: allow-discrete;
}

Accessibilité

Utilisez les requêtes média prefers-reduced-motion pour désactiver les mouvements importants pour les utilisateurs qui le souhaitent.

  • Fournissez un mécanisme de mise en pause : permettez aux utilisateurs d'arrêter les carrousels, bannières ou autres animations persistantes qui s'exécutent automatiquement.
  • Utilisez des vues statiques par défaut : envisagez d'utiliser des états statiques par défaut et de permettre aux utilisateurs d'activer le mouvement.
  • Ne dépassez pas les limites de clignotement (trois par seconde) : n'incluez jamais de clignotement rapide de la lumière à l'obscurité. Ces effets peuvent provoquer des crises.

N'appliquez PAS animation-duration: 0.01ms; de manière globale, car cela peut rendre certaines animations plus saccadées. Gérez plutôt les préférences de mouvement au cas par cas en utilisant l'une des deux approches suivantes, en imbriquant la requête @media dans la règle afin que les deux versions soient conservées ensemble :

  • Commencez par activer les animations par défaut, puis atténuez-les à l'aide de @media (prefers-reduced-motion: reduce) :
/* Good: Dampen spin states or slow down animations for reduced motion */
.spinner {
  animation: spin 1s linear infinite;
  @media (prefers-reduced-motion: reduce) {
    animation: none;
    opacity: 0.5;
  }
}

progress:not([value]) {
  animation: slide 1s infinite linear;
  @media (prefers-reduced-motion: reduce) {
    animation-duration: 20s;
  }
}
  • Commencez par désactiver les animations par défaut, puis activez-les à l'aide de @media (prefers-reduced-motion: no-preference) :
/* Good: Default to static or gentle states and opt-in to full motion */
.spinner {
  opacity: 0.5;
  @media (prefers-reduced-motion: no-preference) {
    opacity: 1;
    animation: spin 1s linear infinite;
  }
}

progress:not([value]) {
  animation: slide 20s infinite linear;
  @media (prefers-reduced-motion: no-preference) {
    animation-duration: 1s;
  }
}

Utiliser les événements d'animation et de transition en JavaScript

Sur les interfaces AnimationEvent (animationstart, animationiteration, animationend, animationcancel) et TransitionEvent (transitionrun, transitionstart, transitionend, transitioncancel), event.target vous donne l'élément DOM d'origine. Pour accéder à l'objet Animation spécifique (Animation, CSSAnimation ou CSSTransition) qui a déclenché l'événement, utilisez la propriété en lecture seule event.animation.

Lorsque event.animation n'est pas disponible, vous pouvez généralement trouver l'instance Animation en appelant event.target.getAnimations() et en filtrant par event.animationName (ou event.propertyName pour les transitions). Toutefois, il est préférable d'utiliser directement event.animation pour éviter plusieurs scénarios dans lesquels cette solution de remplacement qui filtre event.target.getAnimations() ne fonctionne pas comme prévu :

  • Les animations de l'API Web Animations (element.animate()) n'ont pas d'animationName. Elles ne peuvent donc pas être mises en correspondance par nom lors du filtrage de event.target.getAnimations().
  • Le filtrage par animationName pour les AnimationEvent est ambigu lorsque plusieurs animations portant le même nom sont associées au même élément.
    • Notez que le filtrage sur transitionProperty pour les TransitionEvent fonctionne, car il n'y a qu'un seul événement par propriété de transition.
  • event.target pointe toujours vers l'élément DOM d'origine. Il ne fait donc pas de distinction entre les animations exécutées sur l'élément lui-même et celles exécutées sur l'un de ses pseudo-éléments, tandis que event.animation.effect.pseudoElement expose directement le pseudo-élément cible.
// Works in most basic CSS animation cases, but fails for WAAPI animations,
// duplicate animation names on the same element, or pseudo-elements.
document.addEventListener('animationstart', (event) => {
  const animation = event.target
    .getAnimations()
    .find((anim) => anim.animationName === event.animationName);
  console.log(animation);
});

// PREFERRED: Directly access the exact Animation object via event.animation
document.addEventListener('animationstart', (event) => {
  const animation = event.animation;
  console.log(animation);
});

Vous pouvez détecter la compatibilité à l'aide de 'animation' in AnimationEvent.prototype (ou 'animation' in TransitionEvent.prototype).