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

TL;DR

La propriété CSS overscroll-behavior permet aux développeurs d'ignorer le comportement de défilement par défaut du navigateur lorsque le contenu est atteint en haut/en bas. 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 insolites du navigateur. Prenons l'exemple d'un tiroir d'applications contenant un grand nombre d'éléments que l'utilisateur peut être amené à 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 repris par le conteneur parent (la page principale 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 assez intéressante, mais parfois elle n'est ni souhaitable, ni même 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. En faisant glisser votre doigt vers le bas sur un flux de réseau social et en le publiant, vous créez un espace pour le chargement de posts plus récents. 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. En balayant le haut de la page vers le bas, toute la page est actualisée:

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 rafraîchir la page en tirant dessus
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. Vous pouvez également voir 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. Mieux encore, l'utilisation de overscroll-behavior n'a pas d'incidence négative sur les performances de la page, comme les astuces mentionnées dans l'introduction.

La propriété a trois valeurs possibles:

  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 en cas de défilement excessif sur Android ou l'effet de rebond sur iOS, qui avertit l'utilisateur lorsqu'il 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 chaîne de défilement, le document commence à défiler dès que l'utilisateur a appuyé sur le dernier message de l'historique des discussions.

Pour cette application, il est plus approprié de laisser les défilements provenant de la boîte de chat dans le 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. Au final, la page principale reste affichée lorsque l'utilisateur atteint le haut ou le bas de l'historique des discussions. Les défilements qui commencent dans la fenêtre de chat ne se propagent pas.

Scénario de superposition de page

Une autre variante du scénario "sous-défilement" est le défilement du contenu derrière une superposition à position fixe. Un cadeau overscroll-behavior est en ordre ! 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 tirage pour actualiser

La désactivation de l'action Pull-to-Refresh se limite à une seule ligne de code CSS. Empêchez simplement le défilement de s'enchaîner sur l'ensemble de l'élément définissant la fenêtre d'affichage. 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 d'éclat et d'élasticité 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