Scroll-Timeline fortgeschritten: Named Timelines, View-Timeline und animation-range
AI generated
{ }
@
CSS · Scroll-Timeline · View-Timeline · Animation
Scroll-Timeline fortgeschritten
Named Timelines, View-Timeline und animation-range im Detail

Ein einfaches Fade-in beim Scrollen kennt inzwischen fast jedes Projekt. Wirklich interessant wird Scroll-Timeline aber erst, wenn mehrere Achsen, benannte Timelines und präzise animation-range-Werte zusammenspielen, um komplexe Erzähl-Layouts ganz ohne Scroll-Event-Listener zu bauen.

18 Min. Lesezeit scroll-timeline-name · view-timeline · animation-range · timeline-scope Chrome 115+ · progressive Enhancement

1. Warum Named Scroll-Timelines fortgeschrittene Kontrolle brauchen

Die einfachste Form einer Scroll-Timeline koppelt eine Animation direkt an den Scroll-Fortschritt des nächsten scrollenden Vorfahren: animation-timeline: scroll();. Für ein Fortschritts-Balken oder ein einfaches Parallax-Element reicht das völlig aus. Sobald aber mehrere unabhängige Scroll-Container auf einer Seite existieren, etwa ein horizontal scrollender Karussell-Bereich neben dem vertikalen Hauptdokument, wird die anonyme Timeline mehrdeutig: welches animierte Element soll sich auf welchen Container beziehen?

Genau hier setzen benannte Scroll-Timelines an. Mit scroll-timeline-name wird einem beliebigen scrollenden Element ein eindeutiger Bezeichner gegeben, der dann von jedem beliebigen anderen Element im Dokument über animation-timeline: --mein-name; referenziert werden kann, unabhängig von der DOM-Position. Diese Entkopplung von Quelle und Ziel ist der entscheidende Unterschied zwischen einem simplen Scroll-Effekt und einer wirklich fortgeschrittenen Scroll-Timeline-Architektur.

Ein praktisches Beispiel: ein Fortschrittsbalken am oberen Bildschirmrand soll den Lesefortschritt eines Artikelbereichs anzeigen, der selbst nicht scrollt, sondern in einem Container weiter unten liegt. Ohne benannte Timeline müsste der Balken ein Kind des scrollenden Containers sein. Mit scroll-timeline-name kann der Balken irgendwo im Dokument stehen und trotzdem exakt an den Scroll-Fortschritt des Containers gekoppelt werden.

2. scroll-timeline-name und scroll-timeline-axis im Detail

Die Kurzform scroll-timeline: --progress block; setzt in einem Schritt Name und Achse. scroll-timeline-axis bestimmt dabei, ob die Timeline dem Fortschritt entlang der Block-Achse (meist vertikal) oder der Inline-Achse (meist horizontal) folgt. Für horizontal scrollende Karussells oder Storytelling-Sektionen mit seitlichem Scroll ist inline die richtige Wahl, für den überwiegenden Teil klassischer Seiten block.

Wichtig für fortgeschrittene Scroll-Timeline-Setups: der Name selbst ist ein Custom-Ident, beginnt also mit zwei Bindestrichen, genau wie eine CSS-Custom-Property. Mehrere Elemente im Dokument können denselben Namen nutzen, ohne dass es zu einem Konflikt kommt, solange jedes referenzierende Element eindeutig weiß, welche Timeline gemeint ist. In der Praxis empfiehlt sich dennoch ein sprechendes, eindeutiges Namensschema pro Sektion, etwa --hero-scroll oder --gallery-scroll, um Verwechslungen in größeren Stylesheets zu vermeiden.


/* Scrolling container defines the named timeline */
.gallery-track {
  overflow-x: auto;
  scroll-timeline: --gallery-scroll inline;
}

/* Any element in the document can subscribe to it */
.gallery-progress-bar {
  animation: fill-bar linear;
  animation-timeline: --gallery-scroll;
  animation-range: 0% 100%;
}

