Assumi il controllo dello scorrimento personalizzando gli effetti pull-to-refresh e overflow

TL;DR

La proprietà CSS overscroll-behavior consente agli sviluppatori di eseguire l'override del comportamento di scorrimento dell'overflow predefinito del browser quando raggiungono la parte superiore/inferiore dei contenuti. I casi d'uso includono la disattivazione della funzionalità di pull to refresh sui dispositivi mobili, la rimozione degli effetti di overscroll glow e rubberbanding e la prevenzione dello scorrimento dei contenuti della pagina quando si trovano sotto un overlay/una finestra modale.

Sfondo

Limiti di scorrimento e concatenamento dello scorrimento

Concatenamento dello scorrimento su Chrome per Android.

Lo scorrimento è uno dei modi più fondamentali per interagire con una pagina, ma alcuni pattern UX possono essere difficili da gestire a causa dei comportamenti predefiniti particolari del browser. Ad esempio, prendi un riquadro a scomparsa delle app con un numero elevato di elementi che l'utente potrebbe dover scorrere. Quando raggiungono la parte inferiore, il contenitore di overflow interrompe lo scorrimento perché non ci sono più contenuti da visualizzare. In altre parole, l'utente raggiunge un "limite di scorrimento". Ma nota cosa succede se l'utente continua a scorrere. I contenuti dietro il riquadro a scomparsa iniziano a scorrere. Lo scorrimento viene assunto dal container principale, ovvero la pagina principale stessa nell'esempio.

Questo comportamento è chiamato concatenamento dello scorrimento ed è il comportamento predefinito del browser durante lo scorrimento dei contenuti. Spesso l'impostazione predefinita è piuttosto buona, ma a volte non è quella desiderata o è addirittura imprevista. Alcune app potrebbero voler offrire un'esperienza utente diversa quando l'utente raggiunge un limite di scorrimento.

L'effetto pull to refresh

Il pull to refresh è un gesto intuitivo reso popolare da app mobile come Facebook e Twitter. Se trascini verso il basso un feed social e lo rilasci, crei un nuovo spazio per caricare i post più recenti. In effetti, questa particolare UX è diventata così popolare che i browser mobile come Chrome su Android hanno adottato lo stesso effetto. Scorrendo verso il basso nella parte superiore della pagina, l'intera pagina viene aggiornata:

La funzionalità pull to refresh personalizzata di Twitter
quando si aggiorna un feed nella sua PWA.
L'azione nativa di pull to refresh di Chrome per Android
aggiorna l'intera pagina.

