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

Résumé

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. Vous pouvez par exemple désactiver la fonctionnalité Extraire pour actualiser sur mobile, supprimer les effets de halo de défilement et d'élastique, et empêcher le contenu de la page de défiler lorsqu'il se trouve sous une modale ou une superposition.

Contexte

Limites de défilement et chaînage de défilement

Chaînage de défilement dans Chrome pour 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 panneau des applications contenant un grand nombre d'éléments que l'utilisateur devra peut-être faire défiler. Lorsqu'ils atteignent le bas, le conteneur de dépassement arrête le défilement, car il n'y a plus de contenu à utiliser. En d'autres termes, l'utilisateur atteint une "limite de défilement". Notez toutefois ce qui se passe si l'utilisateur continue de faire défiler la page. Le contenu derrière le panneau 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 est appelé chaînage de défilement, c'est-à-dire 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 offrir une expérience utilisateur différente lorsque l'utilisateur atteint une limite de défilement.

Effet "Tirez pour actualiser"

Pull-to-refresh 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 permettant de charger des posts plus récents. En fait, cette expérience utilisateur particulière est devenue si 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:

Fonctionnalité pull-to-refresh personnalisée de Twitter
lors de l'actualisation d'un flux dans sa PWA.
L'action d'actualisation native de Chrome pour Android
actualise la page entière.

Pour des situations telles que la PWA Twitter, il peut être judicieux de désactiver l'action native pull-to-refresh. Pourquoi ? Dans cette application, vous ne voulez probablement pas que l'utilisateur actualise accidentellement la page. Vous pouvez également voir une animation de double actualisation. Il peut également être plus pratique de personnaliser l'action du navigateur, en l'alignant plus étroitement sur le branding du site. Malheureusement, ce type de personnalisation a été difficile à effectuer. Les développeurs finissent par écrire du code JavaScript inutile, ajouter des écouteurs tactiles non passifs (qui bloquent le défilement) ou coller la page entière dans un <div> 100vw/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 de ce qui se passe 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 d'extraction pour actualiser, désactiver les effets d'élastique 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 provenant de l'élément peuvent se propager aux éléments ancêtres.
  2. contain : empêche les enchaînements de défilement. 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 lueur sur le défilement hors limites sur Android ou l'effet élastique 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 avec défilement hors limites.
  3. none : identique à contain, mais empêche également les effets de défilement hors limites dans le nœud lui-même (par exemple, le halo de défilement Android ou l'élastique élastique iOS).

Examinons quelques exemples pour voir comment utiliser overscroll-behavior.

Empêcher les défilements d'échapper 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 fenêtre de chat positionnée de façon fixe en bas de la page. L'objectif est que la fenêtre de chat soit un composant autonome et qu'elle défile indépendamment du contenu qui se trouve derrière. Toutefois, en raison de la chaîne de défilement, le document commence à défiler dès que l'utilisateur appelle 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;
}

Nous créons essentiellement une séparation logique entre le contexte de défilement de la fenêtre de chat et la page principale. Au final, la page principale reste affichée lorsque l'utilisateur atteint le haut/bas 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" 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 il finit par faire apparaître des bugs du site.

Exemple – modale 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 l'action Pull 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 <body>:

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

Grâce à cet ajout simple, nous corrigeons les animations de double extraction pour actualiser dans la démonstration de la boîte de dialogue et nous pouvons à la place implémenter un effet personnalisé utilisant une animation de chargement plus soignée. Toute la boîte de réception est également floutée lors de son 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: appuyer sur la limite de défilement affiche un halo.
Après: halo désactivé.

Démo complète

En résumé, la démonstration de la boîte de chat utilise overscroll-behavior pour créer une animation personnalisée de type "Pull-to-Refresh" et empêcher les défilements d'échapper le widget de la boîte de chat. Cela offre une expérience utilisateur optimale qu'il aurait été difficile d'obtenir sans CSS overscroll-behavior.

Voir la démonstration | Source