Défilement bien contrôlé avec CSS Scroll Snap

Créez des expériences de défilement bien contrôlées en déclarant des positions d'accrochage au défilement.

Robert Flack
Robert Flack
Majid Valipour
Majid Valipour

La fonctionnalité CSS Scroll Snap permet aux développeurs Web de créer des expériences de défilement bien contrôlées en déclarant des positions d'accrochage au défilement. Les articles paginés et les carrousels d'images en sont deux exemples courants. CSS Scroll Snap fournit une API simple et cohérente pour créer ces modèles UX populaires.

Arrière-plan

Les avantages de l'accrochage au défilement

Le défilement est un moyen populaire et naturel d'interagir avec le contenu sur le Web. Il s'agit du moyen natif de la plate-forme pour fournir un accès à plus d'informations que celles visibles à l'écran à la fois, ce qui devient particulièrement important sur les plates-formes mobiles avec un espace d'écran limité. Il n'est donc pas surprenant que les auteurs Web préfèrent de plus en plus organiser le contenu dans des listes plates à faire défiler plutôt que dans des hiérarchies profondes.

Le principal inconvénient du défilement est son manque de précision. Il est rare qu'un défilement se termine sur un paragraphe ou une phrase. Cela est encore plus flagrant pour les contenus paginés ou listés avec des limites significatives lorsque le défilement s'arrête au milieu de la page ou de l'image, la laissant partiellement visible. Ces cas d'utilisation bénéficient d'une expérience de défilement bien contrôlée.

Les développeurs Web s'appuient depuis longtemps sur des solutions basées sur JavaScript pour contrôler le défilement et pallier cette lacune. Toutefois, les solutions basées sur JavaScript ne permettent pas d'obtenir une solution entièrement fidèle en raison du manque de primitives de personnalisation du défilement ou d'accès au défilement composite. CSS Scroll Snap garantit une solution rapide, de haute qualité et facile à utiliser, qui fonctionne de manière cohérente sur tous les navigateurs.

CSS Scroll Snap permet aux auteurs Web de marquer chaque conteneur de défilement avec des limites pour les opérations de défilement à la fin. Les navigateurs choisissent ensuite la position finale la plus appropriée en fonction des spécificités de l'opération de défilement, de la mise en page et de la visibilité du conteneur de défilement, ainsi que des détails des positions d'accrochage, puis l'animent en douceur. Pour revenir à notre exemple précédent, lorsque l'utilisateur termine de faire défiler le carrousel, l'image visible se met en place. Aucun ajustement de défilement n'est nécessaire en JavaScript.

Exemple d'utilisation de l'accrochage de défilement CSS avec un carrousel d'images.
Exemple d'utilisation de l'accrochage de défilement CSS avec un carrousel d'images. Ici, l'accrochage au défilement garantit qu'à la fin du défilement, le centre horizontal d'une image est aligné sur le centre horizontal du conteneur de défilement.

CSS Scroll Snap

L'accrochage au défilement consiste à ajuster le décalage de défilement d'un conteneur de défilement pour qu'il se trouve à une position d'accrochage préférée une fois l'opération de défilement terminée.

Un conteneur de défilement peut être activé pour l'accrochage de défilement à l'aide de la propriété scroll-snap-type. Cela indique au navigateur qu'il doit envisager d'aligner ce conteneur de défilement sur les positions d'accrochage produites par ses descendants. scroll-snap-type détermine l'axe sur lequel le défilement se produit (x, y ou both) et la rigueur de l'accrochage (mandatory, proximity). Nous y reviendrons plus tard.

Une position d'accrochage peut être produite en déclarant un alignement souhaité sur un élément. Cette position correspond au décalage de défilement auquel le conteneur de défilement ancêtre le plus proche et l'élément sont alignés comme spécifié pour l'axe donné. Les alignements suivants sont possibles sur chaque axe : start, end, center.

Un alignement start signifie que le bord de début de la zone d'accrochage du conteneur de défilement doit être aligné sur le bord de début de la zone d'accrochage de l'élément. De même, les alignements end et center signifient que le bord de fin ou le centre du port d'affichage du conteneur de défilement doivent être alignés sur le bord de fin ou le centre de la zone d'accrochage de l'élément.

Exemple de différents alignements sur l'axe de défilement horizontal.

Les exemples suivants illustrent l'utilisation de ces concepts.

Un cas d'utilisation courant du forçage de l'alignement sur un point de défilement est un carrousel d'images. Par exemple, pour créer un carrousel d'images horizontal qui s'arrête sur chaque image lorsque vous faites défiler l'écran, nous pouvons spécifier que le conteneur de défilement doit avoir un scroll-snap-type obligatoire sur l'axe horizontal et définir chaque image sur scroll-snap-align: center pour nous assurer que l'arrêt centre l'image dans le carrousel.

#gallery {
  scroll-snap-type: x mandatory;
  overflow-x: scroll;
  display: flex;
}

#gallery img {
   scroll-snap-align: center;
}
<div id="gallery">
  <img src="cat.jpg">
  <img src="dog.jpg">
  <img src="another_cute_animal.jpg">
</div>

Étant donné que les positions d'accrochage sont associées à un élément, l'algorithme d'accrochage peut déterminer de manière intelligente quand et comment accrocher l'élément en fonction de sa taille et de celle du conteneur de défilement. Prenons l'exemple d'une image plus grande que le carrousel. Un algorithme d'accrochage naïf peut empêcher l'utilisateur de faire un panoramique pour voir l'image complète. Toutefois, la spécification exige que les implémentations détectent ce cas et permettent à l'utilisateur de faire défiler librement l'image, en s'arrêtant uniquement à ses bords.

