Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten. Erfahre mehr über dieses Experiment.

View in English Always switch to English

Verwendung der Web Animations API

Die Web Animations API ermöglicht es uns, Animationen zu erstellen und deren Wiedergabe mit JavaScript zu steuern. Dieser Artikel wird Sie mit unterhaltsamen Demos und Tutorials mit Alice im Wunderland auf den richtigen Weg bringen.

Treffen Sie die Web Animations API

Die Web Animations API öffnet die Animationsmaschine des Browsers für Entwickler und die Manipulation durch JavaScript. Diese API wurde entworfen, um sowohl Implementierungen von CSS Animations als auch CSS Transitions zu unterstützen und lässt Raum für zukünftige Animationseffekte. Es ist eine der leistungsfähigsten Möglichkeiten, im Web zu animieren, da der Browser seine eigenen internen Optimierungen ohne Hacks, Zwang oder Window.requestAnimationFrame() durchführen kann.

Mit der Web Animations API können wir interaktive Animationen von Stylesheets zu JavaScript verschieben und so Präsentation und Verhalten trennen. Wir müssen uns nicht mehr auf DOM-intensive Techniken verlassen, wie z. B. CSS-Eigenschaften zu schreiben und Klassen auf Elemente zu setzen, um die Wiedergaberichtung zu steuern. Und im Gegensatz zu rein deklarativem CSS ermöglicht JavaScript auch das dynamische Setzen von Werten von Eigenschaften bis zu Dauerzeiten. Für den Aufbau benutzerdefinierter Animationsbibliotheken und das Erstellen interaktiver Animationen könnte die Web Animations API das perfekte Werkzeug sein. Lassen Sie uns sehen, was es leisten kann!

Diese Seite enthält eine Reihe von Beispielen, die die Web Animations API nutzen, inspiriert von Alice im Wunderland. Diese Beispiele wurden von Rachel Nabors erstellt und mit uns geteilt. Die vollständige Reihe von Beispielen ist auf CodePen verfügbar; hier präsentieren wir diejenigen, die für unsere Dokumentation relevant sind.

Schreiben von CSS-Animationen mit der Web Animations API

Eine der vertrauteren Möglichkeiten, um die Web Animations API zu erlernen, besteht darin, mit etwas zu beginnen, womit die meisten Webentwickler bereits gearbeitet haben: CSS-Animationen. CSS-Animationen haben eine vertraute Syntax, die sich gut zur Demonstration eignet.

Die CSS-Version

Hier ist eine Tumbling-Animation, die in CSS geschrieben wurde und Alice zeigt, wie sie in das Kaninchenloch fällt, das zum Wunderland führt:

Beachten Sie, dass sich der Hintergrund bewegt, Alice sich dreht und ihre Farbe versetzt zu ihrer Drehung ändert. Wir werden uns in diesem Tutorial nur auf Alice konzentrieren. Sie können sich den vollständigen Quellcode ansehen, indem Sie auf "Play" im Codeblock klicken. Hier ist das vereinfachte CSS, das die Animation von Alice steuert:

css
#alice {
  animation: alice-tumbling infinite 3s linear;
}

@keyframes alice-tumbling {
  0% {
    color: black;
    transform: rotate(0) translate3d(-50%, -50%, 0);
  }
  30% {
    color: #431236;
  }
  100% {
    color: black;
    transform: rotate(360deg) translate3d(-50%, -50%, 0);
  }
}

Dies ändert die Farbe von Alice und ihre Drehung über einen Zeitraum von 3 Sekunden mit einer konstanten (linear) Rate und wiederholt sich unendlich. Im @keyframes-Block können wir sehen, dass 30% des Weges durch jede Schleife (etwa 0,9 Sekunden), die Farbe von Alice von Schwarz zu einem tiefen Burgunder wechselt und am Ende der Schleife wieder zurückwechselt.

Übertragung auf JavaScript

