Skapa silkeslena, högpresterande rullningsbaserade animationer med ren CSS. Denna guide täcker animation-timeline och animation-range för exakt kontroll.
CSS Animation Range: En djupdykning i kontroll av rullningsdrivna animationer
I åratal har skapandet av animationer som reagerar på en användares rullningsposition varit en hörnsten i engagerande webbupplevelser. Från subtila in-toningar till komplexa parallaxeffekter, ger dessa interaktioner liv åt statiska sidor. Dock har de traditionellt kommit med en betydande kostnad: beroendet av JavaScript. Bibliotek och anpassade skript som lyssnar på rullningshändelser kan vara prestandakrävande, köras på huvudtråden och potentiellt leda till hackiga, icke-responsiva användarupplevelser, särskilt på mindre kraftfulla enheter.
Nu inleds en ny era av webbanimation. De senaste framstegen inom CSS revolutionerar hur vi hanterar dessa interaktioner. Specifikationen för Rullningsdrivna animationer (Scroll-Driven Animations) erbjuder ett kraftfullt, deklarativt och högpresterande sätt att koppla animationer direkt till en rullningslists position eller ett elements synlighet i visningsområdet – allt utan en enda rad JavaScript.
Kärnan i detta nya paradigm är två viktiga egenskaper: animation-timeline och animation-range. Medan animation-timeline sätter scenen genom att definiera vad som driver animationen (t.ex. dokumentets rullningslist), är det animation-range som ger oss den granulära kontroll vi alltid har längtat efter. Det låter oss definiera de exakta start- och slutpunkterna för en animation inom den tidslinjen.
I denna omfattande guide kommer vi att utforska världen av CSS Rullningsdrivna animationer med ett särskilt fokus på animation-range. Vi kommer att täcka:
- De grundläggande koncepten för Rullnings- och Visningsförloppstidslinjer (Scroll and View Progress Timelines).
- En detaljerad genomgång av egenskapen
animation-rangeoch dess syntax. - Praktiska, verkliga exempel för att skapa förloppsindikatorer, avslöjande effekter och mer.
- Bästa praxis för prestanda, tillgänglighet och webbläsarkompatibilitet.
Gör dig redo att låsa upp animationer som inte bara är vackra utan också otroligt effektiva, genom att flytta komplex logik från huvudtråden till kompositortråden för en garanterat silkeslen upplevelse.
Förstå grunderna: Vad är rullningsdrivna animationer?
Innan vi dyker ner i animation-range är det avgörande att förstå systemet det verkar inom. Traditionellt är CSS-animationer knutna till en tidsbaserad tidslinje. När du definierar animation-duration: 3s;, fortskrider animationen från 0 % till 100 % över tre sekunder, driven av en klocka.
Rullningsdrivna animationer förändrar detta i grunden. De introducerar konceptet med en Förloppstidslinje (Progress Timeline), som inte drivs av tid, utan av förlopp – antingen förloppet av att rulla en behållare eller förloppet av ett elements synlighet när det rör sig genom visningsområdet.
Denna nya modell erbjuder tre stora fördelar:
- Prestanda: Eftersom dessa animationer kan köras utanför huvudtråden på webbläsarens kompositortråd, konkurrerar de inte om resurser med JavaScript, layout- eller målningsoperationer. Resultatet är exceptionellt mjuka animationer, fria från det hack som ofta plågar JS-baserade rullningslyssnare.
- Enkelhet: CSS-syntaxen är deklarativ. Du anger vad du vill ska hända, och webbläsaren hanterar de komplexa beräkningarna. Detta leder ofta till renare, mer underhållbar kod jämfört med imperativ JavaScript.
- Tillgänglighet: Animationerna respekterar användarinställningar som
prefers-reduced-motiondirekt från start, vilket gör det enklare att bygga inkluderande upplevelser.
Det finns två primära typer av förloppstidslinjer du kommer att arbeta med:
- Rullningsförloppstidslinje (Scroll Progress Timeline): Spårar rullningspositionen inom en rullningsbehållare (en "scroller"). Tidslinjen representerar hela det rullningsbara omfånget, från allra högst upp (0 %) till allra längst ner (100 %).
- Visningsförloppstidslinje (View Progress Timeline): Spårar ett elements synlighet när det korsar visningsområdet. Tidslinjen representerar elementets resa från att precis ha kommit in i visningsområdet till att helt ha lämnat det.
Kärnkonceptet: Egenskapen animation-timeline
Det första steget för att skapa en rullningsdriven animation är att koppla loss en standard CSS-animation från sin vanliga tidsbaserade klocka och fästa den vid en ny förloppsbaserad tidslinje. Detta görs med egenskapen animation-timeline.
Den accepterar en funktion som definierar källan för tidslinjen: antingen scroll() för en Rullningsförloppstidslinje eller view() för en Visningsförloppstidslinje.
Rullningsförloppstidslinje: scroll()
Funktionen scroll() knyter en animation till rullningspositionen för en behållare. Dess vanligaste form är scroll(scroller, axis).
scroller: Specificerar vilket rullningselement som ska spåras. Det kan vararoot(dokumentets visningsområde),self(elementet självt, om det är en rullningsbehållare), ellernearest(den närmaste förfadern som är en rullningsbehållare).axis: Specificerar vilken rullningsaxel som ska spåras. Det kan varablock(den primära riktningen för innehållsflödet, vanligtvis vertikal),inline(vinkelrätt mot block, vanligtvis horisontell),y, ellerx.
Exempel: En enkel förloppsindikator för dokumentrullning
Låt oss skapa en förloppsindikator högst upp på sidan som växer när användaren rullar ner.
<!-- 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;
/* Detach from time, attach to document scroll */
animation: grow-progress linear;
animation-timeline: scroll(root block);
}
I detta exempel drivs nu animationen grow-progress av rullningen av huvuddokumentet (root) på dess vertikala axel (block). När du rullar från 0 % till 100 % av sidan, går förloppsindikatorns scaleX-transformering från 0 till 1.
Visningsförloppstidslinje: view()
Funktionen view() knyter en animation till ett elements synlighet inom dess rullningsbehållare. Detta är otroligt användbart för att utlösa "avslöjande" animationer när element kommer i sikte.
Syntaxen är view(axis, inset).
axis: Valfri, samma värden som iscroll()(t.ex.block). Definierar vilken axel av visningsområdet som ska beaktas.inset: Valfri, låter dig justera gränserna för visningsområdet som används för att beräkna synlighet, liknandeIntersectionObserversrootMargin.
Exempel: Tona in ett element
<!-- HTML -->
<div class="content-box reveal">
This box will fade in as it enters the screen.
</div>
<!-- CSS -->
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
.reveal {
/* Attach animation to this element's visibility */
animation: fade-in linear;
animation-timeline: view();
}
Här är animationen fade-in kopplad till elementet .reveal självt. Animationen kommer att fortskrida när elementet färdas över visningsområdet. Men hur exakt mappas det? När börjar och slutar det? Det är där animation-range kommer in i bilden.
Stjärnan i showen: animation-range
Medan animation-timeline sätter kontexten, ger animation-range den kritiska kontrollen. Den definierar vilken del av tidslinjen som anses vara "aktiv" och mappar den till 0 % till 100 % förlopp av din @keyframes-animation.
Den grundläggande syntaxen är:
animation-range: <range-start> <range-end>;
Detta talar om för webbläsaren: "När tidslinjen når punkten <range-start>, ska animationen vara vid 0 %. När den når punkten <range-end>, ska animationen vara vid 100 %."
Värdena för <range-start> och <range-end> kan vara av flera olika typer:
- Nyckelord (för
view()): Speciella, mycket intuitiva namn somentry,exit,coverochcontain. Vi kommer att utforska dessa i detalj. - Procentandelar: En procentandel av tidslinjens totala varaktighet. För en
scroll()-tidslinje är0%toppen och100%är botten. - CSS-längder: Ett fast längdvärde som
100pxeller20rem. Detta specificerar en punkt vid den rullningsförskjutningen från början av tidslinjen.
Du kan till och med kombinera nyckelord med procentandelar eller längder för extremt finkornig kontroll, som entry 50% eller cover 200px.
Praktisk djupdykning: animation-range med scroll()-tidslinjer
När du arbetar med en scroll()-tidslinje, mappar du din animation till rullningsbehållarens totala rullningsomfång. Låt oss se hur animation-range hjälper oss att rikta in oss på specifika delar av den resan.
Att rikta in sig på en specifik rullningssektion
Föreställ dig att du har en lång artikel och vill att en specifik grafik ska animeras endast medan användaren rullar genom den mellersta halvan av sidan.
@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);
/* Animation starts at 25% scroll and ends at 75% scroll */
animation-range: 25% 75%;
}
Hur det fungerar:
- Innan användaren har rullat 25 % av sidan, hålls animationen i sitt 0 %-läge (
rotate(0deg) scale(0.5) opacity: 0). - När användaren rullar från 25 %-märket till 75 %-märket, fortskrider animationen från 0 % till 100 %.
- Efter att användaren har rullat förbi 75 %-märket, hålls animationen i sitt 100 %-läge (
rotate(360deg) scale(1) opacity: 1).
Detta enkla tillägg av animation-range ger oss kraftfull kontroll över tidpunkten och placeringen av våra effekter inom den större rullningsupplevelsen.
Använda absoluta längder
Du kan också använda absoluta längder. Till exempel, om du vill att en animation endast ska ske under de första 500 pixlarna av rullning:
.hero-animation {
animation: fade-out linear;
animation-timeline: scroll(root block);
/* Animation starts at scroll offset 0px and ends at 500px */
animation-range: 0px 500px;
}
Detta är perfekt för introduktionsanimationer i en sidas hero-sektion som bör avslutas när användaren har börjat rulla djupare in i innehållet.
Bemästra animation-range med view()-tidslinjer
Det är här animation-range blir verkligt magiskt. När det används med en view()-tidslinje, baseras inte omfångsvärdena på hela dokumentets rullningshöjd, utan på elementets synlighet inom visningsområdet. Det är här de speciella namngivna omfången kommer in i bilden.
De namngivna omfången förklarade
Föreställ dig ett element ("subjektet") och visningsområdet ("rullningsbehållaren"). De namngivna omfången beskriver förhållandet mellan dessa två rutor.
entry: Fasen där subjektet kommer in i visningsområdet. Den börjar i det ögonblick subjektets nederkant korsar visningsområdets nederkant och slutar när subjektets nederkant korsar visningsområdets nederkant.exit: Fasen där subjektet lämnar visningsområdet. Den börjar när subjektets överkant korsar visningsområdets överkant och slutar när subjektets överkant korsar visningsområdets nederkant.cover: Fasen där subjektet är tillräckligt stort för att helt täcka visningsområdet. Den börjar när subjektets överkant når visningsområdets överkant och slutar när subjektets nederkant når visningsområdets nederkant. Om subjektet är mindre än visningsområdet, inträffar denna fas aldrig.contain: Fasen där subjektet är helt inneslutet inom visningsområdet. Den börjar när subjektets nederkant kommer in i visningsområdets nederkant och slutar när subjektets överkant lämnar visningsområdets överkant. Om subjektet är större än visningsområdet, inträffar denna fas aldrig.
Praktiskt exempel: Den klassiska 'Avslöja vid rullning'-effekten
Låt oss återskapa en av de vanligaste rullningsbaserade animationerna: ett element som tonar och glider in i sikte när det kommer in på skärmen. Traditionellt krävde detta en Intersection Observer i JavaScript. Nu är det några rader 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 important! */
animation-timeline: view();
/* Start animation when element enters, end when it's halfway through entering */
animation-range: entry 0% entry 50%;
}
Låt oss bryta ner det där animation-range-värdet:
animation-fill-mode: both;är avgörande. Det säkerställer att innan animationens aktiva omfång, stannar elementet i sittfrom-läge (osynligt och nedflyttat), och efter omfånget, stannar det i sittto-läge (fullt synligt och på plats).entry 0%: Startpunkten. Detta refererar till själva början aventry-fasen – det exakta ögonblicket då botten av vårt element vidrör botten av visningsområdet.entry 50%: Slutpunkten. Detta refererar till det ögonblick då elementet har slutfört 50 % av sin resa genomentry-fasen. Vid denna punkt kommer animationen att vara 100 % slutförd.
Detta ger en behaglig effekt där objektet är fullt synligt och i sin slutliga position långt innan användaren har rullat det till mitten av skärmen. Du kan justera dessa procentandelar för att få exakt den känsla du vill ha. Till exempel skulle entry 25% entry 75% skapa en mer utdragen animation.
Avancerad kontroll: Skapa en parallaxeffekt
Låt oss prova en mer komplex effekt. Vi kommer att få en bakgrundsbild att röra sig med en annan hastighet än rullningen, men bara medan dess behållare täcker visningsområdet.
<!-- HTML -->
<div class="parallax-container">
<div class="parallax-bg"></div>
<h2>Parallax Section</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; /* Make it taller than container to allow movement */
background-image: url('your-image.jpg');
background-size: cover;
animation: parallax-shift linear both;
animation-timeline: view(block);
/* Animate across the entire 'cover' phase */
animation-range: cover 0% cover 100%;
}
I det här fallet är animationen parallax-shift knuten till elementet parallax-bgs tidslinje. animation-range är inställt på hela varaktigheten av cover-fasen. Detta innebär att animationen börjar fortskrida först när behållaren är tillräckligt hög för att täcka visningsområdet och är positionerad så att dess topp är vid visningsområdets topp. Den avslutas när behållarens botten når visningsområdets botten. Resultatet är en mjuk, högpresterande parallaxeffekt som är perfekt synkroniserad med rullningspositionen.
Kombinera allt: Kortkommandon och bästa praxis
Kortkommandot animation
För att göra syntaxen ännu mer koncis kan egenskaperna för tidslinje och omfång inkluderas direkt i kortkommandot animation. Detta är en ny, föreslagen syntax som vinner stöd.
Vårt exempel med 'avslöja vid rullning' skulle kunna skrivas om som:
.reveal {
animation: fade-and-slide-in linear both view() entry 0% entry 50%;
}
Denna enda rad ersätter de tre separata egenskaperna animation, animation-timeline och animation-range. Det är rent, effektivt och håller all animationslogik på ett ställe.
Prestandaöverväganden
Den primära fördelen med rullningsdrivna animationer är prestanda. För att bibehålla denna fördel bör du prioritera att animera egenskaper som kan hanteras av kompositortråden. Dessa är främst:
transform(translate, scale, rotate)opacity
Att animera egenskaper som width, height, margin, eller color kommer fortfarande att fungera, men de kan utlösa layout- och målningsoperationer, vilka sker på huvudtråden. Även om de fortfarande ofta är mjukare än JS-baserade alternativ, kommer de inte vara lika högpresterande som animationer som endast körs på kompositortråden.
Tillgänglighet och fallbacks
Det är avgörande att bygga för alla användare. Rullningsdrivna animationer är fantastiska, men vissa användare tycker att rörelse är distraherande eller illamåendeframkallande.
1. Respektera användarinställningar: Omslut alltid din rörelserelaterade CSS i en prefers-reduced-motion media-fråga.
@media (prefers-reduced-motion: no-preference) {
.reveal {
animation: fade-and-slide-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
}
2. Tillhandahåll fallbacks för äldre webbläsare: Eftersom detta är en ny teknik måste du ta hänsyn till webbläsare som ännu inte stöder den. Regeln @supports är din bästa vän här. Tillhandahåll ett enkelt, icke-animerat standardläge, och förbättra det sedan för webbläsare som har stöd.
/* Default state for all browsers */
.reveal {
opacity: 1;
transform: translateY(0);
}
/* Enhancement for supporting browsers */
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
.reveal {
opacity: 0; /* Set initial state for animation */
transform: translateY(50px);
animation: fade-and-slide-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
}
}
Webbläsarstöd och framtiden
I slutet av 2023 stöds CSS Rullningsdrivna animationer i Chrome och Edge. De är under aktiv utveckling i Firefox och övervägs av Safari. Som med alla banbrytande webbplattformsfunktioner är det viktigt att kontrollera resurser som CanIUse.com för den senaste supportinformationen.
Introduktionen av denna teknik markerar ett betydande skifte inom webbutveckling. Det ger designers och utvecklare möjlighet att skapa rika, interaktiva och högpresterande upplevelser deklarativt, vilket minskar vårt beroende av JavaScript för en hel klass av vanliga UI-mönster. Allt eftersom webbläsarstödet mognar kan vi förvänta oss att se rullningsdrivna animationer bli ett oumbärligt verktyg i varje front-end-utvecklares verktygslåda.
Slutsats
CSS Rullningsdrivna animationer, och specifikt egenskapen animation-range, representerar ett monumentalt steg framåt för webbanimation. Vi har gått från tidsbaserade tidslinjer till förloppsbaserade tidslinjer, vilket låser upp förmågan att skapa komplexa, rullningsmedvetna interaktioner med oöverträffad prestanda och enkelhet.
Vi har lärt oss att:
animation-timelinelänkar en animation till enscroll()- ellerview()-förloppstidslinje.animation-rangeger oss exakt kontroll, och mappar en specifik del av den tidslinjen till vår animations keyframes.- Med
view()-tidslinjer ger kraftfulla namngivna omfång somentry,exit,coverochcontainett intuitivt sätt att kontrollera animationer baserat på ett elements synlighet. - Genom att hålla oss till kompositortrådsvänliga egenskaper och tillhandahålla fallbacks kan vi använda denna teknik idag för att bygga tillgängliga, högpresterande och förtjusande användarupplevelser.
Dagarna då vi kämpade med hackiga, huvudtrådsblockerande rullningslyssnare för enkla effekter är räknade. Framtiden för rullningsbaserad animation är här, den är deklarativ, och den är skriven i CSS. Det är dags att börja experimentera.