Créer un composant "Stories"

Découvrez comment créer une expérience semblable aux stories Instagram sur le Web.

Dans cet article, je vais vous expliquer comment créer un composant Stories pour le Web. Il doit être responsif, compatible avec la navigation au clavier et compatible avec tous les navigateurs.

Démonstration

Si vous préférez suivre une démonstration pratique de la création de ce composant Stories, consultez l'atelier de programmation du composant Stories.

Si vous préférez la vidéo, voici une version YouTube de ce post:

Présentation

Les stories Snapchat et Instagram (sans oublier les flottes) sont deux exemples populaires d'expérience utilisateur pour les stories. De manière générale, les stories se présentent sous la forme d'une interface tactile permettant de parcourir plusieurs abonnements, uniquement sur mobile. Par exemple, sur Instagram, les utilisateurs ouvrent l'histoire d'un ami et parcourent les photos qu'elle contient. En général, ils font autant d'amis à la fois. En appuyant sur le côté droit de l'appareil, l'utilisateur passe à l'histoire suivante de cet ami. En balayant l'écran vers la droite, un utilisateur passe directement à un autre ami. Un composant Story est assez semblable à un carrousel, mais il permet de naviguer dans un tableau multidimensionnel par opposition à un tableau à une seule dimension. C'est comme s'il y avait un carrousel à l'intérieur de chaque carrousel. 🤯

Visualisation d'un tableau multidimensionnel à l'aide de cartes De gauche à droite se trouve une pile de cartes avec bordures violettes et à l'intérieur de chaque carte se trouvent une ou plusieurs cartes cyan avec bordure. Liste dans une liste.
Premier carrousel d'amis
2e carrousel d'histoires empilé
👍 Liste sous forme de liste, également appelée tableau multidimensionnel

Choisir les bons outils pour une tâche

Dans l'ensemble, j'ai trouvé ce composant assez simple à créer, grâce à quelques fonctionnalités essentielles de la plate-forme Web. C'est parti !

Grille CSS

Notre mise en page s'est avérée peu complexe pour la grille CSS, car elle est dotée de moyens efficaces pour superposer le contenu.

Présentation des amis

Notre principal wrapper de composant .stories est une vue de défilement horizontale orientée mobile:

.stories {
  inline-size: 100vw;
  block-size: 100vh;

  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;

  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}

/* desktop constraint */
@media (hover: hover) and (min-width: 480px) {
  max-inline-size: 480px;
  max-block-size: 848px;
}
Utiliser le mode Appareil des outils pour les développeurs Chrome pour mettre en évidence les colonnes créées par la grille

Récapitulons cette mise en page grid:

  • Nous remplissons explicitement la fenêtre d'affichage sur mobile avec 100vh et 100vw, et limitons la taille sur les ordinateurs.
  • / sépare nos modèles de ligne et de colonne
  • auto-flow correspond à grid-auto-flow: column
  • Le modèle de flux automatique est 100%, qui correspond ici à la largeur de la fenêtre de défilement.

Sur un téléphone mobile, considérez cela comme la taille de ligne correspondant à la hauteur de la fenêtre d'affichage et chaque colonne à la largeur de la fenêtre d'affichage. Pour continuer avec les stories Snapchat et Instagram, chaque colonne sera celle d'un ami. Nous voulons que les histoires d'amis se poursuivent en dehors de la fenêtre d'affichage. Nous devons donc faire défiler la page jusqu'à un endroit. La grille crée le nombre de colonnes dont elle a besoin pour mettre en page votre code HTML pour chaque récit, créant ainsi un conteneur à défilement dynamique et responsif. La grille nous a permis de centraliser l'ensemble de l'effet.

Empilement

Nous avons besoin que les histoires de chaque ami soient prêtes à être paginées. Pour préparer l'animation et suivre d'autres tendances amusantes, j'ai choisi une pile. Quand je dis empiler, je veux dire que vous regardiez un sandwich par le bas, pas comme si vous regardiez de côté.