Nun versuchen wir, dieselbe Animation mit der Web Animations API zu erstellen.

Darstellung von Keyframes

Das Erste, was wir brauchen, ist die Erstellung eines Keyframe Object, das unserem CSS-@keyframes-Block entspricht:

js
const aliceTumbling = [
  { transform: "rotate(0) translate3d(-50%, -50%, 0)", color: "black" },
  { color: "#431236", offset: 0.3 },
  { transform: "rotate(360deg) translate3d(-50%, -50%, 0)", color: "black" },
];

Hier verwenden wir ein Array, das mehrere Objekte enthält. Jedes Objekt repräsentiert einen Schlüssel des ursprünglichen CSS. Im Gegensatz zu CSS muss die Web Animations API jedoch nicht explizit die Prozentsätze angeben, zu denen jeder Schlüssel erscheinen soll. Sie wird automatisch die Animation in gleiche Teile basierend auf der Anzahl der angegebenen Schlüssel teilen. Das bedeutet, dass ein Keyframe-Objekt mit drei Schlüsseln den mittleren Schlüssel 50 % des Weges durch jede Schleife der Animation abspielen wird, es sei denn, es wird anders angegeben.

Wenn wir den Offset eines Schlüssels von den anderen Schlüsseln explizit festlegen wollen, können wir einen Offset direkt im Objekt angeben, getrennt von der Deklaration mit einem Komma. Im obigen Beispiel geben wir dem Farbwechsel von Alice offset: 0.3, um sicherzustellen, dass sich ihre Farbe bei 30% ändert (nicht bei 50%).

Derzeit sollten mindestens zwei Keyframes angegeben werden (die die Start- und Endzustände der Animationssequenz darstellen). Wenn Ihre Keyframe-Liste nur einen Eintrag hat, kann Element.animate() in manchen Browsern einen NotSupportedError-DOMException auslösen, bis diese aktualisiert werden.

Zusammenfassend: Die Schlüssel sind standardmäßig gleichmäßig verteilt, es sei denn, Sie geben einen Offset für einen Schlüssel an. Praktisch, oder?

Darstellung von Timing-Eigenschaften

Wir müssen auch ein Objekt mit Timing-Eigenschaften erstellen, das den Werten in Alice' Animation entspricht:

js
const aliceTiming = {
  duration: 3000,
  iterations: Infinity,
};

Ihnen fallen hier einige Unterschiede zur Darstellung gleichwertiger Werte in CSS auf:

  • Zum einen ist die Dauer in Millisekunden statt in Sekunden — 3000 und nicht 3s. Wie setTimeout() und Window.requestAnimationFrame() nimmt die Web Animations API nur Millisekunden an.
  • Außerdem fällt auf, dass es iterations und nicht iteration-count ist.

Hinweis: Es gibt einige kleine Unterschiede zwischen der Terminologie, die in CSS-Animationen verwendet wird, und der Terminologie in Web-Animationen. Beispielsweise verwendet Web Animations nicht den String "infinite", sondern das JavaScript-Schlüsselwort Infinity. Und anstelle von timing-function verwenden wir easing. Wir listen hier keinen easing-Wert auf, da im Gegensatz zu CSS-Animationen, bei denen die Standard-animation-timing-function ease ist, in der Web Animations API das Standard-Easing linear ist — was wir hier wollen.

Die Teile zusammenführen

Jetzt ist es an der Zeit, diese beiden mit der Element.animate()-Methode zusammenzuführen:

js
document.getElementById("alice").animate(aliceTumbling, aliceTiming);

Und boom: Die Animation beginnt zu spielen:

Die animate()-Methode kann auf jedem DOM-Element aufgerufen werden, das mit CSS animiert werden könnte. Und sie kann auf verschiedene Arten geschrieben werden. Anstatt Objekte für Keyframes und Timingeigenschaften zu erstellen, könnten wir ihre Werte auch direkt übergeben, wie folgt:

