Lås opp silkemyke, høytytende rullebaserte animasjoner med ren CSS. Denne guiden dekker animation-timeline og animation-range for presis kontroll.
CSS Animation Range: Et dypdykk i kontroll av rullestyrte animasjoner
I årevis har det å lage animasjoner som reagerer på en brukers rulleposisjon vært en hjørnestein i engasjerende webopplevelser. Fra subtile fade-ins til komplekse parallakseeffekter, gir disse interaksjonene liv til statiske sider. De har imidlertid tradisjonelt kommet med en betydelig kostnad: avhengighet av JavaScript. Biblioteker og egendefinerte skript som lytter etter rullehendelser kan være ytelseskrevende, kjøre på hovedtråden og potensielt føre til hakkete, trege brukeropplevelser, spesielt på mindre kraftige enheter.
Velkommen til en ny æra for webanimasjon. De siste fremskrittene innen CSS revolusjonerer hvordan vi håndterer disse interaksjonene. Spesifikasjonen for Rullestyrte animasjoner (Scroll-Driven Animations) gir en kraftig, deklarativ og svært ytelseseffektiv måte å koble animasjoner direkte til en rullefelts posisjon eller et elements synlighet i visningsområdet – alt uten en eneste linje med JavaScript.
I hjertet av dette nye paradigmet ligger to nøkkelegenskaper: animation-timeline og animation-range. Mens animation-timeline legger grunnlaget ved å definere hva som driver animasjonen (f.eks. dokumentets rullefelt), er det animation-range som gir oss den detaljerte kontrollen vi alltid har ønsket oss. Den lar oss definere de nøyaktige start- og sluttpunktene for en animasjon innenfor den tidslinjen.
I denne omfattende guiden vil vi utforske verdenen av CSS' rullestyrte animasjoner med et spesielt fokus på animation-range. Vi vil dekke:
- De grunnleggende konseptene for rulle- og visningsfremdrifts-tidslinjer.
- En detaljert gjennomgang av egenskapen
animation-rangeog dens syntaks. - Praktiske, virkelige eksempler for å lage fremdriftsindikatorer, avsløringseffekter og mer.
- Beste praksis for ytelse, tilgjengelighet og nettleserkompatibilitet.
Gjør deg klar til å låse opp animasjoner som ikke bare er vakre, men også utrolig effektive, og flytter kompleks logikk fra hovedtråden til kompositt-tråden for en garantert silkemyk opplevelse.
Forstå grunnlaget: Hva er rullestyrte animasjoner?
Før vi dykker ned i animation-range, er det avgjørende å forstå systemet det opererer innenfor. Tradisjonelt er CSS-animasjoner knyttet til en tidsbasert tidslinje. Når du definerer animation-duration: 3s;, går animasjonen fra 0 % til 100 % over tre sekunder, drevet av en klokke.
Rullestyrte animasjoner endrer dette fundamentalt. De introduserer konseptet med en Fremdrifts-tidslinje (Progress Timeline), som ikke drives av tid, men av fremdrift – enten fremdriften av rulling i en beholder eller fremdriften av et elements synlighet mens det beveger seg gjennom visningsområdet.
Denne nye modellen tilbyr tre store fordeler:
- Ytelse: Fordi disse animasjonene kan kjøres utenfor hovedtråden på nettleserens kompositt-tråd, konkurrerer de ikke om ressurser med JavaScript, layout- eller paint-operasjoner. Resultatet er eksepsjonelt jevn animasjon, fri for den hakkingen som ofte plager JS-baserte rullelyttere.
- Enkelhet: CSS-syntaksen er deklarativ. Du angir hva du vil skal skje, og nettleseren håndterer de komplekse beregningene. Dette fører ofte til renere, mer vedlikeholdbar kode sammenlignet med imperativ JavaScript.
- Tilgjengelighet: Animasjonene respekterer brukerpreferanser som
prefers-reduced-motionsom standard, noe som gjør det enklere å bygge inkluderende opplevelser.
Det er to hovedtyper av fremdrifts-tidslinjer du vil jobbe med:
- Rullefremdrifts-tidslinje: Spore rulleposisjonen i en rullebeholder (en "scroller"). Tidslinjen representerer hele det rullbare området, fra helt øverst (0 %) til helt nederst (100 %).
- Visningsfremdrifts-tidslinje: Spore et elements synlighet når det krysser visningsområdet. Tidslinjen representerer elementets reise fra det akkurat kommer inn i visningsområdet til det forlater det helt.
Kjernekonseptet: Egenskapen animation-timeline
Det første steget i å lage en rullestyrt animasjon er å løsrive en standard CSS-animasjon fra sin standard tidsbaserte klokke og koble den til en ny fremdriftsbasert tidslinje. Dette gjøres med egenskapen animation-timeline.
Den godtar en funksjon som definerer kilden til tidslinjen: enten scroll() for en rullefremdrifts-tidslinje eller view() for en visningsfremdrifts-tidslinje.
Rullefremdrifts-tidslinje: `scroll()`
Funksjonen scroll() knytter en animasjon til rulleposisjonen til en beholder. Den vanligste formen er scroll(scroller, axis).
scroller: Spesifiserer hvilket rulleelement som skal spores. Det kan væreroot(dokumentets visningsområde),self(elementet selv, hvis det kan rulles), ellernearest(nærmeste overordnede rulleelement).axis: Spesifiserer rulleaksen som skal spores. Det kan væreblock(hovedretningen for innholdsflyt, vanligvis vertikal),inline(vinkelrett på block, vanligvis horisontal),y, ellerx.
Eksempel: En enkel fremdriftsindikator for dokumentrulling
La oss lage en fremdriftsindikator øverst på siden som vokser etter hvert som brukeren ruller nedover.
<!-- 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;
/* Løsriv fra tid, koble til dokumentets rulling */
animation: grow-progress linear;
animation-timeline: scroll(root block);
}
I dette eksempelet blir animasjonen grow-progress nå drevet av rulling i hoveddokumentet (root) på den vertikale aksen (block). Når du ruller fra 0 % til 100 % av siden, går fremdriftsindikatorens scaleX-transformasjon fra 0 til 1.
Visningsfremdrifts-tidslinje: `view()`
Funksjonen view() knytter en animasjon til et elements synlighet innenfor dets rullebeholder. Dette er utrolig nyttig for å utløse "avslørings"-animasjoner når elementer kommer til syne.
Syntaksen er view(axis, inset).
axis: Valgfri, samme verdier som iscroll()(f.eks.block). Definerer hvilken akse av rulleområdet som skal tas i betraktning.inset: Valgfri, lar deg justere grensene for visningsområdet som brukes til å beregne synlighet, liknendeIntersectionObserversrootMargin.
Eksempel: Fade inn et element
<!-- HTML -->
<div class="content-box reveal">
Denne boksen vil fade inn når den kommer inn på skjermen.
</div>
<!-- CSS -->
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
.reveal {
/* Koble animasjonen til dette elementets synlighet */
animation: fade-in linear;
animation-timeline: view();
}
Her er fade-in-animasjonen koblet til .reveal-elementet selv. Animasjonen vil utvikle seg mens elementet beveger seg over visningsområdet. Men hvordan nøyaktig kartlegges dette? Når starter og slutter den? Det er her animation-range kommer inn.
Stjernen i showet: `animation-range`
Mens animation-timeline setter konteksten, gir animation-range den kritiske kontrollen. Den definerer hvilken del av tidslinjen som anses som "aktiv" og kartlegger den til 0 % til 100 % fremdriften av din @keyframes-animasjon.
Den grunnleggende syntaksen er:
animation-range: <range-start> <range-end>;
Dette forteller nettleseren: "Når tidslinjen når <range-start>-punktet, skal animasjonen være på 0 %. Når den når <range-end>-punktet, skal animasjonen være på 100 %."
Verdiene for <range-start> og <range-end> kan være av flere typer:
- Nøkkelord (for
view()): Spesielle, svært intuitive navn somentry,exit,coverogcontain. Vi vil utforske disse i detalj. - Prosentandeler: En prosentandel av tidslinjens totale varighet. For en
scroll()-tidslinje er0%toppen og100%bunnen. - CSS-lengder: En fast lengdeverdi som
100pxeller20rem. Dette spesifiserer et punkt ved den rulleforskyvningen fra begynnelsen av tidslinjen.
Du kan til og med kombinere nøkkelord med prosentandeler eller lengder for ekstremt finkornet kontroll, som entry 50% eller cover 200px.
Praktisk dypdykk: `animation-range` med `scroll()`-tidslinjer
Når du jobber med en scroll()-tidslinje, kartlegger du animasjonen din til rulleelementets totale rulleområde. La oss se hvordan animation-range hjelper oss med å målrette spesifikke deler av den reisen.
Målretting mot en spesifikk rulleseksjon
Tenk deg at du har en lang artikkel, og du vil at en bestemt grafikk skal animeres bare mens brukeren ruller gjennom den midterste halvdelen av siden.
@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);
/* Animasjonen starter ved 25% rulling og slutter ved 75% rulling */
animation-range: 25% 75%;
}
Slik fungerer det:
- Før brukeren har rullet 25 % av siden, holdes animasjonen i sin 0 %-tilstand (
rotate(0deg) scale(0.5) opacity: 0). - Når brukeren ruller fra 25 %-merket til 75 %-merket, går animasjonen fra 0 % til 100 %.
- Etter at brukeren har rullet forbi 75 %-merket, holdes animasjonen i sin 100 %-tilstand (
rotate(360deg) scale(1) opacity: 1).
Dette enkle tillegget av animation-range gir oss kraftig kontroll over timingen og plasseringen av effektene våre innenfor den større rulleopplevelsen.
Bruke absolutte lengder
Du kan også bruke absolutte lengder. For eksempel, hvis du vil at en animasjon skal skje bare over de første 500 pikslene med rulling:
.hero-animation {
animation: fade-out linear;
animation-timeline: scroll(root block);
/* Animasjonen starter ved rulleforskyvning 0px og slutter ved 500px */
animation-range: 0px 500px;
}
Dette er perfekt for introduksjonsanimasjoner i en sides hero-seksjon som skal avsluttes når brukeren har begynt å rulle dypere inn i innholdet.
Mestre `animation-range` med `view()`-tidslinjer
Det er her animation-range blir virkelig magisk. Når den brukes med en view()-tidslinje, er ikke områdets verdier basert på hele dokumentets rullehøyde, men på elementets synlighet innenfor visningsområdet. Det er her de spesielle navngitte områdene kommer inn i bildet.
De navngitte områdene forklart
Se for deg et element ("subjektet") og visningsområdet ("rulleren"). De navngitte områdene beskriver forholdet mellom disse to boksene.
entry: Fasen der subjektet kommer inn i visningsområdet. Den begynner i det øyeblikket subjektets nedre kant krysser visningsområdets øvre kant og slutter når subjektets nedre kant krysser visningsområdets nedre kant.exit: Fasen der subjektet forlater visningsområdet. Den begynner når subjektets øvre kant krysser visningsområdets øvre kant og slutter når subjektets øvre kant krysser visningsområdets nedre kant.cover: Fasen der subjektet er stort nok til å dekke visningsområdet helt. Den begynner når subjektets øvre kant treffer visningsområdets øvre kant og slutter når subjektets nedre kant treffer visningsområdets nedre kant. Hvis subjektet er mindre enn visningsområdet, oppstår aldri denne fasen.contain: Fasen der subjektet er fullstendig inneholdt i visningsområdet. Den begynner når subjektets nedre kant kommer inn i visningsområdets nedre kant og slutter når subjektets øvre kant forlater visningsområdets øvre kant. Hvis subjektet er større enn visningsområdet, oppstår aldri denne fasen.
Praktisk eksempel: Den klassiske "Avslør ved rulling"-effekten
La oss gjenskape en av de vanligste rullebaserte animasjonene: et element som fader og glir inn i synsfeltet når det kommer inn på skjermen. Tradisjonelt krevde dette en Intersection Observer i JavaScript. Nå er det noen få linjer med CSS.
<!-- HTML -->
<section>
<div class="content-box reveal">Boks 1</div>
<div class="content-box reveal">Boks 2</div>
<div class="content-box reveal">Boks 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' er viktig! */
animation-timeline: view();
/* Start animasjonen når elementet kommer inn, avslutt når det er halvveis gjennom inngangsfasen */
animation-range: entry 0% entry 50%;
}
La oss bryte ned den animation-range-verdien:
animation-fill-mode: both;er avgjørende. Det sikrer at før animasjonens aktive område, forblir elementet i sinfrom-tilstand (usynlig og forskjøvet ned), og etter området, forblir det i sinto-tilstand (fullt synlig og på plass).entry 0%: Startpunktet. Dette refererer til selve begynnelsen aventry-fasen – nøyaktig det øyeblikket bunnen av elementet vårt berører bunnen av visningsområdet.entry 50%: Sluttpunktet. Dette refererer til øyeblikket elementet har fullført 50 % av sin reise gjennomentry-fasen. På dette tidspunktet vil animasjonen være 100 % fullført.
Dette gir en behagelig effekt der elementet er fullt synlig og i sin endelige posisjon i god tid før brukeren har rullet det til midten av skjermen. Du kan justere disse prosentandelene for å få nøyaktig den følelsen du ønsker. For eksempel vil entry 25% entry 75% skape en mer langstrakt animasjon.
Avansert kontroll: Å skape en parallakseeffekt
La oss prøve en mer kompleks effekt. Vi skal få et bakgrunnsbilde til å bevege seg med en annen hastighet enn rullingen, men bare mens beholderen dekker visningsområdet.
<!-- HTML -->
<div class="parallax-container">
<div class="parallax-bg"></div>
<h2>Parallakseseksjon</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; /* Gjør det høyere enn beholderen for å tillate bevegelse */
background-image: url('your-image.jpg');
background-size: cover;
animation: parallax-shift linear both;
animation-timeline: view(block);
/* Animer over hele 'cover'-fasen */
animation-range: cover 0% cover 100%;
}
I dette tilfellet er parallax-shift-animasjonen knyttet til parallax-bg-elementets tidslinje. animation-range er satt til hele varigheten av cover-fasen. Dette betyr at animasjonen bare begynner å utvikle seg når beholderen er høy nok til å dekke visningsområdet og er posisjonert slik at toppen er på toppen av visningsområdet. Den avsluttes når beholderens bunn når bunnen av visningsområdet. Resultatet er en jevn, ytelseseffektiv parallakseeffekt som er perfekt synkronisert med rulleposisjonen.
Kombinere alt: Kortformer og beste praksis
Kortformen `animation`
For å gjøre syntaksen enda mer konsis, kan tidslinje- og områdeegenskapene inkluderes direkte i kortformen animation. Dette er en ny, foreslått syntaks som får stadig mer støtte.
Vårt eksempel med avsløring ved rulling kan skrives om som:
.reveal {
animation: fade-and-slide-in linear both view() entry 0% entry 50%;
}
Denne ene linjen erstatter de tre separate egenskapene animation, animation-timeline og animation-range. Det er rent, effektivt og holder all animasjonslogikk på ett sted.
Ytelseshensyn
Den primære fordelen med rullestyrte animasjoner er ytelse. For å opprettholde denne fordelen, bør du prioritere å animere egenskaper som kan håndteres av kompositt-tråden. Disse er primært:
transform(translate, scale, rotate)opacity
Å animere egenskaper som width, height, margin eller color vil fortsatt fungere, men de kan utløse layout- og paint-operasjoner, som skjer på hovedtråden. Selv om de ofte er jevnere enn JS-baserte alternativer, vil de ikke være like ytelseseffektive som animasjoner som kun kjører på kompositt-tråden.
Tilgjengelighet og reserveplaner (Fallbacks)
Det er avgjørende å bygge for alle brukere. Rullestyrte animasjoner er flotte, men noen brukere synes bevegelse er distraherende eller kvalmende.
1. Respekter brukerpreferanser: Pakk alltid din bevegelsesrelaterte CSS inn i en prefers-reduced-motion medie-spørring.
@media (prefers-reduced-motion: no-preference) {
.reveal {
animation: fade-and-slide-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
}
2. Tilby reserveplaner for eldre nettlesere: Siden dette er en ny teknologi, må du ta høyde for nettlesere som ennå ikke støtter den. @supports-regelen er din beste venn her. Gi en enkel, ikke-animert standardtilstand, og forbedre den deretter for nettlesere som støtter det.
/* Standardtilstand for alle nettlesere */
.reveal {
opacity: 1;
transform: translateY(0);
}
/* Forbedring for støttende nettlesere */
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
.reveal {
opacity: 0; /* Sett starttilstand for animasjon */
transform: translateY(50px);
animation: fade-and-slide-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
}
}
Nettleserstøtte og veien videre
Per slutten av 2023 er CSS Rullestyrte animasjoner støttet i Chrome og Edge. De er under aktiv utvikling i Firefox og vurderes av Safari. Som med alle nyskapende webplattformfunksjoner, er det viktig å sjekke ressurser som CanIUse.com for den nyeste støtteinformasjonen.
Introduksjonen av denne teknologien markerer et betydelig skifte i webutvikling. Det gir designere og utviklere mulighet til å skape rike, interaktive og ytelseseffektive opplevelser deklarativt, og reduserer vår avhengighet av JavaScript for en hel klasse vanlige UI-mønstre. Etter hvert som nettleserstøtten modnes, kan vi forvente at rullestyrte animasjoner blir et essensielt verktøy i enhver front-end-utviklers verktøykasse.
Konklusjon
CSS Rullestyrte animasjoner, og spesifikt egenskapen animation-range, representerer et monumentalt sprang fremover for webanimasjon. Vi har beveget oss fra tidsbaserte tidslinjer til fremdriftsbaserte tidslinjer, noe som låser opp muligheten til å skape komplekse, rullebevisste interaksjoner med enestående ytelse og enkelhet.
Vi har lært at:
animation-timelinekobler en animasjon til enscroll()- ellerview()-fremdrifts-tidslinje.animation-rangegir oss presis kontroll, og kartlegger en spesifikk del av den tidslinjen til animasjonens nøkkelbilder.- Med
view()-tidslinjer gir kraftige navngitte områder somentry,exit,coverogcontainen intuitiv måte å kontrollere animasjoner basert på et elements synlighet. - Ved å holde oss til kompositt-vennlige egenskaper og tilby reserveplaner, kan vi bruke denne teknologien i dag for å bygge tilgjengelige, ytelseseffektive og herlige brukeropplevelser.
Dagene med å kjempe mot hakkete, hovedtråd-blokkerende rullelyttere for enkle effekter er talte. Fremtiden for rullebasert animasjon er her, den er deklarativ, og den er skrevet i CSS. Det er på tide å begynne å eksperimentere.