Abschnitt 13 · Lektion 3
@keyframes und animation
transition braucht immer etwas, das sich ändert, also einen Zeiger, einen Fokus oder eine Klasse, die dazukommt. Ein Spinner hat nichts davon. Er soll sich einfach drehen, sobald die Seite da ist. Für alles, was von allein losläuft, gibt es Animationen. Die bestehen aus zwei Teilen, den Stationen und der Anweisung, wie sie abgefahren werden.
Die Stationen
<div class="ladezone">
<span class="spinner"></span>
<span>Wird geladen</span>
</div>
<p class="hinweis">
Zwei Stationen, from und to, und eine Anweisung, das
Ganze endlos zu wiederholen. Einen Auslöser gibt es
nicht, die Animation läuft ab dem ersten Bild.
</p> *,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
padding: 24px;
font-family: system-ui, sans-serif;
line-height: 1.5;
}
@keyframes drehen {
from {
rotate: 0deg;
}
to {
rotate: 360deg;
}
}
.ladezone {
display: flex;
align-items: center;
gap: 12px;
color: #52525b;
}
.spinner {
width: 32px;
height: 32px;
border: 4px solid #dbeafe;
border-top-color: #2563eb;
border-radius: 50%;
/* Name, Dauer, Kurve, Wiederholungen. */
animation: drehen 0.8s linear infinite;
}
.hinweis {
max-width: 60ch;
margin-top: 32px;
color: #52525b;
} @keyframes name { ... } beschreibt, was wann gilt. Der ganze Block heißt kurz die Keyframes. Im einfachsten Fall stehen darin zwei Stationen, from und to. Den Namen wählst du frei und rufst ihn später in animation-name wieder auf. Mehr Verbindung gibt es nicht.
Der Block gehört auf die oberste Ebene des Stylesheets, nicht in eine Regel hinein. Ein Tippfehler im Namen lässt alles stillstehen, und eine Meldung bekommst du nicht. Anders als bei den verworfenen Zeilen aus Lektion 1.4 bleibt die Deklaration dabei stehen. Es fehlt nur der Block, der zu ihrem Namen passt.
Am Element steht das im Auskunftsstreifen als eine Zeile, animation: drehen 0.8s linear infinite, also Name, Dauer, Kurve und Anzahl. drehen zählt nur rotate hoch, und deshalb kannst du der Animation beim Rechnen zusehen. Am festgeklickten Ring steht dort rund rotate: 45deg, kurz darauf 142deg, dann 240deg und 337deg. Jeder Wert liegt knapp 100 Grad vor dem letzten. Eine volle Umdrehung dauert 0,8 Sekunden, die Zahl aus der animation-Zeile.
<div class="reihe">
<span class="punkt"></span>
<span class="punkt"></span>
<span class="punkt"></span>
</div>
<p class="hinweis">
Drei Stationen statt zwei, und die drei Punkte starten
versetzt. Der Versatz kommt allein aus animation-delay,
die Keyframes sind für alle drei dieselben.
</p> *,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
padding: 48px 24px;
font-family: system-ui, sans-serif;
line-height: 1.5;
}
@keyframes huepfen {
0% {
translate: 0px 0px;
}
40% {
translate: 0px -14px;
}
100% {
translate: 0px 0px;
}
}
.reihe {
display: flex;
gap: 12px;
}
.punkt {
width: 14px;
height: 14px;
border-radius: 50%;
background-color: #2563eb;
animation: huepfen 1s ease-in-out infinite;
}
.punkt:nth-child(2) {
animation-delay: 0.15s;
}
.punkt:nth-child(3) {
animation-delay: 0.3s;
}
.hinweis {
max-width: 60ch;
margin-top: 48px;
color: #52525b;
} Braucht der Ablauf mehr als Anfang und Ende, schreibst du die Stationen in Prozent. 0% und from bedeuten dasselbe, 100% und to ebenfalls. Zwischen den Stationen rechnet der Browser wie bei einer transition, und die Kurve gilt dabei für jeden Abschnitt einzeln.
Festgeklickt läuft die translate-Zeile eines Punkts von 0px 0px bis rund 0px -14px und wieder zurück. Ohne Klick hüpft er dir bei seinen 14 Pixeln unter dem Zeiger weg. Beim zweiten und dritten Punkt steht in der animation-Zeile eine Zahl mehr als beim ersten, beim dritten huepfen 1s ease-in-out 0.3s infinite. Das ist die Verzögerung. Sonst unterscheiden sich die drei in nichts.
Nicht jede Station muss jede Eigenschaft nennen. Fehlt sie in einer Station, rechnet der Browser einfach darüber hinweg. Er geht dann von der letzten Station, die sie nennt, bis zur nächsten. Bei 0% { opacity: 0 }, 50% { scale: 1.2 } und 100% { opacity: 1 } steht die Deckkraft bei der Hälfte deshalb nicht auf 1. Sie ist mitten auf dem Weg von 0 nach 1, mit der Standardkurve ease bei rund 0,8. Für sie gibt es die Station bei 50 Prozent gar nicht. Fehlt eine Eigenschaft schon bei 0%, gilt dort der Wert, den das Element ohne Animation hätte.
Die Anweisung
Am Element steht dann, wie der Ablauf gefahren wird:
animation-namenennt den Keyframes-Block.animation-durationist die Dauer eines Durchlaufs. Ohne sie ist die Dauer null, und es passiert nichts.animation-timing-functionist dieselbe Kurve wie bei der transition. Für Endlosdrehungenlinear, sonst hat jeder Durchlauf am Anfang und Ende eine Bremse.animation-delaywartet, bevor es losgeht. Damit staffelst du mehrere Elemente, wie die drei Punkte im Beispiel.animation-iteration-countist eine Zahl oderinfinite.animation-directionkehrt Durchläufe um.alternateläuft abwechselnd vor und zurück und spart dir die Hälfte der Stationen, weil du den Rückweg nicht schreiben musst.animation-fill-modeentscheidet, was vor und nach dem Ablauf gilt.animation-play-statehält an und läuft weiter, umschaltbar per Klasse oder Media Query.
Mit dem Shorthand animation: drehen 0.8s linear infinite; stehen die üblichen Angaben in einer Zeile. Wie bei transition ist bei zwei Zeitangaben die erste die Dauer und die zweite die Verzögerung.
Was vor und nach der Animation gilt
<p class="titel">Fahr über beide Bahnen und warte, bis sie fertig sind.</p>
<div class="bahn"><span class="balken bleibt"></span></div>
<p class="etikett">mit forwards</p>
<div class="bahn"><span class="balken springt"></span></div>
<p class="etikett">ohne fill-mode</p> *,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
padding: 24px;
font-family: system-ui, sans-serif;
line-height: 1.5;
}
@keyframes fuellen {
from {
width: 12%;
}
to {
width: 100%;
}
}
.titel {
max-width: 60ch;
margin: 0 0 24px 0;
color: #52525b;
}
.bahn {
width: 320px;
padding: 4px;
border-radius: 999px;
background-color: #e4e4e7;
}
.balken {
display: block;
width: 12%;
height: 14px;
border-radius: 999px;
background-color: #2563eb;
}
/* Der Auslöser sitzt an der Bahn und nicht am Balken:
die Bahn ist immer 320px breit, der Balken zu Beginn
keine 40, und der Zeiger verlöre ihn beim
Zurückschnappen sofort wieder. */
.bahn:hover .bleibt {
animation: fuellen 0.8s ease-out forwards;
}
.bahn:hover .springt {
animation: fuellen 0.8s ease-out;
}
.etikett {
margin: 8px 0 32px 0;
font-size: 14px;
color: #52525b;
} Von allein gilt eine Animation nur, solange sie läuft. Davor und danach sieht das Element aus, als gäbe es sie nicht. Ein Balken, der auf hundert Prozent wächst, schnappt deshalb am Ende auf seinen Startwert zurück.
animation-fill-mode: forwards lässt den Zustand der letzten Station stehen. backwards zieht die erste Station schon während der Verzögerung vor. Das verhindert das kurze Aufblitzen, wenn etwas mit animation-delay einblendet. both macht beides, und das nehme ich fast immer.
Im Beispiel siehst du den Unterschied, und wenn beide durchgelaufen sind, kannst du ihn auch ablesen. Am oberen Balken steht dann width: 312px, am unteren rund width: 37px, also wieder die zwölf Prozent vom Anfang. Woran es liegt, steht in der animation-Zeile, denn die endet oben auf forwards und unten nicht.
Wann transition, wann animation
transition nehme ich, wenn es einen Auslöser gibt und genau zwei Zustände, etwa Button normal und Button überfahren oder Feld leer und Feld im Fokus. Das ist der häufigere Fall, und es ist weniger Code.
Bei animation lande ich, wenn es keinen Auslöser gibt (ein Spinner), wenn es mehr als zwei Stationen gibt (ein Hüpfen) oder wenn sich etwas wiederholen soll. Beides kann eine Entscheidung gegen den Nutzer sein, und darum geht es in 13.4.
In der Aufgabe stehen ein Spinner und eine Überschrift, die sich beide noch nicht bewegen.
Zum Mitnehmen
Eine transition braucht einen Auslöser und kennt zwei Zustände, eine Animation läuft von allein über beliebig viele Stationen. Was davor und danach gilt, legt animation-fill-mode fest, und ohne forwards oder both schnappt der Endzustand zurück.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
Was in dieser Lektion steckt
-
Artikel mit 3 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe im Editor, direkt im Browser geprüft
Öffnet sich mit dem Basis Konto.