@keyframes fill-bar {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

Ein häufiger Fehler bei der Migration von anonymen zu benannten Scroll-Timelines: das Attribut scroll-timeline-axis ohne overflow auf demselben Element zu setzen. Die Timeline benötigt zwingend einen tatsächlich scrollenden Container, ein Element ohne overflow: auto oder overflow: scroll erzeugt keine gültige Scroll-Timeline, selbst wenn Name und Achse korrekt deklariert sind.

3. View-Timeline für Element-Sichtbarkeit nutzen

Während scroll-timeline den Fortschritt eines Containers misst, misst view-timeline den Sichtbarkeitsfortschritt eines einzelnen Elements innerhalb seines nächsten scrollenden Vorfahren. Das Element selbst wird zur Quelle der Timeline: sobald es in den sichtbaren Bereich eintritt, beginnt die Timeline bei 0 Prozent, verlässt es den sichtbaren Bereich vollständig, endet sie bei 100 Prozent. Das ist exakt das Muster, das man für Reveal-Animationen, Sticky-Highlight-Effekte oder Scrollytelling-Sektionen braucht.

Die Kurzform view-timeline: --card-reveal block; auf dem zu beobachtenden Element aktiviert diese Sichtbarkeits-Timeline direkt. Kombiniert mit view-timeline-inset lässt sich der Sichtbarkeitsbereich zusätzlich verschieben, etwa um eine Animation erst auszulösen, wenn ein Element schon ein Stück im Viewport steht, statt sofort an dessen Rand.


.story-card {
  view-timeline: --card-reveal block;
  view-timeline-inset: 10% 0%;
}

.story-card {
  animation: reveal-card linear both;
  animation-timeline: --card-reveal;
  animation-range: entry 0% cover 40%;
}

@keyframes reveal-card {
  from { opacity: 0; transform: translateY(48px) scale(0.94); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

Der entscheidende Unterschied zu einem einfachen Fade-in-Skript mit IntersectionObserver: view-timeline ist voll scrubbing-fähig. Der Fortschritt der Animation folgt exakt dem Scroll-Fortschritt, in beide Richtungen, ohne dass eine JavaScript-Callback-Kette zwischengeschaltet wäre. Scrollt der Nutzer schnell, folgt die Animation genauso schnell, scrollt er zurück, läuft die Animation rückwärts, alles allein durch den Compositor-Thread des Browsers gesteuert.

4. animation-range: Start und Ende präzise setzen

animation-range ist der Baustein, der aus einer groben Sichtbarkeits-Timeline eine präzise choreografierte Scroll-Timeline-Animation macht. Statt der gesamten Sichtbarkeitsdauer eines Elements lässt sich exakt festlegen, in welchem Ausschnitt der Timeline eine Animation läuft. Die benannten Bereiche entry, exit, cover und contain beschreiben unterschiedliche Phasen des Sichtbarkeitsverlaufs und lassen sich mit Prozentwerten kombinieren.

entry 0% entry 100% etwa beschreibt exakt die Phase, in der das Element von komplett unsichtbar zu komplett sichtbar wird, während cover 0% cover 100% die gesamte Zeitspanne beschreibt, in der irgendein Teil des Elements sichtbar ist. Diese Bereiche lassen sich beliebig mischen: animation-range: entry 20% cover 60%; startet die Animation, wenn das Element zu 20 Prozent in die Entry-Phase eingetreten ist, und beendet sie, wenn 60 Prozent der Cover-Phase erreicht sind.


/* Precise choreography: fade during entry, hold, then fade during exit */
.section-heading {
  view-timeline: --heading-view block;
  animation: heading-choreography linear both;
  animation-timeline: --heading-view;
  animation-range: entry 0% exit 100%;
}

@keyframes heading-choreography {
  0%   { opacity: 0; filter: blur(6px); }
  20%  { opacity: 1; filter: blur(0); }
  80%  { opacity: 1; filter: blur(0); }
  100% { opacity: 0; filter: blur(6px); }
}

Der Vorteil dieser präzisen animation-range-Steuerung gegenüber einem groben Alles-oder-nichts-Fade: eine Sektion kann während des gesamten sichtbaren Zeitraums stabil bleiben und nur an den Übergängen animieren, was für Textabschnitte deutlich ruhiger wirkt als ein Effekt, der über die komplette Sichtbarkeitsdauer läuft. Wer Scroll-Timeline-Effekte produktionsreif einsetzen will, kommt an dieser Feinjustierung nicht vorbei.

5. Mehrere Timelines kombinieren: Parallax mit mehreren Achsen

Klassisches Parallax verschiebt Ebenen mit unterschiedlicher Geschwindigkeit relativ zum Scroll-Fortschritt. Mit mehreren gleichzeitig aktiven Scroll-Timelines lässt sich dieser Effekt vollständig ohne JavaScript umsetzen, indem jede Ebene eine eigene animation-timeline mit unterschiedlichem animation-range oder unterschiedlicher Keyframe-Distanz erhält. Die Hintergrundebene bewegt sich über die gesamte Scroll-Range um wenige Prozent, die Vordergrundebene über dieselbe Range um ein Vielfaches mehr.

Für echte Mehrachsen-Effekte, bei denen eine Ebene sich gleichzeitig vertikal verschiebt und horizontal rotiert, lassen sich sogar zwei unabhängige Animationen auf demselben Element an dieselbe Timeline koppeln, jede mit eigenem animation-range. Das Ergebnis ist ein choreografierter Effekt, der auf den ersten Blick nach komplexem JavaScript aussieht, tatsächlich aber vollständig deklarativ im Stylesheet steht.


.parallax-section {
  scroll-timeline: --parallax-scroll block;
}

.parallax-bg {
  animation: shift-bg linear both;
  animation-timeline: --parallax-scroll;
  animation-range: 0% 100%;
}
.parallax-mid {
  animation: shift-mid linear both;
  animation-timeline: --parallax-scroll;
  animation-range: 0% 100%;
}
.parallax-fg {
  animation: shift-fg linear both, rotate-fg linear both;
  animation-timeline: --parallax-scroll, --parallax-scroll;
  animation-range: 0% 100%, 10% 90%;
}

@keyframes shift-bg { to { transform: translateY(6%); } }
@keyframes shift-mid { to { transform: translateY(18%); } }
@keyframes shift-fg  { to { transform: translateY(40%); } }
@keyframes rotate-fg { to { transform: rotate(4deg); } }

Der Performance-Vorteil ist dabei nicht zu unterschätzen: alle drei Ebenen laufen auf dem Compositor-Thread, ohne dass der Main-Thread bei jedem Scroll-Frame neu berechnen müsste. Ein klassisches JavaScript-Parallax mit scroll-Event-Listenern verursacht dagegen bei jedem einzelnen Scroll-Frame einen Layout-Thrash-Kandidaten, sobald getBoundingClientRect() im Handler aufgerufen wird.

6. timeline-scope für Cross-Element-Steuerung

Standardmäßig ist eine benannte Scroll-Timeline oder view-timeline nur innerhalb ihres eigenen Subtrees sichtbar, also für Nachfahren des Elements, das sie deklariert. Für Fälle, in denen ein Element außerhalb dieses Subtrees auf die Timeline reagieren soll, etwa ein Fortschrittsindikator im Header, der auf ein view-timeline eines Elements weit unten im Dokument reagiert, gibt es timeline-scope.

Deklariert auf einem gemeinsamen Vorfahren, etwa :root oder einem Layout-Wrapper, erweitert timeline-scope die Sichtbarkeit einer benannten Timeline auf den gesamten Scope, unabhängig von der tatsächlichen DOM-Verschachtelung. Das macht komplexe Scrollytelling-Layouts erst möglich, bei denen Steuerelemente und animierte Ziele an völlig unterschiedlichen Stellen im Dokument liegen.


:root {
  timeline-scope: --hero-view;
}

.hero-section {
  view-timeline: --hero-view block;
}

/* Header lives outside .hero-section in the DOM, but can still react */
.site-header .scroll-indicator {
  animation: shrink-indicator linear both;
  animation-timeline: --hero-view;
  animation-range: 0% 100%;
}

7. Fallback mit @supports und IntersectionObserver

Scroll-Timelines sind in der Support-Matrix aktuell weniger verbreitet als grundlegende CSS-Animationen. Für Projekte, die auf breitere Browser-Unterstützung angewiesen sind, empfiehlt sich eine klare Trennung über @supports (animation-timeline: view());. Innerhalb dieses Blocks stehen alle Scroll-Timeline-Deklarationen, außerhalb greift ein einfacher IntersectionObserver, der dieselbe CSS-Klasse toggelt, aber ohne Scrubbing-Fähigkeit.

Wichtig ist, dass beide Codepfade dasselbe visuelle Grundgerüst teilen, damit kein Bruch im Erscheinungsbild entsteht. In der Praxis bedeutet das: Start- und Endzustand der Animation werden als reguläre CSS-Klassen definiert, und sowohl die Scroll-Timeline-Variante als auch der IntersectionObserver-Fallback schalten lediglich zwischen diesen Klassen um, statt komplett unterschiedliche Animationslogik zu pflegen.


// Fallback only runs when native scroll-driven animations are unsupported
if (!CSS.supports('animation-timeline: view()')) {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      entry.target.classList.toggle('is-revealed', entry.isIntersecting);
    });
  }, { threshold: 0.4 });

  document.querySelectorAll('.story-card').forEach((card) => {
    observer.observe(card);
  });
}

