Scroll-animaties: animation-timeline in plaats van IntersectionObserver
Scroll-animaties: animation-timeline in plaats van IntersectionObserver
Moderne browsers scrollen op de compositor. Het scrollen zelf wacht niet op JavaScript. Het scroll-evenement wordt echter nadat dit al is gebeurd aan JavaScript geleverd. De browser scrollt en tekent, daarna informeert hij de listener. Uw laag reageert altijd op een scrollpositie die de gebruiker al heeft gezien. Dat is precies waarom position: sticky bestaat.
Scroll-driven animations snijden dit probleem aan de wortel. De browser kan ze op de compositor uitvoeren.
Een voortgangsbalk in vier regels
css
.progress {position: fixed;inset: 0 0 auto 0;height: 4px;transform-origin: left;animation: grow linear both;animation-timeline: scroll(root block);}@keyframes grow {from { transform: scaleX(0); }to { transform: scaleX(1); }}
Reveal on scroll: de view()-timeline
css
.reveal {animation: fade-up linear both;animation-timeline: view();animation-range: entry 0% entry 60%;}@keyframes fade-up {from { opacity: 0; transform: translateY(32px); }to { opacity: 1; transform: translateY(0); }}
De vier benoemde bereiken: entry, exit, cover (de standaard), contain.
De valkuil die een uur kost: de animation-afkorting reset de timeline
animation-timeline en animation-range worden gereset door de afkorting. Dus dit doet absoluut niets:
css
/* KAPOT: de afkorting reset animation-timeline naar auto */.reveal {animation-timeline: view();animation-range: entry 0% entry 60%;animation: fade-up linear both;}
De oplossing is alleen een kwestie van volgorde:
css
/* Correct: timeline en range na de afkorting */.reveal {animation: fade-up linear both;animation-timeline: view();animation-range: entry 0% entry 60%;}
Benoemde timelines
css
.gallery {overflow-x: auto;scroll-timeline: --gallery inline;}.gallery-indicator {animation: fill linear both;animation-timeline: --gallery;timeline-scope: --gallery;}
Progressive enhancement is hier niet optioneel
css
.reveal {opacity: 1; /* standaard: overal zichtbaar */}@supports (animation-timeline: view()) {@media (prefers-reduced-motion: no-preference) {.reveal {animation: fade-up linear both;animation-timeline: view();animation-range: entry 0% entry 60%;}}}
Valkuilen en best practices
- Alleen
transformenopacityanimeren. - Nooit inhoud verbergen die alleen een animatie kan onthullen.
- "Waarom staat mijn animatie stil?" is bijna altijd de scroll-container.
overflow: hiddenop een wrapper bindt de timeline aan die wrapper. bothgebruiken als fill-modus.- Reduced motion is een medische instelling, geen beleefdheid.
- Geen JavaScript verwijderen dat nog nodig is.
Conclusie
Scroll-driven animations passen hetzelfde idee toe op een hele categorie effecten: wat een scroll-listener, een observer, een klassewissel en een bibliotheek als ScrollTrigger vereiste, wordt één CSS-eigenschap.