Es gibt eine native API für Animationen in JavaScript, bekannt als die Web Animations API. Wir werden sie in diesem Beitrag WAAPI nennen. MDN hat eine gute Dokumentation dazu, und Dan Wilson hat eine großartige Artikelserie.
In diesem Artikel vergleichen wir WAAPI und CSS-Animationen.
Ein Hinweis zur Browserunterstützung
WAAPI verfügt über ein umfassendes und robustes Polyfill, das es ermöglicht, es heute schon produktiv einzusetzen, auch wenn die Browserunterstützung noch eingeschränkt ist.
Wie immer können Sie Can I Use für Daten zur Browserunterstützung prüfen. Diese liefern jedoch keine sehr guten Informationen zur Unterstützung aller Unterfunktionen von WAAPI. Hier ist ein Prüfer dafür:
Siehe den Pen WAAPI Browser Support Test von Dan Wilson (@danwilson) auf CodePen.
Um alle Funktionen ohne Polyfill auszuprobieren, verwenden Sie Firefox Nightly.
Die Grundlagen von WAAPI
Wenn Sie jemals die Methode .animate() von jQuery verwendet haben, sollte die grundlegende Syntax von WAAPI ziemlich vertraut wirken.
var element = document.querySelector('.animate-me');
element.animate(keyframes, 1000);
Die Methode animate akzeptiert zwei Parameter: Keyframes und Dauer. Im Gegensatz zu jQuery hat sie nicht nur den Vorteil, dass sie im Browser integriert ist, sondern ist auch performanter.
Das erste Argument, die Keyframes, sollte ein Array von Objekten sein. Jedes Objekt ist ein Keyframe in unserer Animation. Hier ist ein einfaches Beispiel:
var keyframes = [
{ opacity: 0 },
{ opacity: 1 }
];
Das zweite Argument, die Dauer, gibt an, wie lange die Animation dauern soll. Im obigen Beispiel sind es 1000 Millisekunden. Betrachten wir ein aufregenderes Beispiel.
Eine Animista CSS-Animation mit WAAPI nacherstellen
Hier ist ein CSS-Code, den ich von der fantastischen Seite animista für eine Animation namens „slide-in-blurred-top“ übernommen habe. Sieht ziemlich gut aus.

