Dies ist eine alte Version des Dokuments!
LU13: Keyframe-Animationen & Scroll-Animationen
(Theorie für Modul M291 – Web Frontend)
Auf dieser Seite finden Sie die Theorie zu folgenden Themen:
Was ist eine CSS-Animation?
id="was_ist_eine_css-animation"
Ein einzelnes Bild aus einer Animation heisst ein Frame. Die Animationstechnik, die wir in CSS nutzen, heisst Keyframe-Animation. Dabei werden Schlüsselframes (Keyframes) vorgegeben – vor allem Start und Ende – und alle Frames dazwischen werden vom Browser berechnet.
Eine CSS-Animation besteht aus genau zwei Teilen:
- Die Definition der Animation mit
@keyframes(Name + Ablauf) - Die Zuweisung an ein Element mit den
animation-*-Eigenschaften
Solange nur die Definition vorhanden ist, bewegt sich nichts – erst wenn sie einem Element zugewiesen wird, läuft die Animation.
@keyframes definieren
id="keyframes_definieren"
@keyframes einblenden { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
- Die
@keyframes-Regel leitet die Animationsdefinition ein. - Danach folgt ein frei wählbarer Name – er wird gleich gebraucht, um die Animation zuzuweisen.
from(entspricht0%) ist der erste Frame,to(entspricht100%) der letzte.- Im Keyframe stehen CSS-Eigenschaften, deren Wert sich interpolieren lässt: Grösse, Position, Farbe,
opacity,margin,border-radiusund viele mehr. Eigenschaften wiedisplayoderbackground-imagekönnen nicht interpoliert werden – sie wechseln schlagartig.
Für mehr als zwei Zustände können beliebig viele Prozent-Schritte angegeben werden:
@keyframes farbwechsel { from { background-color: yellow; } 33% { background-color: red; } 66% { background-color: blue; } to { background-color: yellow; } }
<note tip>
from / to oder Prozent?
Geht es nur darum, von Zustand A nach Zustand B zu animieren (z. B. einblenden, verschieben), reichen from und to vollständig aus. Prozent-Schritte benötigt man, wenn die Animation mehr als zwei Zustände hat.
</note>
Animation auf ein Element anwenden
id="animation_anwenden"
.kachel { animation-name: einblenden; animation-duration: 0.6s; animation-timing-function: ease; animation-delay: 0s; animation-iteration-count: 1; animation-direction: normal; animation-fill-mode: both; }
| Eigenschaft | Beispielwert | Bedeutung |
|---|---|---|
animation-name | einblenden | Name des @keyframes-Blocks |
animation-duration | 0.6s | Dauer der Animation |
animation-timing-function | ease | Beschleunigungskurve (ease, linear, ease-in-out, cubic-bezier()) |
animation-delay | 0.2s | Verzögerung vor dem Start |
animation-iteration-count | 1, 3, infinite | Wie oft die Animation wiederholt wird |
animation-direction | normal, alternate, reverse | Richtung der Wiederholung |
animation-fill-mode | both | Zustand vor / nach der Animation (→ siehe unten) |
animation-play-state | running, paused | Animation pausieren und fortsetzen |
Kurzschreibweise
Alle Eigenschaften lassen sich in einer einzigen Zeile zusammenfassen:
.kachel { animation: einblenden 0.6s ease 0.2s 1 normal both; /* Name Dauer Easing Delay Anzahl Richtung fill-mode */ }
<note important>
Reihenfolge bei zwei Zeitangaben: Wenn animation-delay und animation-duration beide angegeben werden, gilt: Dauer kommt zuerst, Delay an zweiter Stelle.
animation: name 0.6s 0.2s → 0.6 s Dauer, 0.2 s Delay.
</note>
Zeitangaben
Zeitangaben können in Sekunden (s) oder Millisekunden (ms) angegeben werden:
animation-duration: 1s; /* 1 Sekunde */ animation-duration: 300ms; /* 300 Millisekunden = 0.3 Sekunden */
animation-fill-mode
id="fill-mode"
Ohne fill-mode springt ein Element nach der Animation sofort in seinen ursprünglichen Zustand zurück. Ausserdem ist es vor dem Start in seinem normalen Zustand sichtbar – auch wenn die Animation mit opacity: 0 beginnen würde.
| Wert | Bedeutung |
|---|---|
none | Standardverhalten: kein spezieller Zustand vor oder nach der Animation |
forwards | Das Element bleibt nach dem Ende im to-Zustand |
backwards | Das Element startet sofort im from-Zustand (auch während eines Delays) |
both | Kombination aus forwards und backwards: empfohlener Wert für Einblend-Animationen |
@keyframes hereinschieben { from { opacity: 0; transform: translateX(-30px); } to { opacity: 1; transform: translateX(0); } } .element { opacity: 0; /* Ohne fill-mode wäre das Element vor dem Start kurz sichtbar */ animation: hereinschieben 0.5s ease 0.3s both; /* Delay ↑ ↑ fill-mode: both */ }
Mit fill-mode: both übernimmt das Element den from-Zustand (opacity: 0) bereits während des Delays – kein Aufflackern.
CSS Transforms
id="css-transforms"
Transformationen sind geometrische Operationen, die das Aussehen eines Elements verändern, ohne den Dokumentfluss zu beeinflussen (andere Elemente rücken nicht nach). Sie werden häufig in Animationen eingesetzt.
/* Verschieben: x nach rechts, y nach unten (negative Werte = gegengleich) */ transform: translate(20px, 10px); transform: translateX(20px); /* nur horizontal */ transform: translateY(-10px); /* nur vertikal */ /* Skalieren: 1 = Originalgrösse, > 1 vergrössert, < 1 verkleinert */ transform: scale(1.5); /* gleichmässig */ transform: scale(1.2, 0.8); /* horizontal × vertikal */ /* Rotieren: positive Werte = im Uhrzeigersinn */ transform: rotate(45deg); /* Scheren: Parallelogramm-Effekt */ transform: skewX(15deg); transform: skewY(10deg);
Mehrere Transformationen kombinieren
Transformationen können kombiniert werden – die Reihenfolge beeinflusst das Ergebnis:
/* Erst rotieren, dann verschieben – Verschiebung erfolgt im rotierten Koordinatensystem */ transform: rotate(45deg) translate(50px, 0); /* Erst verschieben, dann rotieren – Rotation erfolgt um den Ursprung, nicht um das Element */ transform: translate(50px, 0) rotate(45deg);
transform-origin
Standardmässig liegt der Ursprungspunkt aller Transformationen in der Mitte des Elements. Mit transform-origin lässt er sich verschieben:
/* Rotation um die obere linke Ecke */ transform-origin: left top; /* Rotation um die Mitte der Oberkante */ transform-origin: center 0px; /* Rotation um einen Punkt ausserhalb des Elements */ transform-origin: 50% 150%;
<note tip>
transform ist besonders gut für Animationen geeignet, weil der Browser es direkt auf der Grafikkarte berechnen kann – ganz im Gegensatz zu margin, left oder top, die ein vollständiges Neu-Layout der Seite auslösen. Animieren Sie wann immer möglich mit transform und opacity.
</note>
Gestaffelte Animationen mit CSS-Variablen
id="gestaffelt"
Mit einer CSS-Custom-Property lässt sich ein Staffeleffekt erzeugen, ohne für jede Kachel einen eigenen Delay im CSS zu schreiben:
/* CSS: Delay wird aus der CSS-Variable --reihenfolge berechnet */ .kachel { animation: einblenden 0.5s ease both; animation-delay: calc(var(--reihenfolge) * 150ms); }
<!-- HTML: Variable wird pro Element gesetzt --> <div class="kachel" style="--reihenfolge: 1;">Erste Kachel</div> <div class="kachel" style="--reihenfolge: 2;">Zweite Kachel</div> <div class="kachel" style="--reihenfolge: 3;">Dritte Kachel</div>
In Vue übergibt man den Wert dynamisch über :style:
<article :style="{ '--reihenfolge': eintrag.id }">
Das Ergebnis: Kachel 1 startet nach 150 ms, Kachel 2 nach 300 ms, Kachel 3 nach 450 ms – vollständig in CSS gerechnet, ohne JavaScript.
CSS Transitions vs. @keyframes
id="transitions_vs_keyframes"
| CSS Transition | CSS @keyframes Animation | |
|---|---|---|
| Auslöser | Benötigt einen Zustandswechsel (Klasse, Hover, Fokus …) | Läuft eigenständig, kein Auslöser nötig |
| Zustände | Von einem Zustand zum nächsten | Beliebig viele Schritte (0 % bis 100 %) |
| Schleifen | Nicht vorgesehen | infinite, alternate, beliebige Wiederholungen |
| Komplexität | Einfach, direkt auf dem Element | Getrennte @keyframes-Definition |
| Geeignet für | Hover-Effekte, Auf-/Zuklappen, Zustandswechsel in der UI | Ladeanimationen, Einblend-Effekte, Dekorationen |
Transition – Erinnerung
.panel { height: 0; opacity: 0; overflow: hidden; transition: all 300ms ease-in; } .panel.offen { height: auto; opacity: 1; }
Die Transition läuft automatisch, sobald die Klasse offen hinzugefügt oder entfernt wird. Kein @keyframes nötig.
CSS Nesting (nativ)
id="css_nesting"
Seit 2023 unterstützen alle modernen Browser natives CSS Nesting – ohne Präprozessor wie SCSS. Regeln können direkt ineinander verschachtelt werden:
/* Ohne Nesting – jede Regel separat */ .kachel { border-radius: 1rem; } .kachel img { width: 100%; } .kachel:hover { outline: 2px solid gold; } .kachel p { opacity: 0; } .kachel p.sichtbar { opacity: 1; }
/* Mit Nesting – alles in einem Block */ .kachel { border-radius: 1rem; img { width: 100%; /* kompiliert zu: .kachel img */ } &:hover { outline: 2px solid gold; /* kompiliert zu: .kachel:hover */ } p { opacity: 0; /* kompiliert zu: .kachel p */ &.sichtbar { opacity: 1; /* kompiliert zu: .kachel p.sichtbar */ } } }
Das & (Ampersand)
Das & verweist immer auf den übergeordneten Selektor:
| Verschachtelung | Kompiliert zu |
|---|---|
.kachel { img { } } | .kachel img |
.kachel { &:hover { } } | .kachel:hover |
.kachel { &.aktiv { } } | .kachel.aktiv |
p { &.offen { } } | p.offen |
<note> Browserunterstützung: Chrome 112+, Firefox 117+, Safari 16.5+ (Stand 2025). Für ältere Browser ist ein Präprozessor wie SCSS nötig. </note>
height: auto animieren (interpolate-size)
id="height_auto"
CSS kann normalerweise nicht von einer fixen Höhe zu height: auto animieren, weil auto kein numerischer Wert ist. Mit einer einzigen Zeile in :root lässt sich das ändern:
:root { interpolate-size: allow-keywords; }
Danach funktioniert die Transition auf height: auto in modernen Browsern:
.beschreibung { height: 0; overflow: hidden; transition: height 300ms ease; } .beschreibung.offen { height: auto; /* jetzt animierbar! */ }
<note important>
interpolate-size: allow-keywords ist eine neue CSS-Eigenschaft (2024). Sie wird von Chrome 129+, Firefox 131+, Safari 18+ unterstützt. Für ältere Browser kann der gleiche Effekt mit max-height und einem grosszügigen Maximalwert annähernd erreicht werden – allerdings wirkt das Timing dann weniger präzise.
</note>
Scroll-gesteuerte Animationen
id="scroll"
Mit animation-timeline: view() wird der Fortschritt einer Animation nicht durch Zeit gesteuert, sondern durch die Position des Elements im Viewport. Kein JavaScript nötig.
@keyframes aufzoomen { 0%, 100% { transform: scale(0.7); opacity: 0.4; } 50% { transform: scale(1); opacity: 1; } } .kachel { animation: aufzoomen linear; animation-timeline: view(block); /* ↑ Achse: block = vertikal, inline = horizontal */ }
0 %= Kachel tritt unten in den Viewport ein50 %= Kachel ist vollständig sichtbar100 %= Kachel verlässt den Viewport oben
Häufige Fehlerquellen
animation-timeline: view() funktioniert nicht, wenn ein übergeordnetes Element einen neuen Scroll-Container erstellt:
| Problem | Lösung |
|---|---|
overflow: hidden auf einem Elternelement | overflow: clip verwenden |
overflow-x: hidden auf <main> | overflow-x: clip verwenden |
height: 100% auf html, body | min-height: 100% verwenden |
overflow: clip vs. overflow: hidden
id="overflow_clip"
overflow: hidden | overflow: clip |
|
|---|---|---|
| Visuelles Ergebnis | Inhalt wird abgeschnitten | Inhalt wird abgeschnitten |
| Scroll-Container | Ja – erstellt einen neuen Scroll-Container | Nein – kein neuer Scroll-Container |
| animation-timeline: view() | Unterbricht scroll-gesteuerte Animationen | Funktioniert korrekt |
| Scrollbar | Kann Scrollbar erzeugen (wenn auto) | Keine Scrollbar möglich |
| Browserunterstützung | Alle Browser | Chrome 90+, Firefox 102+, Safari 16+ |
Faustregel: Wenn Sie Inhalte nur visuell abschneiden möchten (z. B. überstehende Dekorationselemente), verwenden Sie overflow: clip. Nur wenn Sie tatsächlich einen scrollbaren Bereich erstellen möchten, verwenden Sie overflow: hidden oder overflow: auto.
UX-Richtlinien für Animationen
id="ux"
Animationen sollten die User Experience verbessern – nicht ablenken. Die Norman Group (UX-Forschungsinstitut) empfiehlt:
<note tip> Norman Group: „Wenn UI-Animationen subtil, unauffällig und kurz sind, können sie die Benutzererfahrung verbessern, Feedback und Zustandsänderungen kommunizieren, Desorientierung vermeiden und Signifikanten stärken.„ </note>
Empfohlene Animationsdauern
| Interaktion | Empfohlene Dauer |
|---|---|
| Kleine Interaktionen (Toggle, Button-Feedback) | 100 ms |
| Mittlere Interaktionen (Panels, Chips, Dropdowns) | 200–300 ms |
| Grosse Übergänge (Dialog öffnen, Seiten-Transition) | 300 ms |
| Schliessen / Ausblenden (kürzer als Öffnen!) | 200–250 ms |
Wahrnehmung nach Dauer:
| Dauer | Wahrnehmung |
|---|---|
| 0 ms | Sofort (wird nicht als Animation wahrgenommen) |
| 100 ms | Unmittelbar |
| 200 ms | Schnell |
| 300 ms | Normal |
| 400 ms | Langsam |
Easing-Empfehlungen
| Easing | Wann einsetzen |
|---|---|
ease (Standard) | Allgemeine UI-Elemente |
ease-out (dezeleriert) | Entry-Effekte – das Element verlangsamt sich beim Ankommen |
ease-in (akzeleriert) | Exit-Effekte – das Element beschleunigt beim Verschwinden |
linear | Nur für Loops (Ladeanimationen, kontinuierliche Rotation) – wirkt sonst unnatürlich |
<note> Material Design Motion Guidelines: „Übergänge, die ein Element schliessen, entlassen oder zusammenfalten, verwenden kürzere Dauern.“ → Dialog einblenden: 300 ms / ausblenden: 250 ms. </note>
Reduzierte Bewegung (Barrierefreiheit)
Manche Nutzer reagieren empfindlich auf Bewegung (Vestibularis-Störungen, Epilepsie). Das Betriebssystem bietet eine „Bewegung reduzieren„-Einstellung – CSS kann darauf reagieren:
@keyframes einblenden { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } } .kachel { animation: einblenden 0.6s ease both; } /* Animationen für Nutzer mit reduzierter Bewegung deaktivieren */ @media (prefers-reduced-motion: reduce) { .kachel { animation: none; } }
Weiterführende Informationen
id="weiterfuehrend"
Referenzen
Video: Web Animations Today and Tomorrow
Web animations today and tomorrow – Chrome for Developers / Google I/O 2025
Sprecher: Bramus Van Damme | Dauer: bis 14:12 min (danach fortgeschrittene Themen)
Themen im Video:
@starting-stylefür Entry-Animationeninterpolate-size: allow-keywords(height: auto animieren)- Scroll-gesteuerte Animationen mit
animation-timeline - View Transitions API
- UX-Richtlinien für Animationsdauern (Norman Group, Material Design)
(Seite erstellt für LU13 – M291 Web Frontend · BZZ)
