Das Animieren von Elementen ist im Grunde genommen ziemlich einfach. Definieren Sie die Keyframes. Benennen Sie die Animation. Rufen Sie sie auf einem Element auf.
Manchmal benötigen wir jedoch etwas *etwas* komplexeres, um das richtige "Gefühl" für die Art und Weise zu bekommen, wie sich Dinge bewegen. Zum Beispiel könnte ein Sound-Equalizer die gleiche Animation auf jedem Balken verwenden, aber sie sind gestaffelt, um die Illusion zu erwecken, unabhängig animiert zu sein.
Siehe den Pen
Apple Music Sound Equilizer in SVG von Geoff Graham (@geoffgraham)
auf CodePen.
Ich habe kürzlich ein Dashboard erstellt und wollte, dass die Elemente in einem der Widgets mit einer gestaffelten Animation in die Ansicht fließen.
Genau wie beim obigen Sound-Equalizer begann ich mit dem Ansatz `:nth-child`. Ich verwendete die unsortierte Liste (`
- `) als übergeordneten Container, gab ihr eine Klasse und setzte den `:nth-child`-Pseudoselektor ein, um jedes Listenelement mit `animation-delay` zu versetzen.
.my-list li {
animation: my-animation 300ms ease-out;
}
.my-list li:nth-child(1) {
animation-delay: 100ms;
}
.my-list li:nth-child(2) {
animation-delay: 200ms;
}
.my-list li:nth-child(3) {
animation-delay: 300ms;
}
/* and so on */
Diese Technik versetzt Elemente tatsächlich gut, besonders wenn man weiß, wie viele Elemente zu einem bestimmten Zeitpunkt in der Liste sein werden. Wo es jedoch scheitert, ist, wenn die Anzahl der Elemente unvorhersehbar ist, was bei dem Widget, das ich für das Dashboard erstellte, der Fall war. Ich wollte wirklich nicht jedes Mal, wenn sich die Anzahl der Elemente in der Liste ändert, zu diesem Code zurückkehren, also habe ich eine schnelle Sass-Schleife erstellt, die bis zu 50 Elemente berücksichtigt und die Animationsverzögerung mit jedem Element erhöht.
.my-list {
li {
animation: my-animation 300ms ease-out;
@for $i from 1 through 50 {
&:nth-child(#{$i}) {
animation-delay: 100ms * $i;
}
}
}
}
Das sollte es tun! Doch es fühlt sich viel zu umständlich an. Sicher, es fügt der Datei nicht viel Gewicht hinzu, aber Sie wissen, dass der kompilierte CSS eine Menge ungenutzter Selektoren enthält, wie z. B. `nth-child(45)`.
Es muss einen besseren Weg geben. Hier greife ich normalerweise zu JavaScript, um alle Elemente zu finden und eine Verzögerung hinzuzufügen, aber... dieses Mal habe ich etwas Zeit damit verbracht, zu untersuchen, ob es einen Weg gibt, es nur mit CSS zu machen.
Wie wäre es mit CSS-Zählern?
Das Erste, woran ich dachte, war die Verwendung eines CSS-Zählers in Kombination mit der `calc()`-Funktion.
.my-list {
counter-reset: my-counter;
}
.my-list li {
counter-increment: my-counter;
animation-delay: calc(counter(my-counter) * 100ms);
}
Leider funktioniert das nicht, da die Spezifikation besagt, dass Zähler nicht in `calc()` verwendet werden können).
Bestandteile eines `calc()`-Ausdrucks können literale Werte oder `attr()`- oder `calc()`-Ausdrücke sein.
Es stellt sich heraus, dass einige Leute diese Idee mögen, aber sie ist nicht über die Entwurfsphase hinausgekommen.
Wie wäre es mit einem Datenattribut?
Nachdem ich diesen Auszug aus der Spezifikation gelesen hatte, erfuhr ich, dass `calc()` `attr()` verwenden kann. Und gemäß der CSS Values and Units Specification)
In CSS3 kann der `attr()`-Ausdruck viele verschiedene Typen zurückgeben.
Das brachte mich zum Nachdenken; vielleicht könnte ein Datenattribut den Trick tun.
<ul class="my-list">
<li data-count="1"></li>
<li data-count="2"></li>
<li data-count="3"></li>
<li data-count="4"></li>
</ul>
.my-list li {
animation-delay: calc(attr(data-count) * 150ms);
}
Aber meine Hoffnung wurde zerschlagen, da die Browserunterstützung dafür teuflisch ist!
Diese Browserunterstützungsdaten stammen von Caniuse, wo es weitere Details gibt. Eine Zahl gibt an, dass der Browser die Funktion ab dieser Version unterstützt.
Desktop
| Chrome | Firefox | IE | Edge | Safari |
|---|---|---|---|---|
| Nein | Nein | Nein | Nein | Nein |
Mobil / Tablet
| Android Chrome | Android Firefox | Android | iOS Safari |
|---|---|---|---|
| Nein | Nein | Nein | Nein |
Also, zurück an den Zeichentisch.
Wie wäre es mit benutzerdefinierten Eigenschaften?
Die nächste Idee, die ich hatte, war die Verwendung von CSS benutzerdefinierten Eigenschaften. Es ist nicht schön, aber es hat funktioniert :)
Siehe den Pen
CSS-Variablen Animationsreihenfolge von Dan Benmore (@dbenmore)
auf CodePen.
Es stellt sich heraus, dass es auch ziemlich flexibel ist. Zum Beispiel kann die Animation umgekehrt werden.
Siehe den Pen
CSS-Variablen umgekehrte Animationsreihenfolge von Dan Benmore (@dbenmore)
auf CodePen.
Es kann auch etwas völlig Zufälliges tun *und* Elemente gleichzeitig animieren.
Siehe den Pen
CSS-Variablen zufällige Animationsreihenfolge von Dan Benmore (@dbenmore)
auf CodePen.
Wir können es sogar noch weiter treiben und einen diagonalen Schwung machen.
Siehe den Pen
Animationsstaffelung mit CSS-Eigenschaften / Variablen festlegen von Dan Benmore (@dbenmore)
auf CodePen.
Die Browserunterstützung ist gar nicht so schlecht (stupst IE mit einem Stock an).
Diese Daten zur Browserunterstützung stammen von Caniuse, wo es mehr Details gibt. Eine Zahl gibt an, dass der Browser die Funktion ab dieser Version unterstützt.
Desktop
| Chrome | Firefox | IE | Edge | Safari |
|---|---|---|---|---|
| 49 | 31 | Nein | 16 | 10 |
Mobil / Tablet
| Android Chrome | Android Firefox | Android | iOS Safari |
|---|---|---|---|
| 127 | 127 | 127 | 10.0-10.2 |
Eine der großartigen Funktionen von CSS ist, dass es dank der Kaskade Dinge ignoriert, die es nicht versteht. Das bedeutet, dass sich alles zusammen animiert. Wenn das nicht Ihr Ding ist, können Sie eine Feature-Abfrage hinzufügen, um eine Standardanimation zu überschreiben.
.my-list li {
animation: fallback-animation;
}
@supports (--variables) {
.my-list li {
animation: fancy-animation;
animation-delay: calc(var(--animation-order) * 100ms);
}
}
Vanilla CSS FTW
Je mehr ich innehalte und mich frage, ob ich JavaScript brauche, desto mehr bin ich erstaunt, was CSS allein tun kann. Sicher, es wäre schön, wenn CSS-Zähler in einer `calc()`-Funktion verwendet werden könnten, und es wäre eine ziemlich elegante Lösung. Aber im Moment bieten Inline benutzerdefinierte Eigenschaften eine leistungsstarke und flexible Möglichkeit, dieses Problem zu lösen.
Wenn Sie eine Art Vorlagensprache verwenden, ist ein einfacher Weg, eine `transition-delay`-Eigenschaft im Style-Attribut inline einzufügen, wie folgt:
{% for i in 0..10 %}{% endfor %}Ich würde das Setzen einer Indexvariable in der Schleife immer dem Setzen von `transition-delay` oder einer anderen ähnlichen Eigenschaft vorziehen. Das liegt daran, dass die Indexvariable nützlich sein kann, um mehr als eine Eigenschaft zu setzen. Zum Beispiel kann dieser Index auch die Farbton für den `background` oder einen horizontalen Versatz steuern.
Es kann auch die `transition-duration` steuern, wenn wir sie anders haben wollen, oder mehrere Dauer und Verzögerungen, wenn wir mehrere Eigenschaften animieren wollen.
Ich habe das letzte Woche buchstäblich auf einer Website mit der Sass-Schleife angewendet. Jetzt werde ich den benutzerdefinierten Eigenschaften-Ansatz ausprobieren. Danke für die Erstellung dieses Artikels!
Schön! Gestaffelte Verzögerungen sind etwas, das mir in SASS/SCSS besser gefallen hat als in styled-components. Die Kombination dieser Idee mit gemappten Indizes in React wird diese Sache super einfach machen. Du bist der MANN!
Ich baue sowieso alles in React, also benutze ich einfach den Index, um einen Animationsverzögerungs-Multiplikator hinzuzufügen. Ihre Methode erfordert immer noch, dass Sie eine Variable für jedes Element schreiben, was bei dynamischen Listen nicht funktioniert.
Die Sass-Schleife ist eine fantastische Idee. Ohne JS gab es für mich keine Hoffnung, solche Dinge zu tun. Vielen Dank. Ich werde in Zukunft mehr auf CSS achten.
Ich gehe einfach den JS-Weg.
Toller Artikel. Ein Problem bei gestaffelten Animationen, insbesondere bei Verzögerungen, ist, dass werbelastige Seiten mit einer ausgelasteten Haupt-Thread den Effekt oft ruinieren (unter iOS schlimmer).
Möglicherweise müssen Sie immer noch nur animieren, wenn der Thread frei ist.
Toller Artikel und Ideen.