Crea un indicatore di avanzamento dello scorrimento

Un indicatore di avanzamento dello scorrimento è un pattern di interfaccia utente comune che comunica visivamente l'avanzamento dell'utente in un documento o contenitore scorrevole. Mentre l'utente scorre, un elemento visivo si aggiorna per riflettere la sua posizione, fornendo un'idea chiara e intuitiva di quanti contenuti sono stati visualizzati e quanti ne rimangono.

Come implementare

Per creare un indicatore di avanzamento dello scorrimento, sono necessarie due cose:

  1. Un elemento che funge da barra di avanzamento. Questo elemento è in genere position: fixed o position: absolute in modo che rimanga visibile mentre l'utente scorre la pagina.
  2. Un'animazione collegata alla posizione di scorrimento.

Ecco come fare:

  • Innanzitutto, crea un elemento HTML che fungerà da barra di avanzamento. Questo elemento può essere personalizzato a tuo piacimento.
  • Poi, nel CSS, definisci un'animazione @keyframes che ridimensiona la barra di avanzamento. Un approccio comune consiste nello scalare l'elemento da scaleX(0) a scaleX(1).
  • Infine, applica questa animazione all'elemento della barra di avanzamento e imposta la proprietà animation-timeline su una cronologia di scorrimento. In questo modo, il browser viene istruito a gestire l'avanzamento dell'animazione in base alla posizione di scorrimento dello scroller predecessore più vicino.

Esempio di codice

Questo codice aumenta l'elemento #progress durante lo scorrimento utilizzando una cronologia di scorrimento anonima, creata dalla funzione 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();
    }
  }
}

A causa della sua posizione nel DOM, la funzione scroll() monitorerà lo scroller predecessore più vicino nella direzione block, che in questo caso è lo scroller principale.

<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>

Questo codice espande l'elemento #progress durante lo scorrimento utilizzando una cronologia di scorrimento denominata, creata dalla proprietà 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;
    }
  }
}

Best practice

Quando utilizzi le animazioni di scorrimento, è importante seguire alcune best practice per garantire un'esperienza fluida e accessibile:

  • SÌ: includi il rilevamento delle funzionalità. Non tutti i browser supportano le animazioni basate sullo scorrimento. Utilizza @supports (animation-timeline: scroll()) per verificare il supporto e fornire un'alternativa per i browser che non lo supportano.
    • NON utilizzare il pacchetto scroll-timeline-polyfill per la strategia di riserva, in quanto non è completo di funzionalità e presenta molti problemi noti.
    • Se l'animazione è considerata solo decorativa, opta per il potenziamento progressivo e NON fornire un fallback.
  • SÌ: rimuovi gli elementi puramente decorativi dai flussi di lettura delle tecnologie per la disabilità. Applica aria-hidden="true" agli indicatori di scorrimento puramente visivi per assicurarti che gli screen reader non incontrino nodi vuoti e senza nome.
  • SÌ: rispetta le preferenze degli utenti. Alcuni utenti preferiscono un movimento ridotto sul web. Utilizza la query supporti prefers-reduced-motion per disattivare o ridurre le animazioni per questi utenti.
  • SÌ: prova ad animare solo le proprietà CSS con prestazioni elevate. Per ottenere animazioni più fluide, limita l'animazione alle proprietà che possono essere gestite dal thread del compositore del browser, come transform e opacity. L'animazione di altre proprietà come width o height può causare problemi di prestazioni.
  • SÌ: utilizza l'ordine di dichiarazione corretto. Quando utilizzi la proprietà abbreviata animation, dichiara animation-timeline dopo per evitare che la proprietà abbreviata reimposti la sequenza temporale.

Quando utilizzi la funzione scroll() per creare un'animazione basata sullo scorrimento:

  • FACOLTATIVO Specifica lo scroller: se non scegli come target lo scroller dell'antenato più vicino, specifica lo scroller che vuoi utilizzare con scroll(root) o scroll(self).
    • Quando root, nearest o self non sono sufficienti, utilizza una cronologia di scorrimento con nome.
  • FACOLTATIVO Specifica l'asse da monitorare: se non scegli come target l'asse block predefinito (ad esempio in uno scroller orizzontale), specifica l'asse da monitorare con scroll(block) o scroll(inline).

Quando utilizzi la proprietà scroll-timeline per creare un'animazione basata sullo scorrimento:

  • SÌ: utilizza un CSS <dashed-ident> per il nome.
  • FACOLTATIVO Specifica l'asse da monitorare: se non scegli come target l'asse block predefinito (ad esempio in uno scroller orizzontale), specifica l'asse da monitorare con scroll-timeline-axis.
  • SÌ: assicurati che l'ambito della ricerca funzioni. Quando l'elemento che dichiara scroll-timeline non è un antenato dell'albero piatto dell'elemento animato, aumenta la visibilità del nome di scroll-timeline utilizzando timeline-scope su un antenato condiviso.

Strategie di riserva

Per i browser che non supportano le animazioni basate sullo scorrimento, puoi utilizzare un comportamento di riserva per ricreare gli effetti visivi. I fallback vengono in genere creati con un listener di scorrimento (per gli effetti ScrollTimeline) o con l'API IntersectionObserver (per gli effetti ViewTimeline).

Nei browser con supporto integrato per le animazioni basate sullo scorrimento, utilizza SEMPRE l'implementazione CSS nativa, in quanto è più efficiente.

Tieni presente che non tutti gli effetti possono essere ricreati utilizzando l'approccio dei fallback.

Per questo caso d'uso specifico, lo script seguente applica il comportamento di riserva per i browser che non supportano le animazioni basate sullo scorrimento. Utilizza un listener di scorrimento per monitorare la posizione di scorrimento dell'elemento root e aggiorna di conseguenza la proprietà transform della barra di avanzamento.

<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>