8. Debugging von Scroll-Timelines in den DevTools

Fehlerhafte Scroll-Timeline-Setups zeigen sich meist auf eine bestimmte Art: die Animation läuft überhaupt nicht, oder sie läuft nur einmal statt scrubbing-fähig zu bleiben. Die häufigste Ursache ist ein fehlender overflow-Wert auf dem Timeline-Quellelement, gefolgt von einem Tippfehler im Custom-Ident-Namen zwischen Quelle und Ziel. Chromium-basierte DevTools zeigen im Element-Panel unter "Animations" aktive Scroll-Timelines mit ihrem aktuellen Fortschritt an, inklusive eines visuellen Scrubbers.

Ein zweiter typischer Fehler betrifft Timing-Funktionen: eine Scroll-Timeline-Animation mit ease-in-out statt linear wirkt bei genauem Hinsehen ungleichmäßig, weil die Easing-Kurve für Zeit-basierte Animationen gedacht ist, nicht für Scroll-Fortschritt-basierte. Für die meisten Scroll-Timeline-Fälle ist linear die richtige Timing-Funktion, die eigentliche Beschleunigung oder Verzögerung entsteht über die Keyframe-Verteilung selbst, nicht über die Easing-Funktion.

9. Scroll-Timeline-Patterns im Vergleich

