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

TL;DR

La proprietà CSS overscroll-behavior consente agli sviluppatori di ignorare il comportamento predefinito di scorrimento dell'overflow del browser quando raggiungono la parte superiore o inferiore dei contenuti. I casi d'uso includono la disattivazione della funzionalità pull-to-refresh su dispositivi mobili, la rimozione del bagliore dell'overscroll e degli effetti dell'effetto rubberbanding e la possibilità di impedire lo scorrimento dei contenuti della pagina quando si trovano sotto un modale/overlay.

Contesto

Limiti e concatenamento degli scorrimenti

Concatenamento con lo 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 originali del browser. Ad esempio, analizziamo un riquadro a scomparsa delle app con un gran numero di elementi che l'utente potrebbe dover scorrere. Quando raggiungono la parte inferiore, il contenitore overflow smette di scorrere perché non ci sono altri contenuti da consumare. In altre parole, l'utente raggiunge un "confine di scorrimento". Nota però cosa succede se l'utente continua a scorrere. I contenuti dietro il riquadro a scomparsa iniziano a scorrere. Lo scorrimento viene rilevato dal contenitore principale; la pagina principale nell'esempio.

Questo comportamento si chiama scroll chain; il comportamento predefinito del browser quando scorrono i contenuti. Spesso l'impostazione predefinita è piacevole, ma a volte non è desiderabile e nemmeno inaspettata. Alcune app potrebbero voler fornire un'esperienza utente diversa quando l'utente raggiunge il limite di scorrimento.

Effetto pull-to-refresh

Il pull-to-refresh è un gesto intuitivo reso popolare dalle app mobile come Facebook e Twitter. Trascinando e rilasciando un feed social, si crea un nuovo spazio per il caricamento di post più recenti. Di fatto, questa particolare UX è diventata talmente popolare che anche i browser mobile come Chrome su Android hanno adottato lo stesso effetto. Se scorri verso il basso nella parte superiore della pagina, viene aggiornata l'intera pagina:

Pull-to-refresh personalizzato di Twitter
durante l'aggiornamento di un feed nella PWA.
L'azione nativa di pull-to-refresh di Chrome Android
aggiorna l'intera pagina.

Per situazioni come la PWA di Twitter, potrebbe avere senso disabilitare l'azione nativa di pull-to-refresh. Perché? In questa app, probabilmente non vuoi che l'utente aggiorni accidentalmente la pagina. Inoltre, è possibile vedere un'animazione con doppio aggiornamento. In alternativa, potrebbe essere più utile personalizzare l'azione del browser, allineandola meglio al branding del sito. La parte sfortunata è che questo tipo di personalizzazione è difficile da completare. Gli sviluppatori finiscono per scrivere codice JavaScript non necessario, aggiungere ascoltatori touch non passivi (che bloccano lo scorrimento) o inserire l'intera pagina in un formato 100 vw/vh <div> (per evitare 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 scorri oltre un contenitore (compresa la pagina stessa). Puoi utilizzarla per annullare il concatenamento di scorrimento, disattivare/personalizzare l'azione pull-to-refresh, disattivare gli effetti del 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 le violazioni menzionate nell'introduzione.

La proprietà assume tre possibili valori:

  1. auto: impostazione predefinita. Gli scorrimenti che hanno origine dall'elemento possono propagarsi agli elementi predecessori.
  2. contain: impedisce il concatenamento dello scorrimento. Gli scorrimenti non si propagano ai predecessori, ma vengono mostrati gli effetti locali. Ad esempio, l'effetto di bagliore overscroll su Android o l'effetto elastico su iOS che avvisa l'utente quando raggiunge il limite di scorrimento. Nota: l'utilizzo di overscroll-behavior: contain sull'elemento html impedisce le azioni di navigazione overscroll.
  3. none: uguale a contain ma impedisce anche gli effetti overscroll all'interno del nodo stesso (ad es. bagliore overscroll per Android o rubberbanding di iOS).

Analizziamo alcuni esempi per capire come utilizzare overscroll-behavior.

Impedisci agli scorrimenti di uscire da un elemento con posizione fissa

Lo scenario del riquadro della chat

Anche i contenuti sotto la finestra della chat scorrono :(

Considera l'uso di un riquadro della chat con posizione fissa che si trova in fondo alla pagina. L'obiettivo è che il riquadro della chat sia un componente autonomo e che scorra separatamente dai contenuti sottostanti. Tuttavia, a causa del concatenamento dello scorrimento, il documento inizia a scorrere non appena l'utente tocca l'ultimo messaggio nella cronologia chat.

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

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

In sostanza, stiamo creando una separazione logica tra il contesto a scorrimento del riquadro della chat e la pagina principale. Il risultato finale è che la pagina principale rimane in posizione quando l'utente raggiunge la parte superiore o inferiore della cronologia chat. Gli scorrimenti che iniziano nella chatbox non si propagano.

Scenario overlay di pagina

Un'altra variante dello scenario "underscroll" è quando vedi contenuti che scorrono dietro un overlay in posizione fissa. Un gioco d'azzardo overscroll-behavior è in regola! Il browser sta cercando di essere utile, ma alla fine il sito sembra pieno di errori.

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

Disabilitazione del pull-to-refresh

La disattivazione dell'azione pull-to-refresh utilizza una singola riga di CSS. Basta evitare il concatenamento dell'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 animazioni di doppio pull-to-refresh nella demo della chatbox e possiamo implementare un effetto personalizzato che utilizza un'animazione di caricamento più ordinata. Inoltre, con l'aggiornamento, l'intera casella di posta si sfoca:

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="refresher">
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
</div>

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

<script>
  let _startY;
  const inbox = document.querySelector('#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.classList.contains('refreshing')) {
      // refresh inbox.
    }
  }, {passive: true});
</script>

Disattivazione degli effetti overscroll e rubberbanding

Per disattivare l'effetto di rimbalzo quando raggiungi 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 premi il limite di scorrimento, viene mostrato un bagliore.
Dopo: bagliore disattivato.

Demo completa

Combinando tutto, la demo della chatbox completa utilizza overscroll-behavior per creare un'animazione pull-to-refresh personalizzata e impedire agli scorrimenti di uscire dal widget della chatbox. Ciò fornisce un'esperienza utente ottimale, che sarebbe stata difficile da ottenere senza il CSS overscroll-behavior.

Visualizza demo | Fonte