js
document.getElementById("alice").animate(
  [
    { transform: "rotate(0) translate3d(-50%, -50%, 0)", color: "black" },
    { color: "#431236", offset: 0.3 },
    { transform: "rotate(360deg) translate3d(-50%, -50%, 0)", color: "black" },
  ],
  {
    duration: 3000,
    iterations: Infinity,
  },
);

Außerdem, wenn wir nur die Dauer der Animation angeben wollten und nicht ihre Iterationen (standardmäßig iterieren Animationen einmal), könnten wir allein die Millisekunden übergeben:

js
document.getElementById("alice").animate(
  [
    { transform: "rotate(0) translate3d(-50%, -50%, 0)", color: "black" },
    { color: "#431236", offset: 0.3 },
    { transform: "rotate(360deg) translate3d(-50%, -50%, 0)", color: "black" },
  ],
  3000,
);

Steuerung der Wiedergabe mit play(), pause(), reverse() und updatePlaybackRate()

Während wir CSS-Animationen mit der Web Animations API schreiben können, liegt der wirkliche Nutzen dieser API in der Manipulation der Wiedergabe der Animation. Die Web Animations API bietet mehrere nützliche Methoden zur Steuerung der Wiedergabe. Lassen Sie uns das Pausieren und Abspielen von Animationen im Beispiel "Folgen Sie dem weißen Kaninchen" anschauen:

In diesem Beispiel hat das weiße Kaninchen eine Animation, die es veranlasst, in ein Kaninchenloch zu gehen. Sie wird nur ausgelöst, wenn der Benutzer darauf klickt.

Pausieren und Abspielen von Animationen

Wir können das Kaninchen wie gewohnt mit der animate()-Methode animieren:

js

Die Element.animate()-Methode wird unmittelbar nach ihrem Aufruf ausgeführt. Um zu verhindern, dass der Kuchen sich selbst aufisst, bevor der Benutzer die Chance hatte, darauf zu klicken, rufen wir Animation.pause() sofort nach der Definition auf, wie folgt:

js

Hinweis: Alternativ können Sie rabbitDownAnimation mit dem Konstruktor Animation() definieren, der nicht abgespielt wird, bis Sie play() aufrufen.

Wir können jetzt die Methode Animation.play() verwenden, um sie ablaufen zu lassen, wann immer wir bereit sind. Insbesondere wollen wir sie mit einer Klickaktion verknüpfen. Wir erreichen dies mit folgendem:

js

Wenn ein Benutzer auf das Kaninchen klickt oder ihren Finger darauf drückt, können wir jetzt downHeGoes aufrufen, um alle Animationen abzuspielen.

Andere nützliche Methoden

Zusätzlich zum Pausieren und Abspielen können wir die folgenden Animation-Methoden verwenden:

Lassen Sie uns zuerst die playbackRate anschauen — eine negative playbackRate wird dazu führen, dass eine Animation rückwärts läuft. In Through the Looking-Glass reist Alice in eine Welt, in der sie rennen muss, um an Ort und Stelle zu bleiben — und doppelt so schnell rennen, um sich vorwärts zu bewegen! Im Beispiel des Rennens der Roten Königin rennen Alice und die Rote Königin, um an Ort und Stelle zu bleiben:

Da kleine Kinder schnell ermüden, im Gegensatz zu automatischen Schachfiguren, verlangsamt sich Alice ständig. Wir können dies erreichen, indem wir einen Verfall auf ihre Animations-playbackRate setzen. Wir verwenden updatePlaybackRate() anstelle der direkten Einstellung der playbackRate, da dies ein reibungsloses Update erzeugt:

js
setInterval(() => {
  // Make sure the playback rate never falls below .4
  if (redQueenAlice.playbackRate > 0.4) {
    redQueenAlice.updatePlaybackRate(redQueenAlice.playbackRate * 0.9);
  }
  adjustBackgroundPlayback();
}, 1000);