Für die Wahl der richtigen Technik lohnt sich ein direkter Vergleich der gängigen Ansätze für scroll-gekoppelte Animationen, von der einfachen anonymen Timeline bis zum vollständig choreografierten Multi-Timeline-Setup.

Pattern Kontrolle JavaScript nötig Einsatzbereich
Anonyme scroll()-Timeline Gering Nein Einfacher Fortschrittsbalken
Named scroll-timeline Mittel Nein Element außerhalb des Containers ansteuern
view-timeline + animation-range Hoch Nein Präzise choreografierte Reveal-Effekte
timeline-scope Hoch Nein Cross-Element-Scrollytelling
IntersectionObserver Gering, kein Scrubbing Ja Fallback für ältere Browser

Für neue Projekte, die moderne Browser priorisieren können, ist view-timeline mit präzisem animation-range der klare Favorit: maximale Kontrolle, keine Laufzeitkosten für den Main-Thread, keine zusätzliche JavaScript-Abhängigkeit. Nur wenn breite Legacy-Unterstützung Pflicht ist, bleibt IntersectionObserver als robuster, aber weniger flüssiger Fallback relevant.

Mironsoft

Scrollytelling, Parallax und performante Animationen für moderne Frontends

Scroll-Effekte, die ohne JavaScript flüssig laufen?

