Wskaźnik postępu przewijania to typowy wzorzec interfejsu, który wizualnie informuje użytkownika o postępach w przewijaniu dokumentu lub kontenera. Gdy użytkownik przewija stronę, element wizualny aktualizuje się, aby odzwierciedlić jego pozycję, co pozwala mu łatwo i intuicyjnie sprawdzić, ile treści już wyświetlił, a ile jeszcze zostało.
Jak to zrobić?
Aby utworzyć wskaźnik postępu przewijania, potrzebujesz 2 rzeczy:
- Element, który ma działać jako pasek postępu. Ten element jest zwykle
position: fixedlubposition: absolute, dzięki czemu pozostaje widoczny podczas przewijania. - Animacja powiązana z pozycją przewijania.
Oto co możesz zrobić:
- Najpierw utwórz element HTML, który będzie służył jako pasek postępu. Możesz dostosować styl tego elementu do swoich potrzeb.
- Następnie w kodzie CSS zdefiniuj animację
@keyframes, która skaluje pasek postępu. Typowym podejściem jest skalowanie elementu odscaleX(0)doscaleX(1). - Na koniec zastosuj tę animację do elementu paska postępu i ustaw jego właściwość
animation-timelinena scroll-timeline. Dzięki temu przeglądarka może sterować postępem animacji na podstawie pozycji przewijania najbliższego elementu nadrzędnego.
Przykładowy kod
Ten kod powiększa element #progress podczas przewijania, używając anonimowej osi czasu przewijania utworzonej przez funkcję 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();
}
}
}
Ze względu na lokalizację w DOM funkcja scroll() będzie śledzić najbliższy element przewijany nadrzędny w kierunku block, którym w tym przypadku jest główny element przewijany.
<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>
Ten kod powiększa element #progress podczas przewijania, używając nazwanej osi czasu przewijania utworzonej przez właściwość 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;
}
}
}
Sprawdzone metody
Podczas korzystania z animacji sterowanych przewijaniem warto stosować kilka sprawdzonych metod, aby zapewnić płynne i dostępne działanie:
- DO include feature detection: Not all browsers support scroll-driven animations. Użyj
@supports (animation-timeline: scroll()), aby sprawdzić, czy jest obsługiwany, i zapewnić rozwiązanie zastępcze w przypadku przeglądarek, które go nie obsługują.- NIE używaj pakietu
scroll-timeline-polyfillw strategii zastępczej, ponieważ nie jest on kompletny i ma wiele znanych problemów. - Jeśli animacja ma charakter wyłącznie dekoracyjny, wybierz progresywne ulepszanie i NIE podawaj kreacji zastępczej.
- NIE używaj pakietu
- USUŃ elementy czysto dekoracyjne z procesów odczytu technologii wspomagających osoby z niepełnosprawnością: zastosuj
aria-hidden="true"do czysto wizualnych wskaźników przewijania, aby czytniki ekranu nie napotykały pustych, nienazwanych węzłów. - DO respect user preferences: Some users prefer to have less motion on the web. Użyj zapytania o media
prefers-reduced-motion, aby wyłączyć lub ograniczyć animacje dla tych użytkowników. - DO try to animate only performant CSS properties: For the smoothest animations, stick to animating properties that can be handled by the browser's compositor thread, such as
transformandopacity. Animowanie innych właściwości, takich jakwidthlubheight, może powodować problemy z wydajnością. - DO use the correct declaration order: When using the
animationshorthand property, declareanimation-timelineafter it to prevent the shorthand from resetting the timeline.
Gdy używasz funkcji scroll() do tworzenia animacji sterowanej przewijaniem:
- OPCJONALNIE Określ element przewijany: jeśli nie kierujesz na najbliższy element przewijany, określ, którego elementu przewijanego chcesz użyć, za pomocą
scroll(root)lubscroll(self).- Jeśli
root,nearestlubselfnie wystarczą, użyj nazwanej osi czasu przewijania.
- Jeśli
- OPCJONALNIE: określ oś, którą chcesz śledzić. Jeśli nie kierujesz reklam na domyślną oś
block(np. w przypadku poziomego paska przewijania), określ oś, którą chcesz śledzić, za pomocąscroll(block)lubscroll(inline).
Gdy używasz właściwości scroll-timeline do tworzenia animacji sterowanej przewijaniem:
- UŻYWAJ nazwy usługi porównywania cen
<dashed-ident>. - OPCJONALNIE: określ oś, którą chcesz śledzić. Jeśli nie kierujesz reklam na domyślną oś
block(np. w przypadku poziomego paska przewijania), określ, którą oś chcesz śledzić za pomocąscroll-timeline-axis. - ZADBAJ o to, aby zakres wyszukiwania działał: gdy element, który deklaruje
scroll-timeline, nie jest przodkiem elementu animowanego w płaskim drzewie, zwiększ widoczność nazwyscroll-timeline, używająctimeline-scopewe wspólnym przodku.
Strategie zastępcze
W przypadku przeglądarek, które nie obsługują animacji sterowanych przewijaniem, możesz użyć kreacji zastępczej, aby odtworzyć efekty wizualne. Kreacje zastępcze są zwykle tworzone za pomocą detektora przewijania (w przypadku efektów ScrollTimeline) lub interfejsu IntersectionObserver API (w przypadku efektów ViewTimeline).
W przeglądarkach z wbudowaną obsługą animacji opartych na przewijaniu ZAWSZE używaj natywnej implementacji CSS, ponieważ jest ona bardziej wydajna.
Pamiętaj, że nie każdy efekt można odtworzyć za pomocą kreacji zastępczych.
W tym konkretnym przypadku poniższy skrypt stosuje kreację zastępczą w przeglądarkach, które nie obsługują animacji sterowanych przewijaniem. Używa detektora przewijania do śledzenia pozycji przewijania elementu głównego i odpowiednio aktualizuje właściwość transform paska postępu.
<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>