Aber sie anzuregen, indem man klickt oder tippt, lässt sie schneller werden, indem ihre playbackRate multipliziert wird:

js
function goFaster() {
  // But you can speed them up by giving the screen a click or a tap.
  redQueenAlice.updatePlaybackRate(redQueenAlice.playbackRate * 1.1);
  adjustBackgroundPlayback();
}

document.addEventListener("click", goFaster);
document.addEventListener("touchstart", goFaster);

Auch die Hintergrundelemente haben playbackRates, die beeinträchtigt werden, wenn Sie klicken oder tippen. Ihre Wiedergaberaten leiten sich von der von Alice ab, wie unten gezeigt. Was passiert, wenn Sie Alice und die Rote Königin doppelt so schnell laufen lassen? Was passiert, wenn Sie sie verlangsamen lassen?

js
/* Alice tires so easily! 
  Every so many seconds, reduce their playback rate so they slow a little. 
*/
const sceneries = [
  foreground1Movement,
  foreground2Movement,
  background1Movement,
  background2Movement,
];

function adjustBackgroundPlayback() {
  // If Alice and the Red Queen are running at a speed of 0.8–1.2,
  // the background doesn't move.
  // But if they fall under 0.8, the background slides backwards
  if (redQueenAlice.playbackRate < 0.8) {
    sceneries.forEach((anim) => {
      anim.updatePlaybackRate(-redQueenAlice.playbackRate / 2);
    });
  } else if (redQueenAlice.playbackRate > 1.2) {
    sceneries.forEach((anim) => {
      anim.updatePlaybackRate(redQueenAlice.playbackRate / 2);
    });
  } else {
    sceneries.forEach((anim) => {
      anim.updatePlaybackRate(0);
    });
  }
}
adjustBackgroundPlayback();

Persistente Animationsstile

Beim Animieren von Elementen ist ein häufiger Anwendungsfall, den finalen Zustand der Animation zu behalten, nachdem die Animation beendet ist. Eine Methode, die manchmal verwendet wird, um dies zu erreichen, ist das Setzen des Animations-Fill-Modus auf forwards. Es wird jedoch nicht empfohlen, Fill-Modi zu verwenden, um den Effekt einer Animation auf unbestimmte Zeit beizubehalten, aus zwei Gründen:

  • Der Browser muss den Zustand der Animation beibehalten, während sie noch aktiv ist, sodass die Animation weiterhin Ressourcen verbraucht, obwohl sie nicht mehr animiert. Beachten Sie, dass dies etwas gemildert wird, indem der Browser füllende Animationen automatisch entfernt.
  • Von Animationen angewandte Stile haben eine höhere Priorität in der Kaskade als angegebene Stile, sodass es schwierig sein kann, sie bei Bedarf zu überschreiben.

Ein besserer Ansatz ist die Verwendung der Methode Animation.commitStyles(). Diese schreibt die berechneten Werte der aktuellen Stile der Animation in das {}-Attribut ihres Zielelements, danach kann das Element wie gewohnt umgestylt werden.

Automatisches Entfernen von füllenden Animationen

Es ist möglich, eine große Anzahl von Animationen auf dasselbe Element auszulösen. Wenn sie unbefristet (d.h. vorwärtsfüllend) sind, kann dies zu einer riesigen Animationsliste führen, die ein Speicherleck verursachen könnte. Aus diesem Grund entfernen Browser füllende Animationen automatisch, nachdem sie durch neuere Animationen ersetzt wurden, es sei denn, der Entwickler gibt ausdrücklich an, sie zu behalten.