Wir bauen präzise choreografierte Scroll-Timeline-Animationen mit view-timeline und animation-range, inklusive Fallback-Strategie für ältere Browser und vollständigem Performance-Audit.

Konzeption

Scrollytelling-Layouts planen und Timeline-Struktur entwerfen

Umsetzung

Named Timelines, view-timeline und präzises animation-range

Qualitätssicherung

Fallback-Tests, Compositor-Performance und Debugging-Setup

10. Zusammenfassung

Fortgeschrittene Scroll-Timeline-Technik geht deutlich über ein einzelnes Fade-in beim Scrollen hinaus. scroll-timeline-name entkoppelt Quelle und Ziel einer Timeline, view-timeline koppelt eine Animation an die Sichtbarkeit eines Elements statt an einen Container, und animation-range mit den Werten entry, exit, cover und contain erlaubt eine präzise Choreografie einzelner Animationsphasen.

Mehrere gleichzeitig aktive Timelines ermöglichen vollständig deklarative Parallax-Effekte mit unterschiedlichen Geschwindigkeiten pro Ebene, timeline-scope löst das Problem von Steuerelementen außerhalb des eigenen Subtrees. Da all diese Effekte auf dem Compositor-Thread laufen, bleibt die Scroll-Performance auch bei komplexen Setups stabil, ganz ohne scroll-Event-Listener und ohne die damit verbundenen Main-Thread-Kosten. Ein @supports-Fallback mit IntersectionObserver sichert die Funktion auf Browsern ohne Unterstützung ab.

Scroll-Timeline fortgeschritten — Das Wichtigste auf einen Blick

Named Timelines

scroll-timeline-name entkoppelt Quelle und animiertes Ziel, unabhängig von der DOM-Position.

View-Timeline

view-timeline koppelt an die Sichtbarkeit eines Elements, ideal für Reveal-Effekte und Scrollytelling.

Präzises animation-range

entry, exit, cover, contain erlauben feine Choreografie statt Alles-oder-nichts-Fades.

Performance

Compositor-Thread statt Scroll-Event-Listener. Kein Layout-Thrash, kein Main-Thread-Overhead.

11. FAQ: Scroll-Timeline fortgeschritten

1Unterschied scroll-timeline vs. view-timeline?
scroll-timeline misst den Container-Fortschritt, view-timeline die Sichtbarkeit eines einzelnen Elements.
2Wozu dient scroll-timeline-name?
Gibt der Timeline einen eindeutigen Namen, sodass beliebige Elemente darauf referenzieren können, unabhängig von der DOM-Position.
3entry, exit, cover, contain?
Unterschiedliche Sichtbarkeitsphasen: entry beim Eintreten, exit beim Verlassen, cover für sichtbare Teile, contain wenn alles sichtbar ist.
4Meine Timeline funktioniert nicht?
Meist fehlt overflow auf dem Quellelement, oder der Name stimmt zwischen Quelle und Ziel nicht überein.
5Welche Timing-Funktion nutzen?
Fast immer linear. Easing-Kurven sind für Zeit gedacht, nicht für scroll-basierten Fortschritt.
6Parallax ohne JavaScript?
Mehrere Ebenen an dieselbe Timeline koppeln, jede mit eigenem Keyframe-Abstand oder animation-range.
7Wofür timeline-scope?
Damit ein Element außerhalb des Subtrees der Timeline-Quelle trotzdem darauf reagieren kann.
8Fallback für ältere Browser?
CSS.supports('animation-timeline: view()') prüfen, sonst IntersectionObserver einsetzen, der dieselben Klassen toggelt.
9Debugging im Browser?
DevTools zeigen im Element-Panel unter Animations aktive Timelines mit Fortschritt an. Fehlendes overflow ist die häufigste Ursache.
10Ist view-timeline scrubbing-fähig?
Ja, vollständig, in beide Scroll-Richtungen, ganz ohne JavaScript-Callback-Kette.