Prenez le contrôle de votre défilement en personnalisant les effets d'actualisation et de dépassement.

TL;DR

La propriété overscroll-behavior CSS permet aux développeurs d'ignorer le comportement de défilement par défaut du navigateur lorsqu'ils atteignent le haut/bas du contenu. Les cas d'utilisation incluent la désactivation de la fonctionnalité de rafraîchissement par glissement sur mobile, la suppression des effets de lueur et de rebondissement lors du défilement, et l'empêchement du défilement du contenu de la page lorsqu'il se trouve sous un modal/une superposition.

Contexte

Limites de défilement et enchaînement de défilement

Chaînement de défilement sur Chrome Android.

Le défilement est l'un des moyens les plus fondamentaux d'interagir avec une page, mais certains modèles d'expérience utilisateur peuvent être difficiles à gérer en raison des comportements par défaut inhabituels du navigateur. Prenons l'exemple d'un tiroir d'applications contenant un grand nombre d'éléments que l'utilisateur peut avoir à faire défiler. Lorsqu'il arrive en bas, le conteneur de débordement cesse de défiler, car il n'y a plus de contenu à consommer. En d'autres termes, l'utilisateur atteint une "limite de défilement". Notez ce qui se passe si l'utilisateur continue de faire défiler l'écran. Le contenu derrière le panneau de navigation commence à défiler. Le défilement est géré par le conteneur parent, la page principale elle-même dans l'exemple.

Il s'avère que ce comportement s'appelle le chaînement de défilement, qui est le comportement par défaut du navigateur lors du défilement du contenu. Souvent, la valeur par défaut est très bien, mais parfois, elle n'est pas souhaitable, voire inattendue. Certaines applications peuvent souhaiter proposer une expérience utilisateur différente lorsque l'utilisateur atteint une limite de défilement.

Effet de l'actualisation par glissement

Le geste de balayage pour actualiser est un geste intuitif popularisé par les applications mobiles telles que Facebook et Twitter. Si vous faites glisser un flux de réseau social vers le bas et le relâchez, un nouvel espace est créé pour que les posts plus récents soient chargés. En fait, cette expérience utilisateur est devenue tellement populaire que les navigateurs mobiles tels que Chrome sur Android ont adopté le même effet. Balayez l'écran vers le bas en haut de la page pour actualiser l'ensemble de la page:

La fonctionnalité de balayage pour actualiser personnalisée de Twitter
lors de l'actualisation d'un flux dans sa PWA.
La fonctionnalité native de Chrome sur Android permettant de tirer pour actualiser
actualise l'intégralité de la page.

Dans des situations comme la PWA Twitter, il peut être judicieux de désactiver l'action native de balayage pour actualiser. Pourquoi ? Dans cette application, vous ne souhaitez probablement pas que l'utilisateur actualise accidentellement la page. Il est également possible d'afficher une animation de double actualisation. Il peut également être préférable de personnaliser l'action du navigateur, en l'alignant plus étroitement sur le branding du site. Malheureusement, ce type de personnalisation a été difficile à réaliser. Les développeurs finissent par écrire du code JavaScript inutile, ajouter des écouteurs tactiles non passifs (qui bloquent le défilement) ou coller l'intégralité de la page dans un <div> de 100 vw/vh (pour éviter que la page ne déborde). Ces solutions de contournement ont des effets négatifs bien documentés sur les performances de défilement.

Nous pouvons faire mieux !

Découvrez overscroll-behavior

La propriété overscroll-behavior est une nouvelle fonctionnalité CSS qui contrôle le comportement qui se produit lorsque vous faites défiler un conteneur (y compris la page elle-même). Vous pouvez l'utiliser pour annuler le chaînage de défilement, désactiver/personnaliser l'action de balayage pour actualiser, désactiver les effets de caoutchouc sur iOS (lorsque Safari implémente overscroll-behavior), etc. Le meilleur est que l'utilisation de overscroll-behavior n'a pas d'incidence négative sur les performances des pages, contrairement aux hacks mentionnés dans l'introduction.

