Das Erstellen von CSS-Animationen mag dem Erlernen der Syntax dienen, aber das Beherrschen einer schönen und intuitiv wirkenden Animation erfordert mehr Nuancen. Da Animationen so viel Aufmerksamkeit erregen, ist es wichtig, unseren Code zu verfeinern, um das Timing richtig hinzubekommen und Dinge zu beheben, wenn sie schiefgehen. Nachdem ich dieses Problem selbst angepackt hatte, dachte ich, ich sammle einige der Werkzeuge, die zur Unterstützung dieses Prozesses existieren.
Verwendung negativer Verzögerungswerte
Angenommen, Sie haben mehrere Animationen, die gleichzeitig laufen, und Sie möchten, dass sie sich ein wenig überlappen. Sie können animation-delay verwenden, aber Sie möchten nicht unbedingt, dass der Betrachter die Seite besucht und einige Dinge nicht bewegen, während sie auf ihre Verzögerung warten.
Sie können animation-delay auf eine negative Zahl setzen, und dies verschiebt die Abspielposition zurück in der Zeit, sodass alle Animationen laufen, wenn der Betrachter die Seite aufruft. Dies ist besonders nützlich, wenn die Animationen die gleichen Keyframe-Werte teilen und sich in der Bewegung nur durch die Verzögerung unterscheiden.
Sie können dieses Konzept zum Debuggen verwenden. Setzen Sie animation-play-state: paused; und passen Sie dann die Verzögerung auf verschiedene negative Zeiten an. Sie sehen die Animation in verschiedenen pausierten Zuständen während des Übergangs.
.thing {
animation: move 2s linear infinite alternate;
animation-play-state: paused;
animation-delay: -1s;
}
Beispiel
Siehe den Pen LVMMGZ von CSS-Tricks (@css-tricks) auf CodePen.
In einer lustigen Demo sehen wir, wie sich die beiden Roboter zu leicht unterschiedlichen Zeiten auf und ab bewegen, um natürlicher zu wirken. Wir geben dem lila Roboter eine negative Verzögerung, wenn wir die Hover-Animation deklarieren, damit er sich bewegt, wenn der Betrachter die Seite zum ersten Mal sieht.
.teal {
animation: hover 2s ease-in-out infinite both;
}
.purple {
animation: hover 2s -0.5s ease-in-out infinite both;
}
@keyframes hover {
50% {
transform: translateY(-4px);
}
}
Siehe den Pen Robotter Love von Sarah Drasner (@sdras) auf CodePen.
Die Leiden mehrerer Transform-Werte
Für die bestmögliche Leistung sollten Sie auch Dinge mit transform bewegen und ändern und sich den Aufwand von Neuanordnungen durch `margin` oder `top`/`left` und Ähnliches ersparen. Paul Lewis hat eine großartige Ressource namens CSS Triggers, die diese Kosten in einer leicht verständlichen Tabelle aufschlüsselt. Der Haken an der Sache ist, dass es bei dem Versuch, Dinge mit mehreren Transformationen zu bewegen, eine Reihe von Problemen gibt.
Ein großes Problem ist die Reihenfolge. Transformationen werden nicht gleichzeitig angewendet, wie man es vielleicht erwarten würde, sondern in einer bestimmten Reihenfolge. Die erste durchgeführte Operation ist diejenige, die am weitesten rechts steht, dann nach innen. Im Beispiel unten wird zuerst die Skalierung angewendet, dann die Translation, dann die Rotation.
@keyframes foo {
to {
/* 3rd 2nd 1st */
transform: rotate(90deg) translateX(30px) scale(1.5);
}
}
In den meisten Fällen ist das nicht ideal. Es ist wahrscheinlicher, dass Sie möchten, dass alles gleichzeitig passiert. Darüber hinaus wird dies weitaus komplexer, wenn Sie beginnen, die Transformationen in mehrere Keyframes aufzuteilen, wobei einige Werte gleichzeitig und andere nicht, wie hier
@keyframes foo {
30% {
transform: rotateY(360deg);
}
65% {
transform: translateY(-30px) rotateY(-360deg) scale(1.5);
}
90% {
transform: translateY(10px) scale(0.75);
}
}
Dies führt zu etwas überraschenden und weniger als idealen Ergebnissen. Die Antwort ist leider oft die Verwendung mehrerer verschachtelter <div>s, wobei jedem eine einzelne Transformation zugewiesen wird, damit keine Konflikte entstehen.
Siehe den Pen Show Order of Operations Transform Fail von Sarah Drasner (@sdras) auf CodePen.
Es gibt einige Alternativen, wie z. B. die Verwendung von Matrix-Transformationen (nicht intuitiv, von Hand zu codieren) oder die Verwendung einer JavaScript-Animations-API wie GreenSock, bei der es keine Reihenfolgesequenz für mehrere Transform-Interpolationen gibt.
Die Mehrfach-Div-Implementierung kann auch bei problematischen Bugs mit SVG helfen. In Safari können Sie Opazität und Transformation nicht gleichzeitig in einer Animation deklarieren – eine wird fehlschlagen. Sie können den Workaround in Aktion in der ersten Demo dieses Artikels sehen.
Anfang August 2015 sind unabhängige Transform-Deklarationen in Chrome Canary aufgenommen worden. Das bedeutet, dass wir uns nicht mehr lange um die Reihenfolge kümmern müssen. Sie können `rotate`, `translate` und `scale` separat deklarieren.
DevTools Timing-Helfer
Sowohl Chrome als auch Firefox verfügen inzwischen über spezielle Werkzeuge zur Unterstützung der Arbeit mit Animationen. Sie bieten einen Schieberegler zur Steuerung der Geschwindigkeit, eine Pausentaste und eine Benutzeroberfläche zur Bearbeitung der Beschleunigungswerte. Das Verlangsamen und das Anzeigen der Animation an bestimmten angehaltenen Punkten ist für das Debuggen von CSS-Animationen ziemlich hilfreich.
Beide verwenden Lea Verous cubic-bezier.com für Visualisierung und GUI. Das ist außerordentlich hilfreich, da Sie nicht mehr zwischen cubic-bezier.com, dem Texteditor und der Überprüfung wechseln müssen.
Diese Werkzeuge ermöglichen es uns, unsere Animationen intuitiver zu optimieren. Hier ist ein Blick auf die Benutzeroberfläche beider.


