Tworzenie wskaźnika postępu przewijania

Funkcje internetowe: Animacje sterowane przewijaniem

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:

  1. Element, który ma działać jako pasek postępu. Ten element jest zwykle position: fixed lub position: absolute, dzięki czemu pozostaje widoczny podczas przewijania.
  2. 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 od scaleX(0) do scaleX(1).
  • Na koniec zastosuj tę animację do elementu paska postępu i ustaw jego właściwość animation-timeline na 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-polyfill w 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.
  • 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 transform and opacity. Animowanie innych właściwości, takich jak width lub height, może powodować problemy z wydajnością.
  • DO use the correct declaration order: When using the animation shorthand property, declare animation-timeline after 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) lub scroll(self).
    • Jeśli root, nearest lub self nie wystarczą, użyj nazwanej osi czasu przewijania.
  • 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) lub scroll(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ść nazwy scroll-timeline, używając timeline-scope we 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>