Exemple : une page produit avec parcours

Un autre cas d'utilisation courant du scroll snapping concerne les pages comportant plusieurs sections logiques à parcourir verticalement, par exemple une page produit typique. scroll-snap-type: y proximity; est plus adapté à ce type de cas. Il n'interfère pas lorsqu'un utilisateur fait défiler la page jusqu'au milieu d'une section spécifique, mais il s'accroche et attire l'attention sur une nouvelle section lorsqu'il fait défiler la page suffisamment près.

Voici comment procéder :

article {
  scroll-snap-type: y proximity;
  /* Reserve space for header plus some extra space for sneak peeking. */
  scroll-padding-top: 15vh;
  overflow-y: scroll;
}
section {
  /* Snap align start. */
  scroll-snap-align: start;
}
header {
  position: fixed;
  height: 10vh;
}
<article>
  <header> Header </header>
  <section> Section One </section>
  <section> Section Two </section>
  <section> Section Three </section>
</article>

Marge intérieure et marge de défilement

La page produit comporte un en-tête fixe en haut de la page. La conception demandait également à ce qu'une partie de la section supérieure reste visible lorsque le conteneur de défilement est ancré afin de fournir aux utilisateurs un indice de conception sur le contenu ci-dessus.

La propriété scroll-padding est une nouvelle propriété CSS qui peut être utilisée pour ajuster la région visible effective du conteneur de défilement ou du snapport, qui est utilisé lors du calcul des alignements d'accrochage de défilement. La propriété définit un encart par rapport à la zone de marge intérieure du conteneur de défilement. Dans notre exemple, une marge intérieure supplémentaire de 15vh a été ajoutée en haut, ce qui indique au navigateur de considérer une position inférieure, 15vh sous le bord supérieur du conteneur de défilement, comme bord de début vertical pour l'accrochage au défilement. Lors de l'accrochage, le bord de début de l'élément cible d'accrochage sera aligné sur cette nouvelle position, laissant ainsi de l'espace au-dessus.

La propriété scroll-margin définit la marge extérieure utilisée pour ajuster la boîte effective de la cible d'accrochage, de la même manière que scroll-padding fonctionne sur le conteneur de défilement par accrochage.

Vous avez peut-être remarqué que ces deux propriétés ne contiennent pas le mot "snap". C'est intentionnel, car ils modifient réellement la boîte pour toutes les opérations de défilement pertinentes et ne sont pas uniquement des accroches de défilement. Par exemple, Chrome en tient compte lorsqu'il calcule la taille de la page pour les opérations de défilement par page telles que Page Suivante et Page Précédente, ainsi que lorsqu'il calcule la quantité de défilement pour l'opération Element.scrollIntoView().

Interaction avec d'autres API de défilement

API de défilement DOM

L'accrochage au défilement se produit après toutes les opérations de défilement, y compris celles initiées par un script. Lorsque vous utilisez des API telles que Element.scrollTo, le navigateur calcule la position de défilement prévue de l'opération, puis applique la logique d'accrochage appropriée pour trouver la position d'accrochage finale. Il n'est donc pas nécessaire que le script utilisateur effectue des calculs manuels pour l'accrochage.

Défilement fluide

Le défilement fluide contrôle le comportement d'une opération de défilement programmatique, tandis que l'alignement sur les points d'arrêt de défilement détermine sa destination. Étant donné qu'ils contrôlent des aspects orthogonaux du défilement, ils peuvent être utilisés ensemble et se compléter mutuellement.

Comportement de défilement hors limites

L'API Overscroll behavior contrôle la façon dont le défilement est enchaîné sur plusieurs éléments. Elle n'est pas affectée par l'accrochage de défilement.

Mises en garde et bonnes pratiques

Évitez d'utiliser l'accrochage obligatoire lorsque les éléments cibles sont très espacés. Cela peut rendre le contenu entre les positions d'accrochage inaccessible.

Dans de nombreux cas, l'accrochage au défilement peut être ajouté comme amélioration sans avoir besoin de détecter les fonctionnalités. Si nécessaire, utilisez @supports ou CSS.supports pour détecter la compatibilité avec CSS Scroll Snap. Évitez d'utiliser scroll-snap-type, qui est également présent dans la spécification obsolète.

Détection de fonctionnalités dans CSS

@supports (scroll-snap-align: start) {
  article {
    scroll-snap-type: y proximity;
    scroll-padding-top: 15vh;
    overflow-y: scroll;
  }
}

Détection des fonctionnalités en JavaScript

if (CSS.supports('scroll-snap-align: start')) {
  // use css scroll snap
} else {
  // use fallback
}

Ne partez pas du principe que les API de défilement programmatique telles que Element.scrollTo se terminent toujours au décalage de défilement demandé. L'accrochage au défilement peut ajuster le décalage de défilement une fois le défilement programmatique terminé. Notez qu'il ne s'agissait pas d'une bonne hypothèse, même avant l'accrochage au défilement, car le défilement pouvait être interrompu pour d'autres raisons, mais c'est particulièrement le cas avec l'accrochage au défilement.

Prochains ajouts

L'expérience de défilement était au centre d'une récente enquête de l'équipe Chrome. Les résultats de l'étude ont identifié plusieurs domaines qui nécessitent des efforts supplémentaires pour réduire l'écart entre les bibliothèques de plug-ins et le CSS. Les prochains travaux porteront sur scroll-snap, y compris :

  1. Disponibilité et compatibilité de l'API avec les navigateurs.
  2. Travaillez sur de nouvelles API CSS comme scroll-start.
  3. Travaillez sur de nouveaux événements JS comme snapChanged().