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 de glissement.

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 de glissement. Les articles paginés et les carrousels d'images sont deux exemples couramment utilisés. CSS Scroll Snap fournit une API simple et cohérente pour créer ces modèles d'UX populaires.

Contexte

Pourquoi utiliser le forçage du 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 d'accéder à plus d'informations que celles visibles à l'écran en même temps. Il devient particulièrement essentiel sur les plates-formes mobiles dont l'espace à l'écran est limité. Il n'est donc pas surprenant que les auteurs Web préfèrent de plus en plus organiser le contenu en listes plates à faire défiler plutôt qu'en 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 aligné sur un paragraphe ou une phrase. Cela est encore plus prononcé pour les contenus paginés ou détaillés avec des limites pertinentes lorsque le défilement se termine au milieu de la page ou de l'image, ce qui la laisse partiellement visible. Ces cas d'utilisation bénéficient d'une expérience de défilement bien contrôlée.

Les développeurs Web ont longtemps utilisé des solutions basées sur JavaScript pour contrôler le défilement afin de remédier à ce problème. Toutefois, les solutions basées sur JavaScript ne fournissent pas une solution de fidélité complète en raison de l'absence de primitives de personnalisation du défilement ou de l'accès au défilement composite. Le CSS Scroll Snap garantit une solution rapide, haute fidélité et facile à utiliser qui fonctionne de manière cohérente dans tous les navigateurs.

Le CSS Scroll Snap permet aux auteurs Web de marquer chaque conteneur de défilement avec des limites pour les opérations de défilement à terminer. Les navigateurs choisissent ensuite la position de fin la plus appropriée en fonction des détails 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'ancrage, puis l'animent de manière fluide. Pour revenir à notre exemple précédent, lorsque l'utilisateur a terminé de faire défiler le carrousel, l'image visible se met en place. Aucun ajustement de défilement n'est nécessaire par JavaScript.

Exemple d'utilisation de la fonction de blocage du défilement CSS avec un carrousel d'images.
Exemple d'utilisation de la fonction de blocage du défilement CSS avec un carrousel d'images. Ici, le forçage du 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

Le forçage du défilement consiste à ajuster le décalage de défilement d'un conteneur de défilement pour qu'il se trouve à une position de forçage préférée une fois l'opération de défilement terminée.

Vous pouvez activer le forçage du défilement pour un conteneur de défilement à l'aide de la propriété scroll-snap-type. Cela indique au navigateur qu'il doit envisager d'ancrer ce conteneur de défilement aux positions d'ancrage produites par ses descendants. scroll-snap-type détermine l'axe sur lequel le défilement se produit: x, y ou both, ainsi que la rigueur de l'ancrage: mandatory, proximity. Nous reviendrons sur ce point plus tard.

Vous pouvez créer une position d'ancrage en déclarant l'alignement souhaité sur un élément. Cette position correspond au décalage de défilement auquel le conteneur de défilement de l'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épart du point d'ancrage du conteneur de défilement doit être aligné sur le bord de départ de la zone d'ancrage de l'élément. De même, les alignements end et center signifient que le bord ou le centre de l'ancrage du conteneur de défilement doit être aligné avec le bord ou le centre de la zone d'ancrage de l'élément.

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

Les exemples suivants illustrent comment utiliser ces concepts.

Un cas d'utilisation courant du forçage de défilement est un carrousel d'images. Par exemple, pour créer un carrousel d'images horizontal qui s'ancre à chaque image lorsque vous faites défiler l'écran, vous pouvez spécifier que le conteneur de défilement doit comporter un scroll-snap-type obligatoire sur l'axe horizontal. Définissez chaque image sur scroll-snap-align: center pour vous assurer que l'ancrage 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 de repère sont associées à un élément, l'algorithme de repère peut déterminer de manière intelligente quand et comment il s'ancre en fonction de l'élément et de la taille du conteneur de défilement. Prenons l'exemple d'une image plus grande que le carrousel. Un algorithme de recadrage 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 cette image en s'arrêtant uniquement sur ses bords.

