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

Créez des expériences de défilement bien contrôlées en déclarant les positions d'ancrage du 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'ancrage du défilement. Les articles paginés et les carrousels d'images en 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. C'est le moyen natif de la plate-forme de fournir un accès à plus d'informations qu'il n'est visible à l'écran à la fois. Il devient donc particulièrement essentiel sur les plates-formes mobiles dont l'espace d'é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 déroulantes plates qu'il est possible de faire défiler, plutôt que sous forme de hiérarchies profondes.

Le principal inconvénient du défilement est son manque de précision. Il est rare qu'un défilement soit 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. CSS Scroll Snap assure une solution rapide, haute fidélité, facile à utiliser qui fonctionne de manière cohérente sur 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, son 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, l'ancrage du défilement garantit qu'à la fin du défilement, le centre horizontal de l'image est aligné sur le centre horizontal du conteneur de défilement.

CSS Scroll Snap

L'ancrage du défilement consiste à ajuster le décalage de défilement d'un conteneur de défilement à une position d'ancrage souhaité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 y reviendrons plus tard.

Vous pouvez obtenir une position d'ancrage 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 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ébut du port d'ancrage du conteneur de défilement doit être vidé avec le bord de début 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 d'ancrage du défilement est un carrousel d'images. Par exemple, pour créer un carrousel d'images horizontal qui s'aligne sur chaque image lors du défilement, nous pouvons 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 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 d'ancrage sont associées à un élément, l'algorithme d'ancrage 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. Par exemple, prenons le cas où une image est 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 l'image librement au sein de cette image, en ne s'alignant que sur ses bords.

Voir la démonstration | Source

Exemple : page produit après parcours

L'ancrage du défilement peut également être bénéfique pour les pages comportant plusieurs sections logiques à faire défiler verticalement (par exemple, une page de produit type). scroll-snap-type: y proximity; est plus adapté à ce type de cas. Cela n'interfère pas lorsqu'un utilisateur fait défiler la page jusqu'au milieu d'une section particulière, mais s'aligne également sur une nouvelle section 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, un encart supplémentaire 15vh a été ajouté 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'ancrage du défilement. Lors de l'ancrage, le bord de début de l'élément cible de l'ancrage est vidé avec cette nouvelle position, laissant ainsi de l'espace au-dessus.

La propriété scroll-margin définit le décalage utilisé pour ajuster la zone d'effet de la cible de l'ancrage, de la même manière que scroll-padding fonctionne sur le conteneur de défilement de l'ancrage.

Vous avez peut-être remarqué que ces deux propriétés ne contiennent pas le mot "snap". Cela est intentionnel, car ils modifient la zone pour toutes les opérations de défilement pertinentes et ne se limitent pas à l'ancrage du défilement. Par exemple, Chrome en tient compte lors du calcul de la taille de la page pour les opérations de défilement de pagination telles que Page suivante et Page précédente, 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 de défilement DOM

L'ancrage du défilement se produit après toutes les opérations de défilement, y compris celles déclenchées par le 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. Ainsi, il n'est pas nécessaire que le script utilisateur effectue des 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ètent.

Comportement de défilement hors limites

L'API de comportement du défilement hors limites contrôle la façon dont le défilement est chaîné sur plusieurs éléments. Elle n'est pas affectée par l'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. Par conséquent, le contenu situé entre les positions d'ancrage peut devenir 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 caractéristiques dans CSS

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

Détection de 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 l'ancrage du défilement, car le défilement peut avoir été interrompu pour d'autres raisons, mais c'est particulièrement le cas avec l'ancrage du défilement.

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 aspects nécessitant des efforts supplémentaires pour réduire l'écart entre les bibliothèques de plug-ins et les CSS. Les tâches à venir se concentreront sur scroll-snap, y compris sur:

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