Een voortgangsindicator voor scrollen is een veelgebruikt patroon in de gebruikersinterface dat de voortgang van de gebruiker in een scrollbaar document of container visueel aangeeft. Terwijl de gebruiker scrollt, wordt een visueel element geüpdatet om de positie aan te geven. Zo krijgt de gebruiker een duidelijk en intuïtief idee van hoeveel content is bekeken en hoeveel er nog over is.
Hoe wordt dit geïmplementeerd
Als je een voortgangsindicator voor scrollen wilt maken, heb je 2 dingen nodig:
- Een element dat als voortgangsbalk fungeert. Dit element is meestal
position: fixedofposition: absolute, zodat het in beeld blijft terwijl de gebruiker scrollt. - Een animatie die is gekoppeld aan de scrollpositie.
Dat kun je op deze manieren doen:
- Maak eerst een HTML-element dat als voortgangsbalk dient. U kunt dit element naar wens opmaken.
- Definieer daarna in je CSS een
@keyframes-animatie die de voortgangsbalk schaalt. Een veelgebruikte aanpak is om het element te schalen vanscaleX(0)naarscaleX(1). - Pas deze animatie tot slot toe op het element van de voortgangsbalk en stel de
animation-timelinein op een scroll-tijdlijn. Hiermee wordt de browser geïnstrueerd om de voortgang van de animatie te bepalen op basis van de scrollpositie van de dichtstbijzijnde bovenliggende scroller.
Voorbeeldcode
Deze code vergroot het element #progress bij scrollen met een anonieme scroll-timeline, gemaakt door de functie scroll().
@media (prefers-reduced-motion: no-preference) {
@supports ((animation-timeline: scroll())) {
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
#progress {
position: fixed;
left: 0; top: 0;
width: 100%; height: 1em;
background: red;
transform-origin: 0 50%;
animation: grow-progress auto linear;
animation-timeline: scroll();
}
}
}
Vanwege de locatie in het DOM houdt de functie scroll() de dichtstbijzijnde bovenliggende scroller bij in de richting block, wat hier de hoofdscroller is.
<body>
<!-- MANDATORY: Purely decorative visual scroll progress bars MUST set aria-hidden="true" to remove the empty element from the assistive technology reading tree -->
<div id="progress" aria-hidden="true"></div>
</body>
Deze code vergroot het element #progress bij scrollen met een benoemde scroll-timeline, gemaakt door de property scroll-timeline.
@media (prefers-reduced-motion: no-preference) {
@supports ((animation-timeline: scroll())) {
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
:root {
scroll-timeline: --tl block;
}
#progress {
position: fixed;
left: 0; top: 0;
width: 100%; height: 1em;
background: red;
transform-origin: 0 50%;
animation: grow-progress auto linear;
animation-timeline: --tl;
}
}
}
Praktische tips
Als je scrollgestuurde animaties gebruikt, is het belangrijk dat je een aantal best practices volgt om een soepele en toegankelijke gebruikerservaring te bieden:
- WEL functiedetectie opnemen: Niet alle browsers ondersteunen scrollgestuurde animaties. Gebruik
@supports (animation-timeline: scroll())om te controleren op ondersteuning en een fallback te bieden voor browsers die dit niet ondersteunen.- Gebruik het
scroll-timeline-polyfill-pakket NIET voor de fallback-strategie, omdat het niet alle functies bevat en veel bekende problemen heeft. - Als de animatie alleen als decoratief wordt beschouwd, kies je voor progressive enhancement en bied je GEEN fallback.
- Gebruik het
- WEL: Verwijder puur decoratieve elementen uit de leesstromen van ondersteunende technologie. Pas
aria-hidden="true"toe op puur visuele scrollindicatoren om te zorgen dat schermlezers geen lege, naamloze knooppunten tegenkomen. - WEL: Respecteer gebruikersvoorkeuren. Sommige gebruikers geven de voorkeur aan minder beweging op het web. Gebruik de mediaquery
prefers-reduced-motionom je animaties uit te zetten of te verminderen voor deze gebruikers. - WEL proberen alleen animaties te maken voor presterende CSS-property's: Voor de soepelste animaties maak je alleen animaties voor property's die kunnen worden verwerkt door de compositor-thread van de browser, zoals
transformenopacity. Als je andere eigenschappen animeert, zoalswidthofheight, kan dit leiden tot prestatieproblemen. - Gebruik WEL de juiste declaratievolgorde: Als je de verkorte eigenschap
animationgebruikt, declareer jeanimation-timelineerna om te voorkomen dat de verkorte eigenschap de tijdlijn reset.
Als je de functie scroll() gebruikt om een scrollgestuurde animatie te maken, geldt het volgende:
- OPTIONEEL Wees expliciet over de scroller: Als je niet de dichtstbijzijnde bovenliggende scroller target, wees dan expliciet over welke scroller je wilt gebruiken met
scroll(root)ofscroll(self).- Als
root,nearestofselfniet voldoende zijn, gebruik je een benoemde scroll-timeline.
- Als
- OPTIONEEL Wees expliciet over de as die je wilt bijhouden: Als je niet de standaardas
blocktarget (zoals in een horizontale scroller), wees dan expliciet over welke as je wilt bijhouden metscroll(block)ofscroll(inline).
Als je de eigenschap scroll-timeline gebruikt om een scrollgestuurde animatie te maken:
- WEL een CSS
<dashed-ident>gebruiken voor de naam. - OPTIONEEL Wees expliciet over de as die moet worden bijgehouden: Als je niet de standaardas
blocktarget (zoals in een horizontale scroller), wees dan expliciet over welke as moet worden bijgehouden metscroll-timeline-axis. - Zorg dat het bereik van de zoekopdracht werkt: Als het element dat de
scroll-timelinedeclareert, geen voorouder van de platte structuur van het geanimeerde element is, verhoog je de zichtbaarheid van de naam van descroll-timelinedoortimeline-scopete gebruiken voor een gedeelde voorouder.
Reservestrategieën
Voor browsers die geen scrollgestuurde animaties ondersteunen, kun je een fallback gebruiken om de visuele effecten opnieuw te maken. De fallbacks worden meestal gemaakt met een scroll-listener (voor ScrollTimeline-effecten) of de IntersectionObserver API (voor ViewTimeline-effecten).
In browsers met ingebouwde ondersteuning voor scrollgestuurde animaties gebruik je ALTIJD de native CSS-implementatie, omdat die beter presteert.
Niet elk effect kan opnieuw worden gemaakt met de reserveaanpak.
Specifiek voor deze use case past het volgende script de fallback toe voor browsers die geen scrollgestuurde animaties ondersteunen. De functie gebruikt een scroll-listener om de scrollpositie van het hoofdelement bij te houden en updatet de eigenschap transform van de voortgangsbalk op basis daarvan.
<script>
if (!CSS.supports('animation-timeline', 'scroll()')) {
const progress = document.querySelector('#progress');
window.addEventListener('scroll', () => {
const scrollable = document.documentElement.scrollHeight - window.innerHeight;
const scrolled = window.scrollY;
const progressPercentage = (scrolled / scrollable);
progress.style.transform = `scaleX(${progressPercentage})`;
});
}
</script>