Animationen werden entfernt, wenn Folgendes zutrifft:

  • Die Animation füllt (ihr fill ist forwards, wenn sie vorwärts läuft, backwards, wenn sie rückwärts läuft, oder both).
  • Die Animation ist fertig. (Beachten Sie, dass sie aufgrund des fill immer noch wirksam ist.)
  • Die Zeitleiste der Animation ist monoton ansteigend. (Dies ist immer wahr für DocumentTimeline; andere Zeitleisten wie scroll-timeline können rückwärts laufen.)
  • Die Animation wird nicht durch deklaratives Markup wie CSS gesteuert.
  • Jeder Styling-Effekt der AnimationEffect der Animation wird durch eine andere Animation überschrieben, die ebenfalls alle oben genannten Bedingungen erfüllt. (In der Regel, wenn zwei Animationen dieselbe Stil-Eigenschaft desselben Elements einstellen würden, überschreibt die zuletzt erstellte die andere.)

Die ersten vier Bedingungen stellen sicher, dass, ohne Eingriff durch JavaScript-Code, der Effekt der Animation niemals ändern oder enden wird. Die letzte Bedingung stellt sicher, dass die Animation keinen tatsächlichen Einfluss auf den Stil eines Elements hat: Sie wurde vollständig ersetzt.

Wenn die Animation automatisch entfernt wird, wird das remove Ereignis der Animation ausgelöst.

Um zu verhindern, dass der Browser Animationen automatisch entfernt, rufen Sie die Methode persist() der Animation auf.

Die replaceState-Eigenschaft der Animation wird removed sein, wenn die Animation entfernt wurde, persisted wenn Sie persist() auf die Animation aufgerufen haben, oder active sonst.

Informationen aus Animationen extrahieren

Stellen Sie sich andere Möglichkeiten vor, wie wir playbackRate verwenden könnten, zum Beispiel um die Barrierefreiheit für Benutzer mit vestibulären Störungen zu verbessern, indem sie Animationen auf einer gesamten Website verlangsamen können. Das ist mit CSS nicht möglich, ohne die Zeitdauern in jeder CSS-Regel neu zu berechnen, aber mit der Web Animations API könnten wir die Document.getAnimations-Methode verwenden, um jede Animation auf der Seite zu durchlaufen und ihre playbackRates zu halbieren, etwa so:

js
document.getAnimations().forEach((animation) => {
  animation.updatePlaybackRate(animation.playbackRate * 0.5);
});

Mit der Web Animations API müssen Sie nur eine kleine Eigenschaft ändern!

Eine weitere Sache, die allein mit CSS-Animationen schwer zu bewerkstelligen ist, ist das Erstellen von Abhängigkeiten von Werten, die von anderen Animationen bereitgestellt werden. Im Beispiel des Spiels "Alice wächst und schrumpft" haben Sie vielleicht etwas Merkwürdiges an der Dauer des Kuchens bemerkt:

js
document.getElementById("eat-me-sprite").animate([], {
  duration: aliceChange.effect.getComputedTiming().duration / 2,
});

Um zu verstehen, was hier passiert, schauen wir uns die Animation von Alice an:

js
const aliceChange = document
  .getElementById("alice")
  .animate(
    [
      { transform: "translate(-50%, -50%) scale(.5)" },
      { transform: "translate(-50%, -50%) scale(2)" },
    ],
    {
      duration: 8000,
      easing: "ease-in-out",
      fill: "both",
    },
  );

Die Animation von Alice lässt sie von der Hälfte ihrer Größe auf das Doppelte ihrer Größe über 8 Sekunden wachsen. Dann pausieren wir sie:

js
aliceChange.pause();

Wenn wir sie am Anfang ihrer Animation pausiert hätten, würde sie bei der Hälfte ihrer vollen Größe beginnen, als hätte sie die ganze Flasche schon getrunken! Wir wollen die "Playhead" ihrer Animation in der Mitte setzen, damit sie schon zur Hälfte fertig ist. Wir könnten das tun, indem wir ihre Animation.currentTime auf 4 Sekunden einstellen, etwa so:

js
aliceChange.currentTime = 4000;

