Bewegung

  • Verwenden Sie clip-path und mask-image für benutzerdefinierte geometrische Einblendungen und weiche Ausblendungen.
  • Verwenden Sie für nicht unbedingt erforderliche scrollgebundene Effekte scrollgesteuerte Animationen (animation-timeline: scroll()) anstelle von JS-Listenern.
  • Mit Ansichtsübergängen können Sie nahtlose Animationen zwischen komplexen Layoutzuständen erstellen.

Leistung

  • Animieren Sie bevorzugt opacity und transform (einschließlich einzelner Transformations-Properties, z.B. translate statt left/right/top/bottom), damit Animationen im Compositor-Thread bleiben.
  • Verwenden Sie transition-behavior: allow-discrete, @starting-style und (für Elemente der obersten Ebene wie <dialog> oder [popover]) overlay, um diskrete Ein- und Ausstiegszustände nativ zu animieren. Weitere Informationen finden Sie unter Ein- und Ausstieg von Elementen animieren und Elemente zur und von der obersten Ebene animieren.
.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;
}

Bedienungshilfen

Verwenden Sie prefers-reduced-motion-Medienabfragen, um starke Bewegungen für Nutzer zu deaktivieren, die dies bevorzugen.

  • Pausenmechanismus bereitstellen: Ermöglichen Sie es Nutzern, automatisch laufende Karussells, Banner oder andere dauerhafte Animationen zu stoppen.
  • Standardmäßig statische Ansichten verwenden: Sie können standardmäßig statische Ansichten verwenden und Nutzern die Möglichkeit geben, Bewegungen zu aktivieren.
  • Blitzlimits nicht überschreiten (dreimal pro Sekunde): Verwenden Sie niemals schnelles Blinken von hell zu dunkel. Solche Effekte können Anfälle auslösen.

Wenden Sie animation-duration: 0.01ms; NICHT global an, da dies dazu führen kann, dass bestimmte Animationen noch störender wirken. Stattdessen sollten Sie die Bewegungseinstellungen von Fall zu Fall mit einem der beiden Ansätze verarbeiten und die @media-Abfrage in der Regel verschachteln, damit beide Versionen zusammengehalten werden:

  • Beginnen Sie mit standardmäßig aktivierten Animationen und reduzieren Sie sie mit @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;
  }
}
  • Standardmäßig ohne Animationen starten und mit @media (prefers-reduced-motion: no-preference) aktivieren:
/* 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;
  }
}

Mit Animations- und Übergangsereignissen in JavaScript arbeiten

Sowohl auf der AnimationEvent-Schnittstelle (animationstart, animationiteration, animationend, animationcancel) als auch auf der TransitionEvent-Schnittstelle (transitionrun, transitionstart, transitionend, transitioncancel) gibt event.target das ursprüngliche DOM-Element zurück. Verwenden Sie die schreibgeschützte Eigenschaft event.animation, um auf das spezifische Animation-Objekt (Animation, CSSAnimation oder CSSTransition) zuzugreifen, das das Ereignis ausgelöst hat.

Wenn event.animation nicht verfügbar ist, können Sie die Animation-Instanz in der Regel finden, indem Sie event.target.getAnimations() aufrufen und nach event.animationName (oder event.propertyName für Übergänge) filtern. Es wird jedoch empfohlen, event.animation direkt zu verwenden, um mehrere Szenarien zu vermeiden, in denen dieser Fallback, der event.target.getAnimations() filtert, nicht wie erwartet funktioniert:

  • Web Animations API-Animationen (element.animate()) haben keine animationName. Daher können sie beim Filtern von event.target.getAnimations() nicht nach Namen abgeglichen werden.
  • Das Filtern nach animationName für AnimationEvents ist mehrdeutig, wenn mehrere Animationen mit demselben Namen an dasselbe Element angehängt sind.
    • Das Filtern nach transitionProperty für TransitionEvents funktioniert, da es nur ein Ereignis pro Übergangsattribut gibt.
  • event.target verweist immer auf das ursprüngliche DOM-Element. Es wird also nicht zwischen Animationen unterschieden, die auf dem Element selbst oder auf einem seiner Pseudoelemente ausgeführt werden. event.animation.effect.pseudoElement hingegen gibt das Ziel-Pseudoelement direkt an.
// 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);
});

Sie können die Unterstützung mit 'animation' in AnimationEvent.prototype (oder 'animation' in TransitionEvent.prototype) erkennen.