Single Element Loaders: Der Spinner

Avatar of Temani Afif
Temani Afif am

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

Das Erstellen von reinen CSS-Loadern ist eine meiner Lieblingsaufgaben. Es ist immer wieder befriedigend, sich diese unendlichen Animationen anzusehen. Und natürlich gibt es *viele* Techniken und Ansätze, um sie zu erstellen – man muss nur auf CodePen schauen, um zu sehen, wie viele es sind. In diesem Artikel werden wir jedoch sehen, wie man einen Single-Element-Loader mit möglichst wenig Code erstellt.

Ich habe eine Sammlung von mehr als 500 Single-Div-Loadern erstellt und werde in dieser vierteiligen Serie die Tricks teilen, die ich verwendet habe, um viele davon zu erstellen. Wir werden eine riesige Anzahl von Beispielen behandeln, zeigen, wie kleine Anpassungen zu lustigen Variationen führen können und wie wenig Code wir schreiben müssen, um das alles zu ermöglichen!

Single-Element-Loader-Serie

  1. Single Element Loaders: Der Spinner — Sie sind hier
  2. Single Element Loaders: Die Punkte
  3. Ein-Element-Loader: Die Balken
  4. Single Element Loaders: Going 3D

In diesem ersten Artikel werden wir eines der häufigsten Loader-Muster erstellen: rotierende Balken

Hier ist der Ansatz

Eine triviale Implementierung für diesen Loader besteht darin, für jeden Balken ein Element zu erstellen, das in ein Elternelement (insgesamt neun Elemente) eingeschlossen ist, und dann mit opacity und transform zu arbeiten, um den Rotationseffekt zu erzielen.

Meine Implementierung erfordert jedoch nur ein Element

<div class="loader"></div>

…und 10 CSS-Deklarationen