Doch während wir an dieser Animation arbeiten, könnte sich Alices Dauer oft ändern. Wäre es nicht besser, wenn wir ihre currentTime dynamisch setzen, so dass wir nicht zwei Aktualisierungen auf einmal machen müssen? Tatsächlich können wir das tun, indem wir auf die Eigenschaft Animation.effect von aliceChange Bezug nehmen, die ein Objekt zurückgibt, das alle Details der Effekte enthält, die auf Alice aktiv sind:

js
aliceChange.currentTime = aliceChange.effect.getComputedTiming().duration / 2;

effect ermöglicht uns den Zugriff auf das Keyframe-und Timing-Objekt der Animation — aliceChange.effect.getComputedTiming() zeigt auf das Timing-Objekt von Alice — das enthält ihre duration. Wir können ihre Dauer halbieren, um den Mittelpunkt ihrer Animation-Zeitleiste zu erhalten und sie in normaler Höhe einzustellen. Jetzt können wir ihre Animation in beide Richtungen umkehren und abspielen lassen, um sie kleiner oder größer werden zu lassen!

Und wir können dasselbe tun, wenn wir die Dauer von Kuchen und Flasche einstellen:

js
const drinking = document
  .getElementById("liquid")
  .animate([{ height: "100%" }, { height: "0" }], {
    fill: "forwards",
    duration: aliceChange.effect.getComputedTiming().duration / 2,
  });
drinking.pause();

Jetzt sind alle drei Animationen mit nur einer Dauer verknüpft, die wir einfach an einer Stelle ändern können.

Wir können auch die Web Animations API verwenden, um die aktuelle Zeit der Animation herauszufinden. Das Spiel endet, wenn Ihnen der Kuchen ausgeht oder die Flasche leer ist. Welches Neuklavierspiel die Spieler präsentiert werden, hängt davon ab, wie weit Alice in ihrer Animation war, ob sie zu groß wurde und nicht mehr durch die kleine Tür passt oder zu klein wird und den Schlüssel zum Öffnen der Tür nicht erreichen kann. Wir können herausfinden, ob sie am großen oder kleinen Ende ihrer Animation ist, indem wir die currentTime ihrer Animation und ihr activeDuration durchlaufen:

js
const endGame = () => {
  // get Alice's timeline's playhead location
  const alicePlayhead = aliceChange.currentTime;
  const aliceTimeline = aliceChange.effect.getComputedTiming().activeDuration;

  // stops Alice's and other animations
  stopPlayingAlice();

  // depending on which third it falls into
  const aliceHeight = alicePlayhead / aliceTimeline;

  if (aliceHeight <= 0.333) {
    // Alice got smaller!
    // …
  } else if (aliceHeight >= 0.666) {
    // Alice got bigger!
    // …
  } else {
    // Alice didn't change significantly
    // …
  }
};

Rückrufe und Versprechen

CSS-Animationen und Übergänge haben ihre eigenen Ereignis-Listener, und diese sind auch mit der Web Animations API möglich:

  • onfinish ist der Ereignishandler für das finish-Ereignis und kann manuell mit finish() ausgelöst werden.
  • oncancel ist der Ereignishandler für das cancel-Ereignis und kann mit cancel() ausgelöst werden.

Hier setzen wir die Rückrufe für den Kuchen, die Flasche und Alice, um die endGame-Funktion auszulösen:

js
// When the cake or bottle runs out
nommingCake.onfinish = endGame;
drinking.onfinish = endGame;

// Alice reaches the end of her animation
aliceChange.onfinish = endGame;

Noch besser ist, dass die Web Animations API auch ein finished-Versprechen bietet, das aufgelöst wird, wenn die Animation endet, oder abgelehnt wird, wenn sie abgebrochen wird.

Fazit

Dies sind die grundlegenden Funktionen der Web Animations API. Bis jetzt sollten Sie bereit sein, "ins Kaninchenloch zu springen" und mit dem Animieren im Browser zu experimentieren und Ihre eigenen Animationsexperimente zu schreiben!

Siehe auch