animation-timeline, scroll(), view() und Parallax ohne JS
Scroll-Animationen, Parallax-Effekte und Reveal-Übergänge wurden jahrelang mit JavaScript-Bibliotheken umgesetzt. CSS Scroll-Driven Animations machen das obsolet: animation-timeline, scroll() und view() ermöglichen performante, deklarative Scroll-Animationen direkt im Stylesheet — auf dem Compositor-Thread, ohne Layout-Thrashing.
Inhaltsverzeichnis
- 1. Warum Scroll-Animationen in CSS gehören
- 2. animation-timeline — das neue Herzstück
- 3. scroll() — Scroll-Fortschritt als Timeline
- 4. view() — Sichtbarkeit als Animations-Trigger
- 5. ScrollTimeline und ViewTimeline in JS
- 6. Parallax-Effekte ohne JavaScript
- 7. Reveal-Animationen mit view()
- 8. Scroll-Driven Animations im Vergleich
- 9. Performance, Barrierefreiheit und Browser-Support
- 10. Zusammenfassung
- 11. FAQ
1. Warum Scroll-Animationen in CSS gehören
Scroll-basierte Animationen haben im Web lange als Domäne von JavaScript-Bibliotheken gegolten: GSAP ScrollTrigger, Intersection Observer, requestAnimationFrame-Loops — alles JavaScript, alles auf dem Haupt-Thread. Das Problem dabei ist nicht nur die Abhängigkeit, sondern vor allem die Performance: JavaScript-gesteuerte Animationen können, wenn sie Layout-Eigenschaften lesen oder setzen, Reflow auslösen und den Haupt-Thread blockieren. Das Ergebnis sind ruckelnde Animationen, die in Performance-Audits auffallen. CSS Scroll-Driven Animations setzen direkt auf dem Compositor-Thread an und umgehen dieses Problem grundlegend.
Die Spezifikation wurde als Teil von CSS Animations Level 2 eingeführt und ist eng mit der Web Animations API verknüpft. Das Kernkonzept: Eine CSS-Animation bekommt als animation-timeline statt der standardmäßigen zeitbasierten Timeline eine Scroll-Timeline. Die Animation läuft dann nicht mit der Zeit voran, sondern mit dem Scroll-Fortschritt. CSS Scroll-Driven Animations sind damit keine neuen Animationstypen, sondern eine Erweiterung des bestehenden Animations-Modells um scroll-basierte Zeitachsen.
2. animation-timeline — das neue Herzstück
Die CSS-Eigenschaft animation-timeline ist das zentrale neue Konzept in CSS Scroll-Driven Animations. Sie ersetzt oder ergänzt das Standard-Verhalten, wonach Animationen zeitlich voranschreiten. Mit animation-timeline: scroll() oder animation-timeline: view() wird die Timeline an einen Scroll-Container beziehungsweise an die Sichtbarkeit eines Elements gebunden. Die Eigenschaft akzeptiert drei Arten von Werten: die Funktion scroll(), die Funktion view(), oder den Namen einer benannten Timeline, die mit scroll-timeline-name oder view-timeline-name definiert wurde.
Wichtig für das korrekte Verständnis: animation-timeline ändert nicht, was animiert wird — das bestimmt weiterhin @keyframes. Es ändert, wie die Animation zeitlich fortschreitet. Ein Fortschrittswert von 0% entspricht dem Beginn des Scrollens (oder dem Eintreten ins Viewport), 100% dem Ende. Alle Keyframe-Positionen beziehen sich auf diesen Fortschrittswert. Damit lassen sich mit bekannten CSS-Keyframe-Techniken plötzlich ganz neue Effekte realisieren, die früher zwingend JavaScript erforderten.
/* Reading progress bar — scroll-driven, zero JavaScript */
@keyframes progress-grow {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
.reading-progress {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: linear-gradient(90deg, #7c3aed, #c4b5fd);
transform-origin: left center;
transform: scaleX(0);
/* Link animation to the document scroll position */
animation: progress-grow linear;
animation-timeline: scroll(root block);
/* root = <html> scroll container, block = vertical axis */
}
/* Fade-in element as page scrolls */
@keyframes fade-in-up {
from {
opacity: 0;
translate: 0 2rem;
}
to {
opacity: 1;
translate: 0 0;
}
}
.hero-title {
animation: fade-in-up linear;
animation-timeline: scroll(root);
animation-range: 0% 20%;
/* Only plays during the first 20% of page scroll */
}
3. scroll() — Scroll-Fortschritt als Timeline
Die scroll()-Funktion erzeugt eine anonyme CSS Scroll-Driven Animation-Timeline, die an den Scroll-Fortschritt eines bestimmten Scroll-Containers gekoppelt ist. Sie nimmt zwei optionale Parameter: den Scroll-Container und die Scroll-Achse. Der Container-Parameter kann nearest (nächster Scroll-Ancestor), root (das Dokument selbst) oder self (das Element selbst) sein. Die Achse kann block (typischerweise vertikal), inline (horizontal) oder x/y sein.
Der Fortschrittswert der scroll()-Timeline läuft von 0% — wenn der Scroll-Container ganz oben steht — bis 100%, wenn er ganz unten steht. Die Animation reagiert linear auf den Scroll-Fortschritt, es sei denn, animation-timing-function transformiert den Fortschritt. In Kombination mit animation-range lässt sich genau steuern, in welchem Scroll-Bereich die Animation aktiv ist. Das ermöglicht Effekte, die nur in einem bestimmten Seitenabschnitt ablaufen — ein Kernmerkmal gut gestalteter CSS Scroll-Driven Animations.
/* Horizontal gallery scrolled with scroll() on inline axis */
.gallery-track {
display: flex;
overflow-x: scroll;
scroll-snap-type: x mandatory;
/* Named scroll timeline for the track */
scroll-timeline-name: --gallery;
scroll-timeline-axis: inline;
}
/* Counter shows how far through the gallery we are */
.gallery-counter {
animation: count-progress linear;
animation-timeline: --gallery;
}
@keyframes count-progress {
from { --progress: 0; }
to { --progress: 100; }
}
/* Sticky header shrinks as user scrolls down */
@keyframes shrink-header {
from {
padding-block: 1.5rem;
font-size: 1.125rem;
background: rgba(255, 255, 255, 0);
}
to {
padding-block: 0.75rem;
font-size: 0.875rem;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(12px);
box-shadow: 0 1px 8px rgba(0,0,0,0.1);
}
}
.site-header {
position: sticky;
top: 0;
animation: shrink-header linear both;
animation-timeline: scroll(root block);
animation-range: 0 200px; /* Active during first 200px of scroll */
}
4. view() — Sichtbarkeit als Animations-Trigger
Die view()-Funktion ist die zweite große Säule von CSS Scroll-Driven Animations. Während scroll() an den Gesamt-Fortschritt eines Scroll-Containers gekoppelt ist, bindet view() die Animation an die Sichtbarkeit des animierten Elements selbst im Viewport. Die Timeline beginnt, wenn das Element in den Viewport eintritt, und endet, wenn es ihn verlässt. Der 0%-Punkt markiert den Moment des Eintretens, der 100%-Punkt das vollständige Verlassen.
Mit dem animation-range-Property lässt sich exakt steuern, in welchem Sichtbarkeitsbereich die Animation aktiv ist. Die Werte können absolute Längenangaben oder Prozentwerte der Scrollportgröße sein. Besonders nützlich sind die Named Range Values: entry (Eintreten ins Viewport), exit (Verlassen des Viewports), contain (Element vollständig sichtbar) und cover (Element überlappt den Viewport vollständig). Diese semantischen Bereiche machen es einfach, Reveal-Animationen zu bauen, die genau dann abspielen, wenn das Element ins Bild kommt — ein häufiges Designmuster in modernen CSS Scroll-Driven Animations-Implementierungen.
5. ScrollTimeline und ViewTimeline in JavaScript
Die JavaScript-Pendants zu scroll() und view() sind ScrollTimeline und ViewTimeline aus der Web Animations API. Sie ermöglichen dieselben Effekte programmatisch — nützlich, wenn Animationen dynamisch erstellt oder an DOM-Elemente gebunden werden, die zu Stylesheet-Zeit noch nicht bekannt sind. new ScrollTimeline({ source: scrollContainer, axis: 'block' }) erzeugt eine Timeline, die an den Scroll-Fortschritt des angegebenen Containers gebunden ist. Diese Timeline kann dann an eine Element.animate()-Animation übergeben werden.
ViewTimeline nimmt als Parameter subject (das zu beobachtende Element) und axis. Die Kombination beider APIs erlaubt hybride Implementierungen: Die Animation-Logik bleibt in CSS (@keyframes und animation-timeline mit benannten Timelines), während JavaScript nur die Timeline-Zuordnung übernimmt. Das ist sinnvoll für Frameworks und Komponenten-Bibliotheken, die CSS Scroll-Driven Animations dynamisch zuweisen müssen, ohne den CSS zu kennen.
/* Named view timeline — reusable across multiple elements */
.reveal-item {
/* Each element is its own subject */
view-timeline-name: --reveal;
view-timeline-axis: block;
animation: slide-in linear both;
animation-timeline: --reveal;
animation-range: entry 0% entry 50%;
/* Plays while element enters the viewport (0% to 50% of entry) */
}
@keyframes slide-in {
from {
opacity: 0;
translate: 0 3rem;
filter: blur(4px);
}
to {
opacity: 1;
translate: 0 0;
filter: blur(0);
}
}
/* Stagger delay using animation-range offset */
.reveal-item:nth-child(2) { animation-range: entry 5% entry 55%; }
.reveal-item:nth-child(3) { animation-range: entry 10% entry 60%; }
.reveal-item:nth-child(4) { animation-range: entry 15% entry 65%; }
/* Exit animation — element fades out as it leaves viewport */
.fade-exit {
view-timeline-name: --exit;
animation: fade-out linear both;
animation-timeline: --exit;
animation-range: exit 0% exit 100%;
}
@keyframes fade-out {
to { opacity: 0; translate: 0 -2rem; }
}
6. Parallax-Effekte ohne JavaScript
Parallax-Scrolling — das schnellere oder langsamere Scrollen verschiedener Ebenen — war eine der aufwändigsten Scroll-Animationen, die man mit JavaScript implementieren musste. Mit CSS Scroll-Driven Animations ist das überraschend einfach. Das Grundprinzip: Ein Element bekommt eine scroll()-Timeline und bewegt sich über transform: translateY() mit einem anderen Tempo als das normale Scrollen. Da der Animations-Fortschritt linear mit dem Scroll-Fortschritt verbunden ist, entsteht durch unterschiedliche Keyframe-Werte automatisch der Parallax-Effekt.
Für Performance ist entscheidend: Nur CSS-Eigenschaften verwenden, die der Browser auf dem Compositor-Thread animieren kann — allen voran transform und opacity. Wer top, left, margin oder height animiert, zwingt den Browser zu Reflow und verliert den Performance-Vorteil von CSS Scroll-Driven Animations. Das gilt ebenso für Animations mit JavaScript-ScrollTimeline. Die CSS-Eigenschaft will-change: transform signalisiert dem Browser, das Element auf einer separaten Compositor-Ebene zu halten und beschleunigt die Animation weiter.
7. Reveal-Animationen mit view()
Reveal-Animationen — Elemente, die beim Scrollen eingeblendet werden — sind eines der häufigsten Einsatzgebiete für CSS Scroll-Driven Animations. Früher benötigte man dafür den Intersection Observer API, JavaScript-Callbacks und das Hinzufügen von CSS-Klassen. Mit view() und animation-range: entry lässt sich das komplett in CSS ausdrücken. Jedes Element, das die Klasse .reveal trägt, animiert sich automatisch beim Eintreten in den Viewport — ohne JavaScript, ohne ResizeObserver, ohne MutationObserver.
Für barrierefreie Implementierungen ist @media (prefers-reduced-motion: reduce) essenziell. Nutzerinnen und Nutzer, die Bewegungsreduzierung aktiviert haben, erwarten keine animierten Übergänge. Die Empfehlung lautet: Reveal-Animationen komplett deaktivieren oder durch einfache opacity-Übergänge ersetzen, wenn prefers-reduced-motion: reduce gesetzt ist. Das ist sowohl barrierefreundlich als auch technisch einfach — eine einzige Media Query am Ende des Stylesheets reicht, um alle CSS Scroll-Driven Animations zu deaktivieren.
8. Scroll-Driven Animations im Vergleich
Die Wahl zwischen nativen CSS Scroll-Driven Animations und JavaScript-Lösungen hängt von Komplexität, Browser-Support-Anforderungen und der Natur der Animation ab. Für Standard-Reveal-Animationen und Fortschrittsbalken sind native CSS-Lösungen klar überlegen. Für komplexe Sequenzen mit Abhängigkeiten zwischen mehreren Elementen bleibt JavaScript das mächtigere Werkzeug.
| Anwendungsfall | CSS scroll()/view() | Intersection Observer | GSAP ScrollTrigger |
|---|---|---|---|
| Reveal beim Eintreten | Ideal — view() + entry | Gut — mit JS-Klasse | Möglich — Overhead |
| Fortschrittsbalken | Perfekt — scroll(root) | Nicht geeignet | Möglich |
| Parallax-Ebenen | Gut — transform + scroll() | Nicht geeignet | Gut — mehr Kontrolle |
| Komplexe Sequenzen | Begrenzt | Begrenzt | Ideal |
| Performance | Compositor-Thread | Main Thread (JS) | Main Thread (JS) |
Ein oft übersehener Vorteil von CSS Scroll-Driven Animations gegenüber Intersection Observer: Die Animationen sind umkehrbar. Wenn ein Element rückwärts scrollt, kehrt die Animation zurück — ohne zusätzliche Logik. Intersection Observer feuert nur bei Zustandswechseln und erfordert explizite Logik für umgekehrte Animationen. Das macht CSS-Scroll-Animationen besonders elegant für bidirektionale Effekte wie Sticky-Header-Transformationen oder Parallax-Hintergründe.
9. Performance, Barrierefreiheit und Browser-Support
CSS Scroll-Driven Animations werden in Chrome und Safari auf dem Compositor-Thread ausgeführt, wenn ausschließlich compositor-fähige Eigenschaften animiert werden: transform, opacity, filter und clip-path. Alle anderen Eigenschaften — darunter Farben, Dimensionen, Abstände — erzwingen Hauptthread-Beteiligung. Das ist kein Nachteil gegenüber JavaScript, aber es bedeutet, dass der Performance-Vorteil von CSS Scroll-Driven Animations nur mit disziplinierter Eigenschaftswahl vollständig ausgeschöpft werden kann.
Browser-Support: Chrome 115+, Safari 18+, Firefox 110+ unterstützen die grundlegenden Features von CSS Scroll-Driven Animations. Der Support für einzelne Features wie animation-range mit Named Range Values variiert. Progressive Enhancement: Außerhalb von @supports (animation-timeline: scroll())-Blöcken bleiben Elemente in ihrem statischen Zustand sichtbar — sinnvoll, denn blinklose Inhalte sind besser als Inhalte, die für immer unsichtbar bleiben, weil die Animation nie stattfand.
/* Progressive Enhancement — full accessibility support */
/* Default: always visible, no animation */
.reveal-section {
opacity: 1;
translate: 0 0;
}
/* Enhancement: animate only when supported */
@supports (animation-timeline: view()) {
.reveal-section {
opacity: 0;
translate: 0 2.5rem;
animation: reveal-section linear both;
animation-timeline: view();
animation-range: entry 0% entry 60%;
}
}
@keyframes reveal-section {
to {
opacity: 1;
translate: 0 0;
}
}
/* Respect user preference — disable all scroll animations */
@media (prefers-reduced-motion: reduce) {
.reveal-section,
.parallax-layer,
.reading-progress {
animation: none !important;
opacity: 1 !important;
translate: 0 0 !important;
transform: none !important;
}
}
10. Zusammenfassung
CSS Scroll-Driven Animations sind eine der bedeutendsten Erweiterungen des CSS-Animations-Modells seit Jahren. Mit animation-timeline: scroll() wird eine Animation an den Scroll-Fortschritt eines Containers gebunden, mit animation-timeline: view() an die Sichtbarkeit des Elements selbst. Benannte Timelines (scroll-timeline-name, view-timeline-name) ermöglichen das Verknüpfen von Animationen mit Scroll-Containern über DOM-Ebenen hinweg. animation-range erlaubt präzise Steuerung, in welchem Scroll-/Sichtbarkeitsbereich die Animation aktiv ist.
Der praktische Gewinn: Fortschrittsbalken, Reveal-Animationen, Parallax-Effekte, Sticky-Header-Transformationen und Einblend-Übergänge lassen sich vollständig in CSS ausdrücken — ohne JavaScript, ohne Intersection Observer, ohne requestAnimationFrame. Die Performance-Vorteile durch Compositor-Thread-Ausführung kommen hinzu, wenn ausschließlich compositor-fähige Eigenschaften animiert werden. Für barrierefreie Implementierungen ist @media (prefers-reduced-motion: reduce) Pflicht und sollte in keinem CSS Scroll-Driven Animations-Projekt fehlen.
CSS Scroll-Driven Animations — Das Wichtigste auf einen Blick
scroll()
animation-timeline: scroll(root block) — bindet Animation an Scroll-Fortschritt des Dokuments. 0% = oben, 100% = unten.
view()
animation-timeline: view() — Animation läuft, wenn Element im Viewport erscheint. animation-range: entry steuert den Bereich.
Performance
Nur transform, opacity, filter animieren für Compositor-Thread. Layout-Eigenschaften erzwingen Hauptthread-Beteiligung.
Barrierefreiheit
@media (prefers-reduced-motion: reduce) alle Scroll-Animationen deaktivieren. Basis-Sichtbarkeit ohne @supports sicherstellen.
Mironsoft
Modernes CSS, Animationen und Hyvä-Frontend-Entwicklung
Scroll-Animationen ohne JavaScript-Overhead?
Wir implementieren CSS Scroll-Driven Animations für Hyvä- und Magento-Projekte: Reveal-Effekte, Parallax-Hintergründe und animierte Hero-Bereiche — performant, barrierefrei und ohne eine Zeile JavaScript.
Animations-Audit
Performance-Analyse bestehender JS-Animationen und Migrationsstrategie zu CSS-nativen Lösungen
Reveal-Systeme
Scroll-Driven Reveal-Animationen für Produktlisten, Content-Seiten und Landing Pages
Parallax & Hero
Compositor-optimierte Parallax-Effekte und animierte Hero-Bereiche für hohe Core Web Vitals