La propriété peut prendre trois valeurs:

  1. auto : valeur par défaut. Les défilements qui proviennent de l'élément peuvent se propager aux éléments ancêtres.
  2. contain : empêche le défilement en chaîne. Les défilements ne se propagent pas aux ancêtres, mais les effets locaux au sein du nœud sont affichés. Par exemple, l'effet de lueur de défilement excessif sur Android ou l'effet de rebond sur iOS, qui avertit l'utilisateur lorsqu'il a atteint une limite de défilement. Remarque: L'utilisation de overscroll-behavior: contain sur l'élément html empêche les actions de navigation par défilement excessif.
  3. none : identique à contain, mais empêche également les effets de défilement hors limites dans le nœud lui-même (par exemple, l'effet de lueur de défilement hors limites sur Android ou le rebond sur iOS).

Examinons quelques exemples pour voir comment utiliser overscroll-behavior.

Empêcher le défilement de s'échapper d'un élément de position fixe

Scénario de la fenêtre de chat

Le contenu sous la fenêtre de chat défile également :(

Prenons l'exemple d'une boîte de chat fixe située en bas de la page. L'intention est que la boîte de chat soit un composant autonome et qu'elle défile séparément du contenu derrière elle. Toutefois, en raison de la liaison de défilement, le document commence à défiler dès que l'utilisateur appuie sur le dernier message de l'historique de chat.

Pour cette application, il est préférable que les défilements qui proviennent de la fenêtre de chat restent dans la fenêtre de chat. Pour ce faire, ajoutez overscroll-behavior: contain à l'élément qui contient les messages de chat:

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

En substance, nous créons une séparation logique entre le contexte de défilement de la boîte de chat et la page principale. Par conséquent, la page principale reste en place lorsque l'utilisateur atteint le début ou la fin de l'historique des discussions. Les défilements qui commencent dans la boîte de chat ne se propagent pas.

Scénario de superposition de page

Une autre variante du scénario "sous-défilement" se produit lorsque le contenu défile derrière un calque de position fixe. Un indice flagrant overscroll-behavior est de mise ! Le navigateur essaie d'être utile, mais cela donne l'impression que le site est buggé.

Exemple : modal avec et sans overscroll-behavior: contain :

Avant: le contenu de la page défile sous la superposition.
Après: le contenu de la page ne défile pas sous la superposition.

Désactiver le geste de balayage pour actualiser

Désactiver l'action de balayage pour actualiser ne nécessite qu'une seule ligne de code CSS. Il suffit d'empêcher l'enchaînement de défilement sur l'ensemble de l'élément définissant la vue. Dans la plupart des cas, il s'agit de <html> ou de <body>:

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

Avec cette simple addition, nous corrigeons les animations de double balayage pour actualiser dans la démonstration de la boîte de chat et pouvons implémenter un effet personnalisé qui utilise une animation de chargement plus soignée. L'ensemble de la boîte de réception est également flouté lors de l'actualisation:

Avant
Après

Voici un extrait du code complet:

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

Désactiver les effets de lueur et de rebondissement lors du défilement hors limites

Pour désactiver l'effet de rebond lorsque vous atteignez une limite de défilement, utilisez overscroll-behavior-y: none:

body {
  /* Disables pull-to-refresh and overscroll glow effect.
     Still keeps swipe navigations. */
  overscroll-behavior-y: none;
}
Avant: une lueur s'affiche lorsque vous atteignez la limite de défilement.
Après: la lueur est désactivée.

Démo complète

Pour résumer, la démo complète de la boîte de chat utilise overscroll-behavior pour créer une animation personnalisée de balayage pour actualiser et empêcher les défilements de s'échapper du widget de boîte de chat. Cela offre une expérience utilisateur optimale qui aurait été difficile à atteindre sans CSS overscroll-behavior.

Voir la démonstration | Source