Sowohl Chrome als auch Firefox ermöglichen es Ihnen, das Timing zu steuern (schneller oder langsamer machen) und die Animation manuell durchzuspulen. Fortgeschrittenere Zeitleistenwerkzeuge kommen in Chrome, die mehrere Elemente gleichzeitig betrachten können. Das wird schön sein, da die Arbeit mit nur einem Element auf einmal in einer Animation ein ziemlich großer limitierender Faktor ist.
Eine Sache, mit der ich etwas zu kämpfen habe, ist das schnelle Erfassen des Elements, wenn die Animation kurzlebig und schnell ist. In solchen Fällen setze ich es normalerweise auf animation-iteration-count: infinite;, damit ich weiter damit spielen kann, ohne gegen die Zeit ankämpfen zu müssen.
Ich finde es auch äußerst hilfreich, die Animation stark zu verlangsamen und dann mit diesen Werkzeugen im Browser wieder abzuspielen und das Timing anzupassen. Es ermöglicht Ihnen, jede Bewegung auf einer fundamentalen Ebene zu zerlegen und zu sehen, wie alles interagiert und wie der Bewegungsfortschritt aussieht. Wenn Sie es bei dieser Geschwindigkeit verfeinern, wird es, wenn Sie es schneller abspielen lassen, viel meisterhafter aussehen.
Debugging von CSS-Animationsereignissen mit JavaScript
Wenn Sie herausfinden möchten, wann und wo genau jede Animation ausgelöst wird, können Sie mit etwas JavaScript erkennen und sich benachrichtigen lassen, wann jedes Ereignis auftritt, indem Sie sich mit animationstart, animationiteration und animationend verbinden.
Hier ist eine Demo davon
Siehe den Pen Showing how to Debug Animation Play States in JavaScript von Sarah Drasner (@sdras) auf CodePen.
Keyframes kurz halten
Ich sehe oft, dass Leute dieselbe Eigenschaft und denselben Wert im 0%- und 100%-Keyframe deklarieren. Das ist unnötig und führt zu aufgeblähtem Code. Der Browser übernimmt standardmäßig den Wert der Eigenschaften als Anfangs- und Endwert.
Das bedeutet, das ist übertrieben
.element {
animation: animation-name 2s linear infinite;
}
@keyframes animation-name {
0% {
transform: translateX(200px);
}
50% {
transform: translateX(350px);
}
100% {
transform: translateX(200px);
}
}
Es könnte so geschrieben werden
.element {
transform: translateX(200px);
animation: animation-name 2s linear infinite;
}
@keyframes animation-name {
50% {
transform: translateX(350px);
}
}
Animationen trocken legen (DRY)
Das Erstellen einer schönen und prägnanten Animation bedeutet normalerweise, eine sehr spezifische cubic-bezier()-Easing-Funktion zu schreiben. Eine fein abgestimmte Easing-Funktion funktioniert ähnlich wie die Farbpalette eines Unternehmens. Sie haben Ihre eigene spezifische Markenidentität und "Stimme" in Ihrer Bewegung. Wenn Sie dies überall auf einer Website verwenden (und das sollten Sie für Konsistenz tun), ist der einfachste Weg, eine oder zwei Easing-Funktionen in einer Variablen zu speichern, genau wie wir es mit unseren Farbpaletten tun. SASS und andere Prä-/Post-Prozessoren machen das einfach.
$smooth: cubic-bezier(0.17, 0.67, 0.48, 1.28);
.foo { animation: animation-name 3s $smooth; }
.bar { animation: animation-name 1s $smooth; }
Beim Animieren mit CSS-Keyframes möchten wir so viel Hilfe wie möglich von der GPU erhalten. Das bedeutet, dass Sie, wenn Sie mehrere Objekte animieren, eine Möglichkeit benötigen, das DOM einfach für die eingehende Bewegung vorzubereiten und das Element zu schichten. Sie können ein natives DOM-Element (nicht SVG) mit CSS durch eine Standarddeklaration hardwarebeschleunigen. Da wir diese auf allen animierten Elementen wiederverwenden, ist es sinnvoll, Tipparbeit zu sparen und dies mithilfe eines Mixins oder Extends hinzuzufügen.
@mixin accelerate($name) {
will-change: $name;
transform: translateZ(0);
backface-visibility: hidden;
perspective: 1000px;
}
.foo {
@include accelerate(transform);
}
Seien Sie vorsichtig. Zu viele Elemente gleichzeitig auszulagern kann einen umgekehrten Effekt haben und die Leistung beeinträchtigen. Die meisten Animationen sollten in Ordnung sein, aber seien Sie sich dessen bewusst, wenn Sie etwas wie Haml verwenden, um unzählige DOM-Elemente zu generieren.
Schleifen für bessere Leistung
Smashing Magazine hat kürzlich einen großartigen Beitrag veröffentlicht, der die Arbeit hinter dem fantastischen Projekt Species in Pieces zeigt. In einem Abschnitt geht der Autor detailliert darauf ein, wie die gleichzeitige Animation aller Teile zu Leistungsproblemen führte. Er erklärt:
Stellen Sie sich vor, Sie bewegen 30 Objekte gleichzeitig; Sie verlangen viel vom Browser, und es ist verständlich, dass dies Probleme verursachen würde. Wenn Sie eine Geschwindigkeit von 0,199 Sekunden und eine Verzögerung von 0,2 Sekunden auf jedem Objekt haben, würden Sie das Problem lösen, indem Sie nur ein Objekt nach dem anderen bewegen. Die Tatsache, dass die gleiche Gesamtbewegung stattfindet, spielt keine Rolle: Wenn die Animation als Kette ausgeführt wird, verbessert sich die Leistung sofort um das 30-fache.
Sie können Sass oder andere Prä-/Post-Prozessor-for-Schleifen für diese Art von Funktionalität nutzen. Hier ist eine ziemlich einfache Schleife, die ich geschrieben habe, um durch nth-child zu iterieren.
@for $i from 1 through $n {
&:nth-child(#{$i}) {
animation: loadIn 2s #{$i*0.11}s $easeOutSine forwards;
}
}
Nicht nur das, sondern Sie können sie auch verwenden, um visuelle Effekte wie Farben zu staffeln. (Drücken Sie Wiedergabe, um die Animation erneut auszuführen.)
Siehe den Pen SASS for loops in CSS Animations von Sarah Drasner (@sdras) auf CodePen.
Viele Animationen nacheinander anpassen
Wenn Sie längere Animationen erstellen, besteht die übliche Methode, mehrere Animationen oder Ereignisse zu sequenzieren, darin, sie mit progressiven Verzögerungen zu verketten. Also etwas wie
animation: foo 3s ease-in-out, bar 4s 3s ease-in-out, brainz 6s 7s ease-in-out;
Aber nehmen wir an, Sie nehmen Verfeinerungen vor und entdecken, dass die zweite Wiederholung der ersten Animation geändert werden soll. Dies wirkt sich auf die Verzögerungen von allem danach aus, also passen wir unser Timing für jedes einzelne danach an. Keine große Sache.
animation: foo 2.5s ease-in-out, bar 4s 2.5s ease-in-out, brainz 6s 6.5s ease-in-out;
Aber fügen wir nun eine weitere Animation hinzu und ändern die Verzögerung der zweiten erneut (diese Art von Feinabstimmung geschieht ständig bei der Erstellung einer wirklich guten Animation in der Produktion). Nun, das wird langsam etwas ineffizient. Wenn Sie das noch 3 Mal tun, ist es *wirklich* ineffizient.
Stellen Sie sich dann vor, mitten in der Animation müssen zwei Dinge gleichzeitig ausgelöst werden, sodass Sie das konsistente Timing mit zwei verschiedenen Eigenschaften beibehalten müssen und… nun, Sie verstehen es. **Deshalb wechsle ich, sobald ich über drei oder vier verkettete Animationen in einer Sequenz hinauskomme, normalerweise zu JavaScript.** Persönlich mag ich die GreenSock Animation API, da sie eine sehr robuste Timeline-Funktionalität hat, aber die meisten JS-Animationen ermöglichen es Ihnen, Animationen einfach zu stapeln, ohne Neuberechnungen durchführen zu müssen, was definitiv ein Workflow-Vorteil ist.
∞
Eine Animation gut funktionieren zu lassen, ist so viel mehr als nur ihre Erstellung. Typischerweise sind es die Bearbeitung, Verfeinerung und das Debugging, die ein Projekt von bloßer Bewegung zu einem gut orchestrierten und performanten Stück machen. Hoffentlich bringen diese Tipps einige zusätzliche Werkzeuge in Ihren Werkzeugkasten und glätten einige raue Kanten in Ihrem Workflow.
Toller Artikel. Viele wirklich hilfreiche Tipps und Tricks darin.
Ich frage mich, ob es Werkzeuge gibt, um CSS-Animationen auf eine zeitleistenartige Weise zu erstellen? Etwas Ähnliches wie Tweens aus der Flash-Ära, das aber CSS-Animationen ausgibt?
Ich glaube leider nicht, dass es das derzeit gibt. Es gibt einige zeitleistenbasierte Animationswerkzeuge wie Edge Animate und Animatron, die verschiedene Arten von JavaScript-Animationen exportieren. Und es gibt einige praktische Werkzeuge wie bounce.js (http://bouncejs.com/), die Ihnen helfen, Matrix-Transform-Animationen visuell zu erstellen.
Nicht für CSS, nein, aber *genau* wie in den Flash-Zeiten (weil Sie das vielleicht schon für Flash verwendet haben: GreenSock hat eine JS-Animations-API mit einer sehr robusten Timeline-Funktionalität: http://greensock.com/timelinemax. Ansonsten lässt bodymovin.js Dinge in After Effects erstellen und nach JavaScript exportieren. https://github.com/bodymovin/bodymovin. Hoffe, das hilft!
Perfekte Gelegenheit, ein Tool zu schreiben, das CSS exportiert, dann! (Oder vielleicht nur einen alternativen Exporteur für ein vorhandenes Tool.)
So etwas vielleicht? http://cssanimate.com/
Sieh an! Cooool. Guter Tipp.
Danke für den Artikel, sehr klar und leicht zu lesen!
Danke! Freut mich, dass Sie es hilfreich fanden!
Erstaunliche Informationen in Ihrem Artikel. Neue Tricks von Ihnen gelernt.
Mit CSS können wir leicht Grafiken und Animationen erstellen. Dev Tools und Schleifen sind dafür besser. Gute Arbeit. Danke fürs Teilen.
http://www.discoverwebdesignmelbourne.com.au/
Schöner Artikel!
Bezüglich der GPU-Unterstützung, ist es nicht völlig übertrieben,
will-change,backface-visibilityundtransformEigenschaften gleichzeitig zu verwenden?Gute Frage! Ich verwende `will-change` selbst nicht so viel, nur die anderen drei, aber ich kenne andere, die darauf schwören. Es wäre einen schnellen Test wert, um zu sehen, ob es Vorteile bringt, `will-change` hinzuzufügen (ich habe Tests durchgeführt, die zeigen, dass die anderen drei riesige Vorteile haben - siehe https://css-tricks.de/weighing-svg-animation-techniques-benchmarks/), aber ich sollte sowohl mit als auch ohne `will-change` erneut auf `div`s testen. Ich würde persönlich alles testen, was mit Leistung zu tun hat.
Toller Artikel!
Bezüglich des Problems mit mehreren Transformationen lässt es sich leicht beheben, indem man "none" zu den Keyframes mit weniger Transformationswerten hinzufügt.
Demo
http://codepen.io/brianknapp/pen/QbYboK
Also! Ich war wirklich begeistert, als ich Ihr Beispiel sah, aber nach einem sehr genauen Vergleich und (es gibt hier irgendwo einen Witz) *Debugging* ist Ihre Technik nicht wirklich dasselbe - es gibt einen kleinen, aber erkennbaren Unterschied, und es ist ein wenig ungenau - ein Unterschied, den wahrscheinlich nur jemand wie ich bemerkt - aber wenn man versucht, etwas Minutiöses zu perfektionieren, macht es einen Unterschied. Hier meine ich:
Siehe den Pen Show Order of Operations Transform Fail von Sarah Drasner (@sdras) auf CodePen.
Aber wenn ich mich da irre, lassen Sie es mich bitte wissen, ich versuche immer zu lernen.
Sie haben Recht. Nach viel Herumprobieren mit diesem Thema bin ich mir nicht sicher, was `none` tatsächlich tut, abgesehen davon, einige der Zustände zu glätten. Es schneidet auch den letzten Keyframe ab, was nicht gut ist :(
Tatsächlich werden die Transformationen immer "gleichzeitig" animiert, da es *keine* verschiedenen Transformationen gibt, sondern nur *eine* Transformation (genauso wie in der CSS-Syntax, bei der alle Transformationsfunktionen einen einzigen Wert der einzelnen
transform-Eigenschaft bilden) mit mehreren Komponenten, die durch mehrere Zwischenwerte animiert werden. Das Problem ist, dass fehlende Werte für die Transformationskomponenten ihre *Standardwerte* bedeuten, nicht *"unverändert"*. D.h.ist äquivalent zu
Aber wenn wir diese Standardwerte durch manuell interpolierte Werte ersetzen, können wir fast das gleiche Ergebnis erzielen wie mit separaten Animationen von unterschiedlich transformierten Wrappern: http://codepen.io/SelenIT/pen/pJYOmY
Daher ist es meiner Meinung nach eine Vereinfachung zu sagen, dass "Transformationen nacheinander angewendet werden".
Hallo SelenIT! Ihr Pen ist großartig, ich denke, es ist der erste, den ich erhalten habe, der zeigt, wie man ein `div` für alle Transform-Werte verwendet, ich werde den Beitrag bearbeiten, um diese Lösung aufzunehmen. Fantastisch.
Eines möchte ich noch sagen: Das Schreiben ist nicht sehr intuitiv. Berücksichtigen Sie, dass Sie nur die Skalierung von 1,5 auf 1,75 bei 60% anstelle von 65% anpassen müssen. Dann müssen Sie alle anderen Werte neu berechnen, die normalerweise für Sie interpoliert worden wären. Ich würde sagen, dass eine solche Workflow-Blockade Sie bei komplexeren Animationen oder wenn Sie versuchen, einige Dinge gleichzeitig zu verfeinern, stark verlangsamen kann. Sie vermeiden jedoch mehrere `div`s, sodass es wirklich davon abhängt, worauf Sie optimieren. Nochmals vielen Dank für Ihren Beitrag, ich bin sicher, er wird den Leuten helfen.