.loader {
  width: 150px; /* control the size */
  aspect-ratio: 1;
  display: grid;
  mask: conic-gradient(from 22deg, #0003, #000);
  animation: load 1s steps(8) infinite;
}
.loader,
.loader:before {
  --_g: linear-gradient(#17177c 0 0) 50%; /* update the color here */
  background: 
    var(--_g)/34% 8%  space no-repeat,
    var(--_g)/8%  34% no-repeat space;
}
.loader:before {
  content: "";
  transform: rotate(45deg);
}
@keyframes load {
  to { transform: rotate(1turn); }
}

Lassen Sie uns das aufschlüsseln

Auf den ersten Blick mag der Code seltsam aussehen, aber Sie werden sehen, dass er einfacher ist, als Sie vielleicht denken. Der erste Schritt ist, die Dimension des Elements zu definieren. In unserem Fall ist es ein 150px Quadrat. Wir können aspect-ratio verwenden, damit das Element quadratisch bleibt, egal was passiert.

.loader {
  width: 150px; /* control the size */
  aspect-ratio: 1; /* make height equal to width */
}

Beim Erstellen von CSS-Loadern versuche ich immer, einen Wert zur Steuerung der Gesamtgröße zu haben. In diesem Fall ist es die width und alle Berechnungen, die wir behandeln, werden sich auf diesen Wert beziehen. So kann ich einen einzigen Wert ändern, um den Loader zu steuern. Es ist immer wichtig, die Größe unserer Loader einfach anpassen zu können, ohne viele zusätzliche Werte anpassen zu müssen.

Als Nächstes verwenden wir Farbverläufe, um die Balken zu erstellen. Das ist der kniffligste Teil! Verwenden wir *einen* Farbverlauf, um *zwei* Balken zu erstellen, wie unten gezeigt

background: linear-gradient(#17177c 0 0) 50%/34% 8% space no-repeat;
Showing a space between two gradient lines for a single element loader.

Unser Farbverlauf ist mit einer Farbe und zwei Farbstopps definiert. Das Ergebnis ist eine Volltonfarbe ohne Ausblendung oder Übergänge. Die Größe beträgt 34% in der Breite und 8% in der Höhe. Er ist auch in der Mitte platziert (50%). Der Trick ist die Verwendung des Schlüsselworts space – dies dupliziert den Farbverlauf und ergibt uns insgesamt zwei Balken.

Aus der Spezifikation

Das Bild wird so oft wiederholt, wie es in den Hintergrund-Positionierungsbereich passt, ohne abgeschnitten zu werden, und dann werden die Bilder so verteilt, dass sie den Bereich ausfüllen. Das erste und letzte Bild berühren die Ränder des Bereichs.

Ich verwende eine Breite von 34%, was bedeutet, dass wir nicht mehr als zwei Balken haben können (3*34% ist größer als 100%), aber mit zwei Balken haben wir leere Stellen (100% - 2 * 34% = 32%). Dieser Platz wird in der Mitte zwischen den beiden Balken platziert. Mit anderen Worten, wir verwenden eine Breite für den Farbverlauf, die zwischen 33% und 50% liegt, um sicherzustellen, dass wir mindestens zwei Balken mit etwas Platz dazwischen haben. Der Wert space platziert sie korrekt für uns.

Wir tun dasselbe und erstellen einen zweiten ähnlichen Farbverlauf, um zwei weitere Balken oben und unten zu erhalten, was uns einen background-Eigenschaftswert von ergibt

background: 
 linear-gradient(#17177c 0 0) 50%/34% 8%  space no-repeat,
 linear-gradient(#17177c 0 0) 50%/8%  34% no-repeat space;

Das können wir mit einer CSS-Variablen optimieren, um Wiederholungen zu vermeiden

--_g: linear-gradient(#17177c 0 0) 50%; /* update the color here */
background: 
 var(--_g)/34% 8%  space no-repeat,
 var(--_g)/8%  34% no-repeat space;

Wir haben jetzt vier Balken und dank CSS-Variablen können wir den Farbwert einmal schreiben, was die spätere Aktualisierung erleichtert (wie wir es bei der Größe des Loaders getan haben).

Um die restlichen Balken zu erstellen, greifen wir auf das .loader-Element und sein ::before-Pseudo-Element zurück, um vier weitere Balken zu erhalten, was insgesamt acht ergibt.

.loader {
  width: 150px; /* control the size */
  aspect-ratio: 1;
  display: grid;
}
.loader,
.loader::before {
  --_g: linear-gradient(#17177c 0 0) 50%; /* update the color here */
  background: 
    var(--_g)/34% 8%  space no-repeat,
    var(--_g)/8%  34% no-repeat space;
}
.loader::before {
  content: "";
  transform: rotate(45deg);
}

Beachten Sie die Verwendung von display: grid. Dies ermöglicht es uns, uns auf die standardmäßige stretch-Ausrichtung des Grids zu verlassen, damit das Pseudo-Element den gesamten Bereich seines Elternelements abdeckt; so muss keine Dimension darauf angegeben werden – ein weiterer Trick, der den Code reduziert und uns erspart, uns mit vielen Werten befassen zu müssen!

Nun drehen wir das Pseudo-Element um 45deg, um die restlichen Balken zu positionieren. Fahren Sie mit der folgenden Demo mit der Maus darüber, um den Trick zu sehen

Opazität einstellen

Was wir zu tun versuchen, ist der Eindruck zu erwecken, dass es einen Balken gibt, der eine Spur von verblassenden Balken hinter sich herzieht, während er sich auf einem kreisförmigen Pfad bewegt. Was wir jetzt brauchen, ist, mit der Transparenz unserer Balken zu spielen, um diese Spur zu erzeugen, was wir mit CSS mask in Kombination mit einem konischen Farbverlauf wie folgt tun werden

mask: conic-gradient(from 22deg,#0003,#000);

Um den Trick besser zu sehen, wenden wir dies auf eine vollfarbige Box an

Die Transparenz der roten Farbe nimmt im Uhrzeigersinn allmählich zu. Wir wenden dies auf unseren Loader an und haben die Balken mit unterschiedlicher Opazität

Radial gradient plus, spinner bars equals spinner bars with gradients.

In Wirklichkeit scheint jeder Balken zu verblassen, weil er von einem Farbverlauf maskiert wird und zwischen zwei halbtransparenten Farben liegt. Das ist kaum bemerkbar, wenn dies läuft, also ist es so, als könnten wir sagen, dass alle Balken die gleiche Farbe mit unterschiedlichem Grad an Opazität haben.

Die Rotation

Wenden wir eine Rotationsanimation an, um unseren Loader zu erhalten. Beachten Sie, dass wir eine schrittweise Animation und keine kontinuierliche Animation benötigen, weshalb ich steps(8) verwende. 8 ist nichts anderes als die Anzahl der Balken, sodass dieser Wert geändert werden kann, je nachdem, wie viele Balken verwendet werden.

.loader {
  animation: load 3s steps(8) infinite;
}

/* Same as before: */
@keyframes load {
  to { transform: rotate(1turn) }
}

Das ist alles! Wir haben unseren Loader mit nur einem Element und wenigen Zeilen CSS. Wir können seine Größe und Farbe einfach durch Anpassen eines Wertes steuern.

Da wir nur das ::before-Pseudo-Element verwendet haben, können wir vier weitere Balken hinzufügen, indem wir ::after verwenden, um insgesamt 12 Balken zu erhalten, und das mit fast demselben Code

Wir aktualisieren die Rotation unserer Pseudo-Elemente auf 30deg und 60deg anstelle von 45deg und verwenden eine zwölfstündige Animation anstelle von acht. Ich habe auch die Höhe auf 5% anstelle von 8% reduziert, um die Balken etwas dünner zu machen.

Beachten Sie auch, dass wir auf den Pseudo-Elementen grid-area: 1/1 haben. Dies ermöglicht es uns, sie im selben Bereich wie ihre Geschwister zu platzieren, übereinander gestapelt.

Erraten Sie was? Wir können mit einer anderen Implementierung zum selben Loader gelangen

Können Sie die Logik hinter dem Code herausfinden? Hier ist ein Tipp: Die Opazität wird nicht mehr mit einer CSS-mask gehandhabt, sondern innerhalb des Farbverlaufs und verwendet auch die opacity-Eigenschaft.

Warum nicht stattdessen Punkte?

Das können wir absolut tun

Wenn Sie sich den Code ansehen, werden Sie feststellen, dass wir nun mit einem radialen Farbverlauf anstelle eines linearen arbeiten. Ansonsten ist das Konzept genau dasselbe, wobei die Maske den Eindruck von Opazität erzeugt, aber wir haben die Formen als Kreise anstelle von Linien erstellt.

Unten ist eine Abbildung zur Veranschaulichung der neuen Farbverlaufskonfiguration

Showing placement of dots in the single-element loader.

Wenn Sie Safari verwenden, beachten Sie, dass die Demo fehlerhaft sein kann. Das liegt daran, dass Safari derzeit die Unterstützung für die at-Syntax in radialen Farbverläufen vermissen lässt. Wir können den Farbverlauf jedoch etwas neu konfigurieren, um dies zu überwinden

.loader,
.loader:before,
.loader:after {
  background:
    radial-gradient(
      circle closest-side,
      currentColor 90%,
      #0000 98%
    ) 
    50% -150%/20% 80% repeat-y,
    radial-gradient(
      circle closest-side,
      currentColor 90%,
      #0000 98%
    ) 
    -150% 50%/80% 20% repeat-x;
}

Mehr Loader-Beispiele

Hier ist eine weitere Idee für einen Spinner-Loader, ähnlich dem vorherigen.

Für diesen setze ich nur auf background und mask, um die Form zu erstellen (keine Pseudo-Elemente nötig). Ich definiere die Konfiguration auch mit CSS-Variablen, um viele Variationen aus demselben Code erstellen zu können – ein weiteres Beispiel für die Kraft von CSS-Variablen. Ich habe noch einen Artikel über diese Technik geschrieben, wenn Sie mehr Details wünschen.

Beachten Sie, dass einige Browser immer noch auf ein -webkit- Präfix für mask-composite mit eigenen Werten zurückgreifen und den Spinner in der Demo nicht anzeigen. Hier ist eine Möglichkeit, dies ohne mask-composite für mehr Browserunterstützung zu tun.

Ich habe noch einen für Sie

Für diesen verwende ich eine background-color, um die Farbe zu steuern, und mask und mask-composite, um die endgültige Form zu erstellen

Different steps for applying a master to a element in the shape of a circle.

Bevor wir enden, hier sind noch ein paar rotierende Loader, die ich vor einiger Zeit erstellt habe. Ich setze auf verschiedene Techniken, verwende aber immer noch Farbverläufe, Masken, Pseudo-Elemente usw. Es könnte eine gute Übung sein, die Logik jedes einzelnen herauszufinden und gleichzeitig neue Tricks zu lernen. Wenn Sie Fragen dazu haben, ist der Kommentarbereich unten.

Zusammenfassung

Sehen Sie, es gibt so viel, was wir in CSS mit nichts als einem einzigen Div, ein paar Farbverläufen, Pseudo-Elementen und Variablen tun können. Es scheint, als hätten wir eine ganze Reihe verschiedener rotierender Loader erstellt, aber im Grunde ist es alles dasselbe mit kleinen Änderungen.

Das ist erst der Anfang. In dieser Serie werden wir uns weitere Ideen und fortgeschrittene Konzepte für die Erstellung von CSS-Loadern ansehen.

Single-Element-Loader-Serie

  1. Single Element Loaders: Der Spinner — Sie sind hier
  2. Single Element Loaders: Die Punkte
  3. Ein-Element-Loader: Die Balken
  4. Single Element Loaders: Going 3D