Intestazione che si riduce durante lo scorrimento

Un'intestazione che si riduce durante lo scorrimento è un pattern UI comune in cui un elemento di intestazione fisso nella parte superiore della pagina passa gradualmente a dimensioni inferiori man mano che l'utente scorre verso il basso. Questo effetto viene spesso utilizzato per massimizzare lo spazio sullo schermo per i contenuti principali, mantenendo accessibili gli elementi di navigazione o gli elementi distintivi del brand essenziali. Con le animazioni basate sullo scorrimento CSS, questo effetto può essere ottenuto in modo dichiarativo e performante, collegando un'animazione alla posizione di scorrimento del documento.

Come implementare

Ecco come creare un'intestazione che si rimpicciolisce quando l'utente scorre la pagina:

  1. Crea un'intestazione fissa: inizia con un elemento di intestazione fissato nella parte superiore della pagina e con un'altezza predefinita.

    <header>HEADER</header>
    
    header {
      position: fixed;
      height: 200px;
      top: 0;
      left: 0;
      right: 0;
    }
    
  2. Definisci l'animazione di rimpicciolimento: crea un'animazione CSS che modifica l'altezza dell'intestazione.

    @keyframes shrink {
      to {
        height: 50px;
      }
    }
    
  3. Applica l'animazione e la sequenza temporale di scorrimento: collega l'animazione all'intestazione e utilizza la funzione scroll() per collegarla alla posizione di scorrimento del documento.

    header {
      animation: shrink auto linear both;
      animation-timeline: scroll(block root);
    }
    
  4. Imposta animation-range: utilizza la proprietà animation-range per specificare la distanza di scorrimento su cui deve avvenire l'animazione. Ad esempio, per ridurre l'intestazione nei primi 150 pixel di scorrimento, utilizza animation-range: 0px 150px;.

    header {
      animation-range: 0px 150px;
    }
    

Suggerimento: per evitare che i contenuti che seguono l'intestazione vengano oscurati da quest'ultima, aggiungi un padding-top a body (o al contenitore dei contenuti principali) pari all'altezza iniziale dell'intestazione.

Suggerimento: per assicurarti che i contenuti della pagina scorrano in sincronia con l'intestazione che si riduce, imposta animation-range-end sulla differenza tra le dimensioni di inizio e di fine. In questo modo, l'animazione viene completata esattamente quando l'intestazione raggiunge le dimensioni finali. In questa demo l'intestazione si riduce da 200px a 50px, quindi animation-range-end è impostato su 150px.

Esempio di codice

@keyframes shrink {
  to {
    height: 50px;
  }
}

header {
  animation: shrink auto linear both;
  animation-timeline: scroll(block root);
  animation-range: 0px 150px;
}

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()) and (animation-range: 0% 100%)) per verificare il supporto e fornire un'alternativa per i browser che non lo supportano.
    • Il controllo (animation-range: 0% 100%) DEVE essere incluso qui per filtrare i browser con supporto solo parziale.
    • 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Ì: 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 e animation-range 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).

Per quanto riguarda questo caso d'uso specifico:

  • L'elemento che animi NON deve essere position: static o position: relative quando utilizzi le percentuali in animation-range.
    • Questo perché questi elementi sono considerati "in-flow". Se li riduci durante lo scorrimento, la distanza di scorrimento totale si riduce, influendo sul valore calcolato, ad esempio, di 10% nello scorrimento.

Supporto del browser e strategie di riserva

Pertanto, in genere è necessaria una strategia 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 del documento su una distanza di 150px e aggiorna l'altezza dell'intestazione di conseguenza.

// Fallback for browsers that don't support scroll-driven animations
if (!CSS.supports('(animation-timeline: scroll()) and (animation-range: 0% 100%)')) {
  const header = document.querySelector('header');

  const initialHeight = 200;
  const finalHeight = 50;
  const scrollDistance = 150;

  window.addEventListener('scroll', () => {
    const scrollY = window.scrollY;
    const scrollPercent = Math.min(1, scrollY / scrollDistance);
    const newHeight = initialHeight - (initialHeight - finalHeight) * scrollPercent;

    header.style.height = `${newHeight}px`;
  });
}