Für Websites mit Scroll-Animationen, Videos und aufwendigen Effekten. Damit sie auf dem Handy genauso läuft wie auf deinem Rechner.
Alles hier ist das, was ich in echten Kundenprojekten mache — keine Theorie.
Zuerst: richtig messen
Der häufigste Fehler ist nicht die Animation. Es ist, dass du sie nur auf deinem Rechner siehst.
- Chrome DevTools → Device Toolbar (Handy-Symbol oben links).
- Tab Network → Drosselung auf “Fast 4G” oder langsamer.
- Tab Performance → Zahnrad → CPU: 4x slowdown. Ein Mittelklasse-Handy ist ungefähr viermal langsamer als dein Laptop.
- Danach trotzdem auf einem echten Handy testen. Der Simulator zeigt dir die Ladezeit, nicht die Hitze und nicht das Ruckeln.
Wenn die Seite hier flüssig ist, ist sie überall flüssig.
Teil 1 — Die Dateien
- Alle Bilder als WebP (oder AVIF), nie als PNG ausliefern. Bei Frame-Sequenzen ist das der mit Abstand größte Hebel — Faktor 10 bis 25 sind normal.
- Auflösung passt zur Anzeigegröße. Ein Bild, das auf dem Handy 400 px breit dargestellt wird, muss nicht 3000 px breit sein.
- Frame-Anzahl kritisch prüfen. 80 Frames wirken genauso flüssig wie 200, wenn die Bewegung ruhig ist. Jeder Frame, den du streichst, ist Ladezeit, die du geschenkt bekommst.
- Alle Frames exakt gleich groß (gleiche Pixelmaße, gleiches Seitenverhältnis), sonst springt die Animation.
- Videos statt Bildsequenz prüfen. Wenn du nicht scroll-gesteuert scrubben musst, ist ein komprimiertes MP4/WebM fast immer leichter.
Teil 2 — Was das Gerät bekommt
- Nicht jedes Gerät bekommt dieselbe Datei. Lege getrennte Varianten an — mindestens Handy und Desktop, gerne Handy / Tablet / Desktop. Die Variante wird beim Laden anhand der Bildschirmbreite ausgewählt.
- Die Handy-Variante ist kleiner UND kürzer: geringere Auflösung und weniger Frames.
-
<link rel="preload">nur für den einen Frame, den man zuerst sieht — mitmedia-Attribut pro Breakpoint, damit das Handy nicht das Desktop-Bild vorlädt. - Statisches Fallback-Bild hinterlegen (
<picture>oder CSS-background), damit vor dem ersten Frame nie eine schwarze Fläche steht.
Teil 3 — Wie es abgespielt wird
- Ein
<canvas>statt hunderter<img>-Elemente im DOM. Hundert Bilder im DOM heißt hundert Elemente, die der Browser bei jedem Scroll bewerten muss. - Nur neu zeichnen, wenn sich der Frame wirklich ändert. Frame-Index merken, bei gleichem Index nichts tun.
- Zeichnen in
requestAnimationFrame, nie direkt im Scroll-Handler. -
devicePixelRatioauf maximal 2 begrenzen. Manche Handys melden 3 oder 4 — du malst dann die vierfache Pixelmenge für null sichtbaren Unterschied. - Nur
transformundopacityanimieren, nietop,left,widthoderheight. Alles andere zwingt den Browser zum Neu-Layouten. - Scroll-Listener auf
{ passive: true }.
Teil 4 — Vorladen: der Schritt, der das Ruckeln killt
- Alle Frames vorladen, bevor die Animation läuft. Genau hier sterben die meisten Scroll-Animationen: Wenn die Bilder erst nachladen, während schon gescrollt wird, ruckelt es sichtbar — die Bewegung stockt oder springt, weil der nächste Frame noch nicht da ist.
- Keine Angst vor der Datenmenge. Wenn Teil 1 und 2 sitzen (WebP + eigene Handy-Variante), ist die komplette Sequenz meistens klein genug, um sie problemlos komplett vorzuladen — Größenordnung ein paar MB. Einmal laden ist besser als hundertmal stocken.
- Trotzdem sofort den ersten Frame zeigen. Damit niemand auf eine leere Fläche schaut: Startframe zuerst laden und anzeigen, die restlichen Frames laufen unmittelbar danach im Hintergrund durch. Der Besucher sieht sofort ein Bild — und bis er scrollt, ist alles im Speicher.
-
img.decoding = 'async'setzen, damit das Dekodieren den Hauptthread nicht blockiert. - Lazy Loading gilt für den Rest der Seite, nicht für die Sequenz. Bilder weit unten bekommen
loading="lazy"— die Frames deiner Animation ausdrücklich nicht. - Liegt die Animation weit unten, das Vorladen per
IntersectionObserveranstoßen — kurz bevor die Sektion in den Blick kommt, statt beim Seitenaufruf. So blockiert sie den ersten Seitenaufbau nicht und ist trotzdem fertig geladen, wenn sie dran ist.
Teil 5 — Die Pflicht, die fast alle vergessen
-
prefers-reduced-motionrespektieren. Wer im Betriebssystem “Bewegung reduzieren” aktiviert hat, bekommt ein statisches Bild statt der Animation. Zwei Zeilen Code:
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (reduce) { /* statisches Bild zeigen, Animation gar nicht erst starten */ }
Das ist Barrierefreiheit, kein Nice-to-have — für manche Leute lösen solche Animationen echte Übelkeit aus.
Woran du dich orientieren kannst
Offizielle Grenzwerte (Google Core Web Vitals — die zählen auch für dein Ranking):
| Wert | Gut | Bedeutung |
|---|---|---|
| LCP | unter 2,5 s | wann das größte Element sichtbar ist |
| INP | unter 200 ms | wie schnell die Seite auf Eingaben reagiert |
| CLS | unter 0,1 | wie stark das Layout beim Laden springt |
Meine eigenen Richtwerte für Frame-Sequenzen — das sind meine Erfahrungswerte aus echten Projekten, kein Standard:
- Handy-Variante: unter 4 MB für die komplette Sequenz
- pro Frame: 30–50 KB als WebP
- Frame-Anzahl auf dem Handy: 80–100
Der Prompt zum Kopieren
Wenn du mit Claude Code arbeitest und schon eine Frame-Sequenz auf der Seite hast:
Ich habe auf meiner Seite eine scroll-gesteuerte Bildsequenz-Animation.
Optimiere sie für mobile Geräte, ohne dass sie auf dem Desktop schlechter aussieht.
Bitte:
1. Prüfe, in welchem Format und in welcher Auflösung die Frames aktuell
ausgeliefert werden, und sag mir die Gesamtgröße der Sequenz.
2. Konvertiere die Frames nach WebP und lege zusätzlich eine reduzierte
Handy-Variante an (kleinere Auflösung UND weniger Frames). Sag mir
vorher, welche Frames du weglässt.
3. Wähl die passende Variante zur Laufzeit anhand der Bildschirmbreite aus.
4. Render die Sequenz auf ein <canvas> und zeichne nur neu, wenn sich der
Frame-Index ändert. devicePixelRatio auf max. 2 begrenzen.
5. Lade ALLE Frames vor, bevor gescrollt werden kann — nichts darf während
der Animation nachladen. Zeig den Startframe sofort an, damit nichts
leer bleibt, und lad den Rest unmittelbar danach im Hintergrund durch.
6. Setz ein preload nur für den Startframe, mit media-Attribut pro Breakpoint,
plus ein statisches Fallback-Bild.
7. Bei prefers-reduced-motion: Animation nicht starten, statisches Bild zeigen.
Sag mir am Ende, wie groß die Sequenz vorher und nachher war.
In einer Zeile
Schön und schnell ist kein Widerspruch. Es ist Arbeit, die man einmal macht — und dann läuft es auf jedem Gerät.
Wenn du so eine Seite komplett fertig willst, schreib mir einfach eine DM.