Voir la démonstration | Source

Exemple: page produit après parcours

Un autre cas courant pouvant bénéficier du forçage du défilement est celui des pages comportant plusieurs sections logiques à faire défiler 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 l'écran jusqu'au milieu d'une section particulière, mais il s'ancre également et attire l'attention sur une nouvelle section lorsqu'il fait défiler l'écran suffisamment près.

Pour ce faire, procédez comme suit:

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 supérieur fixe. La conception exigeait également que certaines parties de la section supérieure restent visibles lorsque le conteneur de défilement est épinglé afin de fournir aux utilisateurs un indice de conception sur le contenu situé au-dessus.

La propriété scroll-padding est une nouvelle propriété CSS qui permet d'ajuster la région visible effective du conteneur de défilement, ou snapport, qui est utilisé lors du calcul des alignements de repères de défilement. La propriété définit une marge intérieure par rapport à la zone de marge 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 le forçage du défilement. Lors de l'ancrage, le bord de départ de l'élément cible d'ancrage est aligné sur cette nouvelle position, ce qui laisse de l'espace au-dessus.

La propriété scroll-margin définit la valeur de décalage utilisée pour ajuster la zone effective de la cible d'ancrage, comme scroll-padding fonctionne sur le conteneur de défilement d'ancrage.

Vous avez peut-être remarqué que ces deux propriétés ne contiennent pas le mot "snap". Il s'agit d'un choix délibéré, car ils modifient réellement la zone pour toutes les opérations de défilement pertinentes et ne se limitent pas à l'ancrage du défilement. Par exemple, Chrome les prend en compte lors du calcul de la taille de page pour les opérations de défilement de pagination telles que PageDown et PageUp, ainsi que lors du calcul de la quantité de défilement pour l'opération Element.scrollIntoView().

Voir la démonstration | Source

Interaction avec d'autres API de défilement

API DOM Scrolling

Le forçage du défilement se produit après toutes les opérations de défilement, y compris celles lancées par 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'ancrage appropriée pour trouver l'emplacement final de l'ancrage. Par conséquent, le script utilisateur n'a pas besoin d'effectuer de calculs manuels pour l'ancrage.

Défilement fluide

Le défilement fluide contrôle le comportement d'une opération de défilement programmatique, tandis que le point d'ancrage du 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.

Comportement de défilement hors limites

L'API de comportement de défilement excessif contrôle la façon dont le défilement est enchaîné sur plusieurs éléments et n'est pas affecté par le point d'ancrage du défilement.

Mises en garde et bonnes pratiques

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

Dans de nombreux cas, le forçage du défilement peut être ajouté en tant qu'amélioration sans avoir à détecter les fonctionnalités. Si nécessaire, utilisez @supports ou CSS.supports pour détecter la prise en charge de la fonctionnalité 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 en 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 par programmation telles que Element.scrollTo se terminent toujours au décalage de défilement demandé. Le forçage du défilement peut ajuster le décalage de défilement une fois le défilement programmatique terminé. Notez que ce n'était pas une bonne hypothèse, même avant le glissement, car le défilement peut avoir été interrompu pour d'autres raisons, mais c'est particulièrement le cas avec le glissement.

Prochains ajouts

L'expérience de défilement a fait l'objet d'une enquête récente de l'équipe Chrome. Les résultats de l'enquête ont identifié plusieurs domaines qui nécessitent un travail supplémentaire pour réduire l'écart entre les bibliothèques de plug-ins et les CSS. Les prochains travaux seront axés sur scroll-snap, y compris:

  1. Disponibilité et compatibilité des API dans les différents navigateurs
  2. Travailler sur de nouvelles API CSS comme scroll-start
  3. Travaillez sur les nouveaux événements JavaScript, comme snapChanged().