Verschiedene Ansätze zur Erstellung einer gestaffelten Animation

Avatar of Daniel Benmore
Daniel Benmore am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

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

    ChromeFirefoxIEEdgeSafari
    NeinNeinNeinNeinNein

    Mobil / Tablet

    Android ChromeAndroid FirefoxAndroidiOS Safari
    NeinNeinNeinNein

    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

    ChromeFirefoxIEEdgeSafari
    4931Nein1610

    Mobil / Tablet

    Android ChromeAndroid FirefoxAndroidiOS Safari
    12712712710.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.