Avec la grille CSS, nous pouvons définir une grille à une seule cellule (c'est-à-dire un carré), dans laquelle les lignes et les colonnes partagent un alias ([story]), puis chaque enfant est affecté à cet espace à une seule cellule aliasé:

.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.story {
  grid-area: story;
  background-size: cover;
  …
}

Cela permet à notre code HTML de contrôler l'ordre d'empilement et permet également de maintenir le flux de tous les éléments. Notez que nous n'avons rien à faire avec le positionnement de absolute ou z-index, et que nous n'avons pas besoin d'encadrer correctement avec height: 100% ou width: 100%. La grille parente définit déjà la taille de la fenêtre d'affichage de l'image de l'histoire. Il n'est donc pas nécessaire de dire à ces composants pour la remplir.

Points d'ancrage de défilement CSS

La spécification des points d'ancrage de défilement CSS permet de verrouiller facilement des éléments dans la fenêtre d'affichage lors du défilement. Avant que ces propriétés CSS n'existent, il fallait utiliser JavaScript, et c'était... pour le moins délicat. Lisez l'article Présentation des points d'ancrage CSS Scroll de Sarah Drasner pour en savoir plus sur leur utilisation.

Défilement horizontal sans et avec les styles scroll-snap-points. Sans cela, les utilisateurs peuvent faire défiler l'écran comme d'habitude. Avec elle, le navigateur repose doucement sur chaque élément.
parent
.stories {
  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}
Le parent avec défilement hors limites définit le comportement d'ancrage.
enfant
.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
Les enfants ont la possibilité d'être des cibles d'ancrage.

J'ai choisi les points d'ancrage de défilement pour plusieurs raisons:

  • Accessibilité sans frais : La spécification de défilement des points d'ancrage indique que le fait d'appuyer sur les touches Flèche vers la gauche et Flèche vers la droite doit passer d'un point d'ancrage à l'autre par défaut.
  • Une spécification qui ne cesse de s'améliorer : la spécification des points d'ancrage de défilement bénéficie constamment de nouvelles fonctionnalités et améliorations, ce qui signifie que mon composant "Stories" s'améliorera probablement à partir de maintenant.
  • Facilité d'implémentation. Les points d'ancrage de défilement sont pratiques pour le cas d'utilisation de pagination horizontale axée sur l'écran tactile.
  • Une inertie libre comme celle d'une plate-forme : Chaque plate-forme défile et reste dans son style, par opposition à une inertie normalisée qui peut avoir un style de défilement et de repos étrange.

Compatibilité multinavigateur

Nous avons testé Opera, Firefox, Safari et Chrome, ainsi qu'avec Android et iOS. Voici un bref aperçu des fonctionnalités Web dans lesquelles nous avons constaté des différences au niveau des fonctionnalités et de l'assistance.

Cependant, certains CSS ne s'appliquent pas, c'est pourquoi certaines plates-formes manquent actuellement d'optimisation de l'expérience utilisateur. J'aimais ne pas avoir à gérer ces fonctionnalités et je suis sûr qu'elles finiront par être disponibles sur d'autres navigateurs et plates-formes.

scroll-snap-stop

Les carrousels sont l'un des principaux cas d'utilisation de l'expérience utilisateur à l'origine de la création de la spécification des points d'ancrage de défilement CSS. Contrairement aux stories, un carrousel ne doit pas toujours s'arrêter sur chaque image après qu'un utilisateur a interagi avec. Il peut être acceptable ou encouragé de faire défiler rapidement le carrousel. En revanche, il est préférable de parcourir les stories une par une, et c'est exactement ce que fournit scroll-snap-stop.

.user {
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

Au moment de la rédaction de cet article, scroll-snap-stop n'est compatible qu'avec les navigateurs basés sur Chromium. Consultez la section Compatibilité du navigateur pour obtenir des mises à jour. Mais ce n’est pas un obstacle. Cela signifie simplement que sur un navigateur non compatible, les utilisateurs peuvent ignorer un ami par erreur. Les utilisateurs devront donc être plus prudents, ou bien nous devrons écrire du code JavaScript pour nous assurer qu'un ami ignoré ignoré ne soit pas marqué comme vu.

Pour en savoir plus, consultez la spécification si cela vous intéresse.

overscroll-behavior

Avez-vous déjà fait défiler une fenêtre modale lorsque vous commencez soudainement à faire défiler le contenu derrière la modale ? overscroll-behavior permet au développeur d'emprisonner ce défilement et de ne jamais le laisser partir. Elle est idéale pour toutes sortes d'occasions. Le composant "Mes histoires" l'utilise pour éviter que des balayages et des gestes de défilement supplémentaires ne quittent le composant.

.stories {
  overflow-x: auto;
  overscroll-behavior: contain;
}

Safari et Opera sont les deux navigateurs qui ne sont pas compatibles avec cette fonctionnalité, et c'est tout à fait normal. Ces utilisateurs bénéficieront d'une expérience de défilement hors limites comme à leur habitude et ne remarqueront peut-être jamais cette amélioration. Personnellement, je suis un grand fan et j'aime l'inclure dans presque toutes les fonctionnalités de défilement hors limites que j'implémente. C'est un ajout inoffensif qui ne peut qu'améliorer l'expérience utilisateur.

scrollIntoView({behavior: 'smooth'})

Lorsqu'un utilisateur appuie ou clique et atteint la fin de l'ensemble d'histoires d'un ami, il est temps de passer à l'ami suivant dans l'ensemble de points d'ancrage de défilement. Avec JavaScript, nous avons pu référencer l'ami suivant et demander à le faire défiler. La prise en charge des principes de base est excellente : tous les navigateurs l'ont fait défiler pour la faire défiler. Cependant, tous les navigateurs ne l'ont pas fait 'smooth'. Cela signifie simplement qu'il est affiché par défilement au lieu d'être ancré.

element.scrollIntoView({
  behavior: 'smooth'
})

Safari est le seul navigateur à ne pas accepter behavior: 'smooth' ici. Consultez la section Compatibilité du navigateur pour obtenir des mises à jour.

Pratique

Maintenant que tu sais comment j'ai fait, comment tu en ferais ?! Diversifions nos approches et apprenons toutes les façons de créer sur le Web. Créez un Glitch, puis envoyez-moi votre version par tweet et je l'ajouterai à la section Remix de la communauté ci-dessous.

Remix de la communauté