de:modul:m291:learningunits:lu13:theorie:b_general_animations

Dies ist eine alte Version des Dokuments!


LU13: Keyframe-Animationen & Scroll-Animationen

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.

Pac-Man Animation

Eine CSS-Animation besteht aus genau zwei Teilen:

  1. Die Definition der Animation mit @keyframes (Name + Ablauf)
  2. 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 einblenden {
    from {
        opacity: 0;
        transform: translateY(20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}
  1. Die @keyframes-Regel leitet die Animationsdefinition ein.
  2. Danach folgt ein frei wählbarer Name – er wird gleich gebraucht, um die Animation zuzuweisen.
  3. from (entspricht 0%) ist der erste Frame, to (entspricht 100%) der letzte.
  4. Im Keyframe stehen CSS-Eigenschaften, deren Wert sich interpolieren lässt: Grösse, Position, Farbe, opacity, margin, border-radius und viele mehr. Eigenschaften wie display oder background-image kö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>


.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

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 können in Sekunden (s) oder Millisekunden (ms) angegeben werden:

animation-duration: 1s;      /* 1 Sekunde */
animation-duration: 300ms;   /* 300 Millisekunden = 0.3 Sekunden */

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.


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);

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);

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>


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 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
.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.


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 & 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>


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>


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 ein
  • 50 % = Kachel ist vollständig sichtbar
  • 100 % = Kachel verlässt den Viewport oben

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: 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.


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>

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 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>

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;
    }
}

youtube>UcXWY057YuQ

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-style für Entry-Animationen
  • interpolate-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)

  • de/modul/m291/learningunits/lu13/theorie/b_general_animations.1780260830.txt.gz
  • Zuletzt geändert: 2026/05/31 22:53
  • von gkoch