Hier sind die Keyframes in CSS:
0% {
transform: translateY(-1000px) scaleY(2.5) scaleX(.2);
transform-origin: 50% 0;
filter: blur(40px);
opacity: 0;
}
100% {
transform: translateY(0) scaleY(1) scaleX(1);
transform-origin: 50% 50%;
filter: blur(0);
opacity: 1;
}
Hier ist derselbe Code in WAAPI:
var keyframes = [
{
transform: 'translateY(-1000px) scaleY(2.5) scaleX(.2)',
transformOrigin: '50% 0', filter: 'blur(40px)', opacity: 0
},
{
transform: 'translateY(0) scaleY(1) scaleX(1)',
transformOrigin: '50% 50%',
filter: 'blur(0)',
opacity: 1
}
];
Wir haben bereits gesehen, wie einfach es ist, die Keyframes auf jedes Element anzuwenden, das wir animieren möchten.
element.animate(keyframes, 700);
Um das Beispiel einfach zu halten, habe ich nur die Dauer angegeben. Wir können diesen zweiten Parameter jedoch verwenden, um weit mehr Optionen zu übergeben. Zumindest sollten wir auch eine Beschleunigung angeben. Hier ist die vollständige Liste der verfügbaren Optionen mit einigen Beispielwerten:
var options = {
iterations: Infinity,
iterationStart: 0,
delay: 0,
endDelay: 0,
direction: 'alternate',
duration: 700,
fill: 'forwards',
easing: 'ease-out',
}
element.animate(keyframes, options);
Mit diesen Optionen beginnt unsere Animation ohne Verzögerung und wird abwechselnd vorwärts und rückwärts wiederholt.
Siehe den Pen motion blur waapi circle von CSS GRID (@cssgrid) auf CodePen.
Ärgerlicherweise variieren einige der Terminologien für uns, die mit CSS-Animationen vertraut sind, von dem, was wir gewohnt sind. Obwohl es auf der positiven Seite ist, dass die Dinge schneller zu tippen sind!
- Es ist
easingstattanimation-timing-function. - Statt
animation-iteration-countist esiterations. Wenn die Animation für immer wiederholt werden soll, ist esInfinitystatt infinite. Etwas verwirrend ist, dass Infinity nicht in Anführungszeichen steht.Infinityist ein JavaScript-Schlüsselwort, während die anderen Werte Zeichenketten sind. - Wir verwenden Millisekunden statt Sekunden, was jedem vertraut sein sollte, der viel JavaScript geschrieben hat. (Sie können auch Millisekunden in CSS-Animationen verwenden, aber nur wenige tun das.)
Werfen wir einen genaueren Blick auf eine der Optionen: iterationStart.
Ich war verwirrt, als ich zum ersten Mal auf iterationStart stieß. Warum sollte man bei einer bestimmten Iteration beginnen, anstatt einfach die Anzahl der Iterationen zu verringern? Diese Option ist meist nützlich, wenn Sie eine Dezimalzahl verwenden. Sie könnten sie beispielsweise auf .5 setzen, und die Animation würde auf halbem Weg beginnen. Es braucht zwei Hälften, um ein Ganzes zu ergeben. Wenn also Ihre Iterationsanzahl auf eins gesetzt ist und Ihr iterationStart auf .5 gesetzt ist, wird die Animation von der Hälfte bis zum Ende der Animation abgespielt, dann beginnt sie am Anfang der Animation und endet in der Mitte!
Es ist erwähnenswert, dass Sie auch die Gesamtzahl der Iterationen auf weniger als eins setzen können. Zum Beispiel:
var option = {
iterations: .5,
iterationStart: .5
}
Dies würde die Animation von der Mitte bis zum Ende abspielen.
endDelay: endDelay ist nützlich, wenn Sie mehrere Animationen nacheinander schalten möchten, aber eine Lücke zwischen dem Ende einer Animation und dem Beginn einer nachfolgenden Animation wünschen. Hier ist ein nützliches Video von Patrick Brosset, das dies erklärt.
Beschleunigung (Easing)
Easing ist eines der wichtigsten Elemente in jeder Animation. WAAPI bietet uns zwei verschiedene Möglichkeiten, Easing festzulegen: innerhalb unseres Keyframes-Arrays oder innerhalb unseres Options-Objekts.
In CSS, wenn Sie animation-timing-function: ease-in-out angewendet haben, würden Sie annehmen, dass der Anfang Ihrer Animation sich einblendet und das Ende Ihrer Animation sich ausblendet. Tatsächlich gilt das Easing zwischen den Keyframes, nicht für die gesamte Animation. Dies kann eine feingranulare Kontrolle über das Gefühl einer Animation geben. WAAPI bietet ebenfalls diese Möglichkeit.
var keyframes = [
{ opacity: 0, easing: 'ease-in' },
{ opacity: 0.5, easing: 'ease-out' },
{ opacity: 1 }
]
Es ist erwähnenswert, dass Sie sowohl in CSS als auch in WAAPI keinen Easing-Wert für den letzten Frame angeben sollten, da dies keine Auswirkung hat. Dies ist ein Fehler, den viele Leute machen.
Manchmal ist es viel intuitiver, das Easing über eine gesamte Animation hinzuzufügen. Dies ist mit CSS nicht möglich, kann aber jetzt mit WAAPI erreicht werden.
var options = {
duration: 1000,
easing: 'ease-in-out',
}
Sie können den Unterschied zwischen diesen beiden Arten von Easing in diesem Pen sehen:
Siehe den Pen Same animation, different easing von CSS GRID (@cssgrid) auf CodePen.
Easing vs. Linear
Es ist erwähnenswert, dass es einen weiteren Unterschied zwischen CSS-Animationen und WAAPI gibt: **Der Standard von CSS ist ease, während der Standard von WAAPI linear ist.** Ease ist tatsächlich eine Version von ease-in-out und ist eine ziemlich gute Option, wenn Sie faul sind. Linear hingegen ist todlangweilig und leblos – eine konstante Geschwindigkeit, die mechanisch und unnatürlich aussieht. Es wurde wahrscheinlich als Standard gewählt, da es die neutralste Option ist. Es ist jedoch noch wichtiger, bei der Arbeit mit WAAPI ein Easing anzuwenden als bei der Arbeit mit CSS, damit Ihre Animation nicht langweilig und roboterhaft wirkt.
Performance
WAAPI bietet die gleichen Leistungsverbesserungen wie CSS-Animationen, obwohl dies nicht bedeutet, dass eine reibungslose Animation unvermeidlich ist.
Ich hatte gehofft, dass die Leistungsoptimierungen dieser API es uns ermöglichen würden, auf die Verwendung von will-change und das völlig hacky translateZ zu verzichten – und irgendwann vielleicht. Zumindest in den aktuellen Browser-Implementierungen können diese Eigenschaften jedoch immer noch hilfreich und notwendig sein, um Jank-Probleme zu bewältigen.
Wenn Sie jedoch eine Verzögerung bei Ihrer Animation haben, müssen Sie sich keine Sorgen um die Verwendung von will-change machen. Der Hauptautor der Web-Animations-Spezifikation hatte einige interessante Ratschläge in der Animation for Work Slack community, die er hoffentlich nicht beanstandet, wenn ich sie hier wiederhole:
Wenn Sie eine positive Verzögerung haben, benötigen Sie kein
will-change, da der Browser die Schichtung zu Beginn der Verzögerung vornimmt und wenn die Animation startet, ist sie bereit.
WAAPI im Vergleich zu CSS-Animationen?
WAAPI bietet uns eine Syntax, um in JavaScript das zu tun, was wir bereits in einem Stylesheet tun konnten. Dennoch sollten sie nicht als Rivalen betrachtet werden. Wenn wir uns entscheiden, bei CSS für unsere Animationen und Übergänge zu bleiben, können wir mit WAAPI mit diesen Animationen interagieren.
Animations-Objekt
Die Methode .animate() animiert nicht nur unser Element, sie gibt auch etwas zurück.
var myAnimation = element.animate(keyframes, options);

