Ontgrendel boterzachte, performante scroll-gebaseerde animaties met pure CSS. Deze gids behandelt animation-timeline en animation-range voor nauwkeurige controle.
CSS Animation Range: Een diepgaande blik op de besturing van scroll-gestuurde animaties
Jarenlang was het creëren van animaties die reageren op de scrollpositie van een gebruiker een hoeksteen van boeiende webervaringen. Van subtiele fade-ins tot complexe parallaxeffecten, deze interacties blazen leven in statische pagina's. Dit ging echter traditioneel gepaard met aanzienlijke kosten: de afhankelijkheid van JavaScript. Bibliotheken en aangepaste scripts die luisteren naar scroll-events kunnen prestatie-intensief zijn, draaien op de main thread en kunnen leiden tot haperige, niet-responsieve gebruikerservaringen, vooral op minder krachtige apparaten.
Betreed een nieuw tijdperk van webanimatie. De nieuwste ontwikkelingen in CSS revolutioneren hoe we deze interacties aanpakken. De Scroll-Driven Animations-specificatie biedt een krachtige, declaratieve en zeer performante manier om animaties rechtstreeks te koppelen aan de positie van een scrollbar of de zichtbaarheid van een element binnen de viewport—allemaal zonder één regel JavaScript.
De kern van dit nieuwe paradigma wordt gevormd door twee belangrijke eigenschappen: animation-timeline en animation-range. Terwijl animation-timeline de basis legt door te definiëren wat de animatie aandrijft (bijv. de scrollbar van het document), is het animation-range dat ons de granulaire controle geeft waar we altijd naar hebben verlangd. Het stelt ons in staat om de precieze start- en eindpunten van een animatie binnen die tijdlijn te definiëren.
In deze uitgebreide gids verkennen we de wereld van CSS Scroll-Driven Animations met een speciale focus op animation-range. We behandelen:
- De fundamentele concepten van Scroll en View Progress Timelines.
- Een gedetailleerde uiteenzetting van de
animation-range-eigenschap en de syntaxis ervan. - Praktische, real-world voorbeelden voor het maken van voortgangsbalken, onthullingseffecten en meer.
- Best practices voor prestaties, toegankelijkheid en browsercompatibiliteit.
Maak je klaar om animaties te ontgrendelen die niet alleen mooi zijn, maar ook ongelooflijk efficiënt, waarbij complexe logica van de main thread naar de compositor thread wordt verplaatst voor een gegarandeerd boterzachte ervaring.
De basis begrijpen: Wat zijn scroll-gestuurde animaties?
Voordat we dieper ingaan op animation-range, is het cruciaal om het systeem te begrijpen waarin het opereert. Traditioneel zijn CSS-animaties gekoppeld aan een op tijd gebaseerde tijdlijn. Wanneer je animation-duration: 3s; definieert, vordert de animatie van 0% tot 100% over drie seconden, aangedreven door een klok.
Scroll-gestuurde animaties veranderen dit fundamenteel. Ze introduceren het concept van een Progress Timeline (voortgangstijdlijn), die niet wordt aangedreven door tijd, maar door voortgang—ofwel de voortgang van het scrollen in een container, ofwel de voortgang van de zichtbaarheid van een element terwijl het door de viewport beweegt.
Dit nieuwe model biedt drie grote voordelen:
- Prestaties: Omdat deze animaties buiten de main thread op de compositor thread van de browser kunnen draaien, concurreren ze niet om middelen met JavaScript, layout- of paint-operaties. Het resultaat is een uitzonderlijk vloeiende animatie, vrij van de haperingen die vaak voorkomen bij op JS gebaseerde scroll-listeners.
- Eenvoud: De CSS-syntaxis is declaratief. Je geeft aan wat je wilt dat er gebeurt, en de browser regelt de complexe berekeningen. Dit leidt vaak tot schonere, beter onderhoudbare code in vergelijking met imperatief JavaScript.
- Toegankelijkheid: De animaties respecteren standaard gebruikersvoorkeuren zoals
prefers-reduced-motion, wat het gemakkelijker maakt om inclusieve ervaringen te bouwen.
Er zijn twee primaire typen voortgangstijdlijnen waarmee je zult werken:
- Scroll Progress Timeline: Volgt de scrollpositie binnen een scrollcontainer (een "scroller"). De tijdlijn vertegenwoordigt het volledige scrollbare bereik, van helemaal bovenaan (0%) tot helemaal onderaan (100%).
- View Progress Timeline: Volgt de zichtbaarheid van een element terwijl het de viewport doorkruist. De tijdlijn vertegenwoordigt de reis van het element van net binnenkomen in de viewport tot het volledig verlaten ervan.
Het Kernconcept: De `animation-timeline` eigenschap
De eerste stap bij het maken van een scroll-gestuurde animatie is om een standaard CSS-animatie los te koppelen van de standaard op tijd gebaseerde klok en deze te koppelen aan een nieuwe, op voortgang gebaseerde tijdlijn. Dit wordt gedaan met de animation-timeline-eigenschap.
Deze accepteert een functie die de bron van de tijdlijn definieert: ofwel scroll() voor een Scroll Progress Timeline, ofwel view() voor een View Progress Timeline.
Scroll Progress Timeline: `scroll()`
De scroll()-functie koppelt een animatie aan de scrollpositie van een container. De meest gebruikte vorm is scroll(scroller, axis).
scroller: Specificeert welk scrollend element gevolgd moet worden. Dit kanroot(de viewport van het document),self(het element zelf, als het een scroller is), ofnearest(de dichtstbijzijnde voorouder-scroller) zijn.axis: Specificeert de scroll-as die gevolgd moet worden. Dit kanblock(de primaire richting van de contentstroom, meestal verticaal),inline(loodrecht op block, meestal horizontaal),y, ofxzijn.
Voorbeeld: Een eenvoudige voortgangsbalk voor het scrollen van het document
Laten we een voortgangsbalk bovenaan de pagina maken die groeit naarmate de gebruiker naar beneden scrolt.
<!-- HTML -->
<div id="progress-bar"></div>
<!-- CSS -->
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
#progress-bar {
position: fixed;
top: 0;
left: 0;
height: 10px;
width: 100%;
background-color: dodgerblue;
transform-origin: left;
/* Maak los van tijd, koppel aan het scrollen van het document */
animation: grow-progress linear;
animation-timeline: scroll(root block);
}
In dit voorbeeld wordt de grow-progress-animatie nu aangedreven door het scrollen van het hoofddocument (root) op de verticale as (block). Terwijl je van 0% naar 100% van de pagina scrolt, gaat de scaleX-transformatie van de voortgangsbalk van 0 naar 1.
View Progress Timeline: `view()`
De view()-functie koppelt een animatie aan de zichtbaarheid van een element binnen zijn scroller. Dit is ongelooflijk handig voor het activeren van "onthullings"-animaties wanneer elementen in beeld komen.
De syntaxis is view(axis, inset).
axis: Optioneel, dezelfde waarden als inscroll()(bijv.block). Definieert welke as van de scrollport in overweging moet worden genomen.inset: Optioneel, hiermee kun je de grenzen van de viewport aanpassen die worden gebruikt voor het berekenen van de zichtbaarheid, vergelijkbaar met derootMarginvanIntersectionObserver.
Voorbeeld: Een element laten infaden
<!-- HTML -->
<div class="content-box reveal">
Deze box zal infaden als hij het scherm binnenkomt.
</div>
<!-- CSS -->
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
.reveal {
/* Koppel animatie aan de zichtbaarheid van dit element */
animation: fade-in linear;
animation-timeline: view();
}
Hier is de fade-in-animatie gekoppeld aan het .reveal-element zelf. De animatie vordert naarmate het element door de viewport beweegt. Maar hoe wordt dit precies gemapt? Wanneer begint en eindigt het? Dat is waar animation-range om de hoek komt kijken.
De ster van de show: `animation-range`
Terwijl animation-timeline de context bepaalt, biedt animation-range de cruciale controle. Het definieert welk deel van de tijdlijn als "actief" wordt beschouwd en koppelt dit aan de 0% tot 100% voortgang van je @keyframes-animatie.
De basissyntaxis is:
animation-range: <range-start> <range-end>;
Dit vertelt de browser: "Wanneer de tijdlijn het <range-start>-punt bereikt, moet de animatie op 0% zijn. Wanneer het het <range-end>-punt bereikt, moet de animatie op 100% zijn."
De waarden voor <range-start> en <range-end> kunnen van verschillende typen zijn:
- Sleutelwoorden (voor
view()): Speciale, zeer intuïtieve namen zoalsentry,exit,coverencontain. We zullen deze in detail bekijken. - Percentages: Een percentage van de totale duur van de tijdlijn. Voor een
scroll()-tijdlijn is0%de bovenkant en100%de onderkant. - CSS-lengtes: Een vaste lengtewaarde zoals
100pxof20rem. Dit specificeert een punt op die scroll-offset vanaf het begin van de tijdlijn.
Je kunt zelfs sleutelwoorden combineren met percentages of lengtes voor extreem fijnmazige controle, zoals entry 50% of cover 200px.
Praktische diepgang: `animation-range` met `scroll()` tijdlijnen
Wanneer je met een scroll()-tijdlijn werkt, map je je animatie aan het totale scrollbereik van de scroller. Laten we eens kijken hoe animation-range ons helpt om specifieke delen van die reis te targeten.
Een specifieke scrolsectie targeten
Stel je voor dat je een lang artikel hebt en je wilt dat een specifieke afbeelding alleen animeert terwijl de gebruiker door de middelste helft van de pagina scrolt.
@keyframes spin-and-grow {
from { transform: rotate(0deg) scale(0.5); opacity: 0; }
to { transform: rotate(360deg) scale(1); opacity: 1; }
}
.special-graphic {
animation: spin-and-grow linear;
animation-timeline: scroll(root block);
/* Animatie start bij 25% scroll en eindigt bij 75% scroll */
animation-range: 25% 75%;
}
Hoe het werkt:
- Voordat de gebruiker 25% van de pagina heeft gescrold, wordt de animatie vastgehouden in de 0%-staat (
rotate(0deg) scale(0.5) opacity: 0). - Terwijl de gebruiker van de 25%-markering naar de 75%-markering scrolt, vordert de animatie van 0% naar 100%.
- Nadat de gebruiker voorbij de 75%-markering scrolt, wordt de animatie vastgehouden in de 100%-staat (
rotate(360deg) scale(1) opacity: 1).
Deze eenvoudige toevoeging van animation-range geeft ons krachtige controle over de timing en plaatsing van onze effecten binnen de grotere scroll-ervaring.
Absolute lengtes gebruiken
Je kunt ook absolute lengtes gebruiken. Bijvoorbeeld, als je wilt dat een animatie alleen plaatsvindt tijdens de eerste 500 pixels van het scrollen:
.hero-animation {
animation: fade-out linear;
animation-timeline: scroll(root block);
/* Animatie start bij scroll-offset 0px en eindigt bij 500px */
animation-range: 0px 500px;
}
Dit is perfect voor inleidende animaties in de hero-sectie van een pagina, die moeten eindigen zodra de gebruiker dieper in de content begint te scrollen.
`animation-range` meesteren met `view()` tijdlijnen
Dit is waar animation-range echt magisch wordt. Wanneer gebruikt met een view()-tijdlijn, zijn de bereikwaarden niet gebaseerd op de totale scrollhoogte van het document, maar op de zichtbaarheid van het element binnen de viewport. Hier komen de speciale benoemde bereiken om de hoek kijken.
De benoemde bereiken uitgelegd
Stel je een element (het "subject") en de viewport (de "scroller") voor. De benoemde bereiken beschrijven de relatie tussen deze twee boxen.
entry: De fase waarin het subject de viewport binnenkomt. Het begint op het moment dat de onderkant van het subject de bovenkant van de viewport kruist en eindigt wanneer de onderkant van het subject de onderkant van de viewport kruist.exit: De fase waarin het subject de viewport verlaat. Het begint wanneer de bovenkant van het subject de bovenkant van de viewport kruist en eindigt wanneer de bovenkant van het subject de onderkant van de viewport kruist.cover: De fase waarin het subject groot genoeg is om de viewport volledig te bedekken. Het begint wanneer de bovenkant van het subject de bovenkant van de viewport raakt en eindigt wanneer de onderkant van het subject de onderkant van de viewport raakt. Als het subject kleiner is dan de viewport, vindt deze fase nooit plaats.contain: De fase waarin het subject volledig binnen de viewport valt. Het begint wanneer de onderkant van het subject de onderkant van de viewport binnenkomt en eindigt wanneer de bovenkant van het subject de bovenkant van de viewport verlaat. Als het subject groter is dan de viewport, vindt deze fase nooit plaats.
Praktisch voorbeeld: Het klassieke "onthul bij scrollen"-effect
Laten we een van de meest voorkomende scroll-gebaseerde animaties nabootsen: een element dat infade en in beeld schuift wanneer het het scherm binnenkomt. Traditioneel vereiste dit een Intersection Observer in JavaScript. Nu zijn het een paar regels CSS.
<!-- HTML -->
<section>
<div class="content-box reveal">Box 1</div>
<div class="content-box reveal">Box 2</div>
<div class="content-box reveal">Box 3</div>
</section>
<!-- CSS -->
@keyframes fade-and-slide-in {
from { opacity: 0; transform: translateY(50px); }
to { opacity: 1; transform: translateY(0); }
}
.reveal {
animation: fade-and-slide-in linear both; /* 'both' is belangrijk! */
animation-timeline: view();
/* Start animatie wanneer element binnenkomt, eindig wanneer het halverwege binnenkomen is */
animation-range: entry 0% entry 50%;
}
Laten we die animation-range-waarde eens ontleden:
animation-fill-mode: both;is cruciaal. Het zorgt ervoor dat het element vóór het actieve bereik van de animatie in zijnfrom-staat blijft (onzichtbaar en naar beneden verschoven), en na het bereik in zijnto-staat blijft (volledig zichtbaar en op zijn plaats).entry 0%: Het startpunt. Dit verwijst naar het allereerste begin van deentry-fase—het exacte moment dat de onderkant van ons element de onderkant van de viewport raakt.entry 50%: Het eindpunt. Dit verwijst naar het moment waarop het element 50% van zijn reis door deentry-fase heeft voltooid. Op dit punt zal de animatie 100% voltooid zijn.
Dit geeft een prettig effect waarbij het item volledig zichtbaar en op zijn definitieve positie is, ruim voordat de gebruiker het naar het midden van het scherm heeft gescrold. Je kunt deze percentages aanpassen om precies het gewenste gevoel te krijgen. Bijvoorbeeld, entry 25% entry 75% zou een meer uitgerekte animatie creëren.
Geavanceerde controle: Een parallaxeffect creëren
Laten we een complexer effect proberen. We maken een achtergrondafbeelding die met een andere snelheid beweegt dan de scroll, maar alleen terwijl de container de viewport bedekt.
<!-- HTML -->
<div class="parallax-container">
<div class="parallax-bg"></div>
<h2>Parallax Sectie</h2>
</div>
<!-- CSS -->
@keyframes parallax-shift {
from { background-position: 50% -50px; }
to { background-position: 50% 50px; }
}
.parallax-container {
position: relative;
height: 100vh;
overflow: hidden;
}
.parallax-bg {
position: absolute;
inset: -50px; /* Maak het hoger dan de container om beweging mogelijk te maken */
background-image: url('your-image.jpg');
background-size: cover;
animation: parallax-shift linear both;
animation-timeline: view(block);
/* Animeer over de gehele 'cover'-fase */
animation-range: cover 0% cover 100%;
}
In dit geval is de parallax-shift-animatie gekoppeld aan de tijdlijn van het parallax-bg-element. De animation-range is ingesteld op de volledige duur van de cover-fase. Dit betekent dat de animatie pas begint te vorderen wanneer de container hoog genoeg is om de viewport te bedekken en zo is gepositioneerd dat de bovenkant gelijk is aan de bovenkant van de viewport. Het eindigt wanneer de onderkant van de container de onderkant van de viewport bereikt. Het resultaat is een soepel, performant parallaxeffect dat perfect gesynchroniseerd is met de scrollpositie.
Alles combineren: Afkortingen en best practices
De `animation` afkorting
Om de syntaxis nog beknopter te maken, kunnen de timeline- en range-eigenschappen direct in de animation-afkorting worden opgenomen. Dit is een nieuwe, voorgestelde syntaxis die steeds meer ondersteuning krijgt.
Ons onthul-bij-scrollen-voorbeeld kan worden herschreven als:
.reveal {
animation: fade-and-slide-in linear both view() entry 0% entry 50%;
}
Deze enkele regel vervangt de drie afzonderlijke animation-, animation-timeline- en animation-range-eigenschappen. Het is schoon, efficiënt en houdt alle animatielogica op één plek.
Prestatieoverwegingen
Het belangrijkste voordeel van scroll-gestuurde animaties is de prestatie. Om dit voordeel te behouden, moet je prioriteit geven aan het animeren van eigenschappen die door de compositor thread kunnen worden afgehandeld. Dit zijn voornamelijk:
transform(translate, scale, rotate)opacity
Het animeren van eigenschappen zoals width, height, margin of color werkt nog steeds, maar ze kunnen layout- en paint-operaties triggeren, die op de main thread plaatsvinden. Hoewel ze vaak nog steeds soepeler zijn dan op JS gebaseerde alternatieven, zullen ze niet zo performant zijn als animaties die alleen op de compositor draaien.
Toegankelijkheid en fallbacks
Het is cruciaal om voor alle gebruikers te bouwen. Scroll-gestuurde animaties zijn geweldig, maar sommige gebruikers vinden beweging storend of misselijkmakend.
1. Respecteer gebruikersvoorkeuren: Plaats je bewegingsgerelateerde CSS altijd binnen een prefers-reduced-motion media query.
@media (prefers-reduced-motion: no-preference) {
.reveal {
animation: fade-and-slide-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
}
2. Bied fallbacks voor oudere browsers: Aangezien dit een nieuwe technologie is, moet je rekening houden met browsers die het nog niet ondersteunen. De @supports-regel is hier je beste vriend. Bied een eenvoudige, niet-geanimeerde standaardstatus en verbeter deze voor ondersteunende browsers.
/* Standaardstatus voor alle browsers */
.reveal {
opacity: 1;
transform: translateY(0);
}
/* Verbetering voor ondersteunende browsers */
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
.reveal {
opacity: 0; /* Stel de beginstatus voor de animatie in */
transform: translateY(50px);
animation: fade-and-slide-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
}
}
Browserondersteuning en de toekomst
Sinds eind 2023 worden CSS Scroll-Driven Animations ondersteund in Chrome en Edge. Ze zijn in actieve ontwikkeling in Firefox en worden overwogen door Safari. Zoals bij elke geavanceerde webplatformfunctie is het essentieel om bronnen zoals CanIUse.com te raadplegen voor de laatste ondersteuningsinformatie.
De introductie van deze technologie markeert een belangrijke verschuiving in webontwikkeling. Het stelt ontwerpers en ontwikkelaars in staat om rijke, interactieve en performante ervaringen declaratief te creëren, waardoor onze afhankelijkheid van JavaScript voor een hele klasse van veelvoorkomende UI-patronen wordt verminderd. Naarmate de browserondersteuning volwassener wordt, kun je verwachten dat scroll-gestuurde animaties een essentieel hulpmiddel worden in de toolkit van elke front-end ontwikkelaar.
Conclusie
CSS Scroll-Driven Animations, en specifiek de animation-range-eigenschap, vertegenwoordigen een monumentale sprong voorwaarts voor webanimatie. We zijn overgestapt van op tijd gebaseerde tijdlijnen naar op voortgang gebaseerde tijdlijnen, wat de mogelijkheid ontsluit om complexe, scroll-bewuste interacties te creëren met ongeëvenaarde prestaties en eenvoud.
We hebben geleerd dat:
animation-timelineeen animatie koppelt aan eenscroll()- ofview()-voortgangstijdlijn.animation-rangeons precieze controle geeft, waarbij een specifiek deel van die tijdlijn wordt gemapt aan de keyframes van onze animatie.- Met
view()-tijdlijnen bieden krachtige benoemde bereiken zoalsentry,exit,coverencontaineen intuïtieve manier om animaties te besturen op basis van de zichtbaarheid van een element. - Door vast te houden aan compositor-vriendelijke eigenschappen en fallbacks te bieden, kunnen we deze technologie vandaag de dag gebruiken om toegankelijke, performante en prachtige gebruikerservaringen te bouwen.
De dagen van vechten met haperige, main-thread-blokkerende scroll-listeners voor eenvoudige effecten zijn geteld. De toekomst van scroll-gebaseerde animatie is hier, het is declaratief en het is geschreven in CSS. Het is tijd om te gaan experimenteren.