Per situazioni come la PWA di Twitter, potrebbe avere senso disattivare l'azione di pull to refresh nativa. Perché? In questa app, probabilmente non vuoi che l'utente aggiorni accidentalmente la pagina. C'è anche la possibilità di vedere un'animazione di aggiornamento doppia. In alternativa, potrebbe essere più utile personalizzare l'azione del browser, allineandola maggiormente al branding del sito. La parte sfortunata è che questo tipo di personalizzazione è stato difficile da realizzare. Gli sviluppatori finiscono per scrivere JavaScript non necessario, aggiungere listener touch non passivi (che bloccano lo scorrimento) o inserire l'intera pagina in un <div> 100vw/vh (per impedire l'overflow della pagina). Queste soluzioni alternative hanno effetti negativi ben documentati sulle prestazioni di scorrimento.

Possiamo fare di meglio.

Ti presentiamo overscroll-behavior

La proprietà overscroll-behavior è una nuova funzionalità CSS che controlla il comportamento di ciò che accade quando esegui lo scorrimento eccessivo di un container (inclusa la pagina stessa). Puoi utilizzarla per annullare il concatenamento dello scorrimento, disattivare/personalizzare l'azione di pull to refresh, disattivare gli effetti di rubberbanding su iOS (quando Safari implementa overscroll-behavior) e altro ancora. La parte migliore è che l'utilizzo di overscroll-behavior non influisce negativamente sulle prestazioni della pagina come gli hack menzionati nell'introduzione.

La proprietà accetta tre possibili valori:

  1. auto: predefinito. Gli scorrimenti che hanno origine sull'elemento possono propagarsi agli elementi principali.
  2. contain: impedisce il concatenamento dello scorrimento. Gli scorrimenti non si propagano agli elementi precedenti, ma vengono mostrati gli effetti locali all'interno del nodo. Ad esempio, l'effetto di overscroll glow su Android o l'effetto di rubberbanding su iOS, che avvisa l'utente quando ha raggiunto un limite di scorrimento. Nota: l'utilizzo di overscroll-behavior: contain sull'elemento html impedisce le azioni di navigazione con overscroll.
  3. none: come contain, ma impedisce anche gli effetti di overscroll all'interno del nodo stesso (ad es. l'effetto di overscroll di Android o l'effetto di rimbalzo di iOS).

Vediamo alcuni esempi per capire come utilizzare overscroll-behavior.

Impedisci lo scorrimento di un elemento con posizione fissa

Lo scenario della chatbox

Anche i contenuti sotto la finestra della chat scorrono :(

Considera una finestra di chat con posizione fissa nella parte inferiore della pagina. L'intenzione è che la chatbox sia un componente autonomo e che scorra separatamente dai contenuti dietro di essa. Tuttavia, a causa del concatenamento dello scorrimento, il documento inizia a scorrere non appena l'utente raggiunge l'ultimo messaggio nella cronologia chat.

Per questa app, è più appropriato che gli scorrimenti che hanno origine all'interno della chatbox rimangano all'interno della chat. Possiamo farlo aggiungendo overscroll-behavior: contain all'elemento che contiene i messaggi chat:

#chat .msgs {
  overflow: auto;
  overscroll-behavior: contain;
  height: 300px;
}

In sostanza, stiamo creando una separazione logica tra il contesto di scorrimento della chatbox e la pagina principale. Il risultato finale è che la pagina principale rimane ferma quando l'utente raggiunge l'inizio o la fine della cronologia chat. Gli scorrimenti che iniziano nella casella di chat non si propagano all'esterno.

Scenario di overlay della pagina

Un'altra variante dello scenario di "scorrimento sotto" si verifica quando vedi i contenuti scorrere dietro un overlay con posizione fissa. Un indizio evidente overscroll-behavior è d'obbligo! Il browser sta cercando di essere utile, ma finisce per far sembrare il sito difettoso.

Esempio: finestra modale con e senza overscroll-behavior: contain:

Prima: i contenuti della pagina scorrono sotto l'overlay.
Dopo: i contenuti della pagina non scorrono sotto l'overlay.

Disattivazione della funzionalità pull to refresh

La disattivazione dell'azione di pull to refresh è una singola riga di CSS. Basta impedire il concatenamento dello scorrimento sull'intero elemento che definisce l'area visibile. Nella maggior parte dei casi, si tratta di <html> o <body>:

body {
  /* Disables pull-to-refresh but allows overscroll glow effects. */
  overscroll-behavior-y: contain;
}

Con questa semplice aggiunta, correggiamo le doppie animazioni di pull to refresh nella demo della chatbox e possiamo invece implementare un effetto personalizzato che utilizza un'animazione di caricamento più ordinata. Anche l'intera posta in arrivo viene sfocata durante l'aggiornamento:

Prima
Dopo

Ecco uno snippet del codice completo:

<style>
  body.refreshing #inbox {
    filter: blur(1px);
    touch-action: none; /* prevent scrolling */
  }
  body.refreshing .refresher {
    transform: translate3d(0,150%,0) scale(1);
    z-index: 1;
  }
  .refresher {
    --refresh-width: 55px;
    pointer-events: none;
    width: var(--refresh-width);
    height: var(--refresh-width);
    border-radius: 50%;
    position: absolute;
    transition: all 300ms cubic-bezier(0,0,0.2,1);
    will-change: transform, opacity;
    ...
  }
</style>

<div class="refre>she<r"
  div class=&qu><ot;l>oad<ing-bar"/div
  div>< cla>ss=<"loading-bar"></div>
  <div class="loading><-bar>&<quot>;/<div
  div class=&q><uot;loading><-bar&quo>t;</div
/>div

section id="inbox"!-- msgs --/section

script
  let _startY;
  const inbox = document.querySel>ector('#inbox');

  inbox.addEventListener('touchstart', e = {
    _startY = e.touches>[0].pageY;
  }, {passive: true});

  inbox.addEventListener('touchmove', e = {
    const y = e.touches[0].pageY;
    // Activate custom pull-to-refresh effects when at the top of the container&&
  >  // and &&user is scrolling up.
    if (document.scrollingElement.scrollTop === 0  y  _startY 
        !document.body.class<List.co>ntains('refreshing')) {
      // refresh inbox.
    }
  }, {passive: true});
/script

Disattivazione degli effetti di overscroll glow e rubberbanding

Per disattivare l'effetto di rimbalzo quando si raggiunge un limite di scorrimento, utilizza overscroll-behavior-y: none:

body {
  /* Disables pull-to-refresh and overscroll glow effect.
     Still keeps swipe navigations. */
  overscroll-behavior-y: none;
}
Prima: quando si raggiunge il limite di scorrimento, viene mostrato un bagliore.
Dopo: bagliore disattivato.

Demo completa

Mettendo tutto insieme, la demo completa della chatbox utilizza overscroll-behavior per creare un'animazione di pull to refresh personalizzata e impedire che gli scorrimenti escano dal widget della chatbox. In questo modo, l'esperienza utente è ottimale, cosa che sarebbe stata difficile da ottenere senza CSS overscroll-behavior.

Visualizza demo | Origine