Wenn wir den Rückgabewert in der Konsole betrachten, sehen wir, dass es sich um ein Animations-Objekt handelt. Dies bietet uns alle möglichen Funktionalitäten, von denen einige selbsterklärend sind, wie myAnimation.pause(). Wir konnten bereits ein ähnliches Ergebnis mit CSS-Animationen erzielen, indem wir die Eigenschaft animation-play-state geändert haben, aber die WAAPI-Syntax ist etwas knapper als element.style.animationPlayState = "paused". Wir haben auch die Möglichkeit, unsere Animation einfach mit myAnimation.reverse() umzukehren, was wiederum nur eine geringfügige Verbesserung gegenüber der Änderung der animation-direction CSS-Eigenschaft mit unserem Skript darstellt.
Allerdings war die Manipulation von @keyframes mit JavaScript bisher nicht gerade einfach. Selbst etwas so Einfaches wie das Neustarten einer Animation erfordert etwas Know-how, wie Chris Coyier bereits geschrieben hat. Mit WAAPI können wir einfach myAnimation.play() verwenden, um die Animation von vorne abzuspielen, wenn sie zuvor abgeschlossen war, oder um sie von der Mitte einer Iteration abzuspielen, wenn wir sie angehalten hatten.
Wir können sogar die Geschwindigkeit einer Animation mit vollständiger Leichtigkeit ändern.
myAnimation.playbackRate = 2; // speed it up
myAnimation.playbackRate = .4; // use a number less than one to slow it down
getAnimations()
Diese Methode gibt ein Array von allen Animations-Objekten für Animationen zurück, die wir mit WAAPI definiert haben, sowie für alle CSS-Übergänge oder Animationen.
element.getAnimations() // returns any animations or transitions applied to our element using CSS or WAAPI
Wenn Sie sich mit CSS für die Definition und Anwendung Ihrer Animationen wohlfühlen, ermöglicht Ihnen getAnimations() die Verwendung der API in Verbindung mit @keyframes. Es ist möglich, CSS weiterhin für den Großteil Ihrer Animationsarbeit zu verwenden und dennoch die Vorteile der API zu nutzen, wenn Sie sie benötigen. Sehen wir uns an, wie einfach das ist.
Selbst wenn ein DOM-Element nur eine Animation angewendet hat, gibt getAnimations() immer ein Array zurück. Greifen wir uns das einzelne Animations-Objekt, um damit zu arbeiten.
var h2 = document.querySelector("h2");
var myCSSAnimation = h2.getAnimations()[0];
Jetzt können wir die Web Animations API auf unsere CSS-Animation anwenden :)
myCSSAnimation.playbackRate = 4;
myCSSAnimation.reverse();
Promises und Events
Wir haben bereits eine Vielzahl von Ereignissen, die von CSS ausgelöst werden und die wir in unserem JavaScript-Code nutzen können: animationstart, animationend, animationiteration und transitionend. Ich muss oft auf das Ende einer Animation oder eines Übergangs warten, um das Element, auf das sie angewendet wurde, aus dem DOM zu entfernen.
Das Äquivalent zur Verwendung von animationend oder transitionend für diesen Zweck in WAAPI würde wieder das Animations-Objekt nutzen:
myAnimation.onfinish = function() {
element.remove();
}
WAAPI bietet uns die Wahl, sowohl mit Ereignissen als auch mit Promises zu arbeiten. Die Eigenschaft .finished unseres Animations-Objekts gibt ein Promise zurück, das am Ende der Animation aufgelöst wird. So würde das obige Beispiel mit einem Promise aussehen:
myAnimation.finished.then(() =>
element.remove())
Betrachten wir ein etwas komplexeres Beispiel, das aus dem Mozilla Developer Network übernommen wurde. Promise.all erwartet ein Array von Promises und führt unsere Callback-Funktion erst aus, wenn *alle* diese Promises aufgelöst wurden. Wie wir bereits gesehen haben, gibt element.getAnimations() ein Array von Animations-Objekten zurück. Wir können über alle Animations-Objekte im Array iterieren und bei jedem .finished aufrufen, was uns das benötigte Array von Promises liefert.
In diesem Beispiel wird unsere Funktion erst ausgeführt, nachdem *alle* Animationen auf der Seite abgeschlossen sind.
Promise.all(document.getAnimations().map(animation =>
animation.finished)).then(function() {
// do something cool
})
Die Zukunft
Die in diesem Artikel erwähnten Funktionen sind nur der Anfang. Die aktuelle Spezifikation und Implementierung scheinen der Beginn von etwas Großem zu sein.
Das ist großartig. Deklarative Übergänge passen perfekt zu CSS, aber Animationen fühlten sich aufgrund ihrer imperativen Natur immer umständlich an (zum Beispiel das Entfernen und erneute Hinzufügen einer Klasse, um sie erneut auszulösen). Übergänge sind implizit, Animationen sind imperativ. Ich bin unsicher wegen der nicht ganz CSS-Syntax für die Definition von Keyframe-Attributen, aber froh zu sehen, dass wir die Keyframes im natürlichen Kontext von CSS definieren und sie dann imperativ in JavaScript auslösen und darauf reagieren können. Das scheint das Beste aus beiden Welten zu sein.
Das einzige Problem, das ich mit der JavaScript-API habe, ist – wenn ich sie anstelle der Übergangsfunktion verwenden möchte –, dass ich nach Abschluss der Animation immer noch manuell alle CSS-Eigenschaften setzen muss, da sie animiert und dann auf den Zustand 0 zurückfällt.
Die
fill-Eigenschaft im Timing-Options-Objekt hilft dabei, wenn Sie sie aufforwardssetzen.Tolle Artikel…Schnelle Frage…Gibt es eine Möglichkeit, Prozentsätze bei den Keyframes festzulegen, wie bei CSS-Keyframes? In dem von Ihnen gegebenen Beispiel hatten Sie nur zwei Keyframes…einen für 0% und einen für 100% … Was, wenn Sie drei Keyframes hätten und sie beispielsweise bei 10%, 70% und 100% laufen lassen wollten? Gibt es eine Möglichkeit, das mit WAAPI einzustellen?
Das können Sie mit dem
offsetbei Keyframes tun.z.B.
Standardmäßig sind alle Keyframes gleichmäßig verteilt. Wie TLGregg sagte, verwenden Sie Offsets.
Guter Artikel über CSS-Animation.
Gibt es eine Chance, dass wir die Animationen eines Tages durchsuchen können?
Ich bin mir zu 91 % sicher, dass Sie Animationen, die in WAAPI gemacht wurden, in DevTools (Firefox oder Chrome) durchsuchen können.
Oh ja, ich bin mir da zu etwa 92 % sicher in Devtools, aber ich dachte mehr an die Möglichkeit, es in unserem Code zu schreiben, damit wir es vielleicht verwenden können, um den Fortschritt einer Animation an unsere Scroll-Position zu koppeln, ähnlich wie bei Parallax :D
Ja, Chris hat Recht. Die Animations-Entwicklertools mit ihrer Timeline-Funktion funktionieren auch für WAAPI-Animationen. Sehr hilfreich.
Hallo Chris. Die currentTime-Eigenschaft könnte Ihnen dabei helfen.
https://developer.mozilla.org/en-US/docs/Web/API/Animation/currentTime
Sie müssten sie irgendwie mit der Scroll-Position verknüpfen.
Es sieht so aus, als würden einfache Scroll-verknüpfte Animationen irgendwann implementiert werden.
https://wicg.github.io/scroll-animations/
Schauen Sie sich dieses wirklich schöne Beispiel von Dan Wilson an: https://codepen.io/danwilson/pen/JJEoxq/
Ich glaube, das ist genau das, wonach ich gesucht habe, danke Oliver. Ich habe eine React-Komponente erstellt, die Parallax behandelt, und ich möchte das gerne ausprobieren :)