Créer un composant "Stories"

Présentation de base sur la création d'une expérience semblable à celle des stories Instagram sur le Web.

Dans cet article, je souhaite partager mes réflexions sur la création d'un composant Stories pour le Web qui est responsif, compatible avec la navigation au clavier et compatible avec tous les navigateurs.

Démonstration

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

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

Présentation

Les stories Snapchat et Instagram (sans parler des flottes) sont deux exemples populaires de l'expérience utilisateur pour les stories. En termes d'expérience utilisateur, les stories sont généralement un modèle basé sur les pressions, réservé aux mobiles et permettant de naviguer dans plusieurs abonnements. Par exemple, sur Instagram, les utilisateurs ouvrent l'histoire d'un ami et parcourent les images qu'elle contient. Ils le font généralement avec plusieurs amis à la fois. En appuyant sur le côté droit de l'appareil, l'utilisateur passe à la prochaine story de cet ami. En balayant l'écran vers la droite, l'utilisateur passe à un autre ami. Un composant Story est assez semblable à un carrousel, mais il permet de naviguer dans un tableau multidimensionnel plutôt que dans un tableau unidimensionnel. C'est comme s'il y avait un carrousel à l'intérieur de chaque carrousel. 🤯

Tableau multidimensionnel visualisé à l'aide de cartes. De gauche à droite, une pile de cartes à bordure violette, et à l'intérieur de chaque carte, une ou plusieurs cartes à bordure cyan. Liste dans une liste.
1er carrousel d'amis
2e carrousel "empilé" d'histoires
👍 Liste dans une 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. Voyons-les.

Grille CSS

Notre mise en page ne s'est pas avérée difficile pour CSS Grid, car il est équipé de méthodes efficaces pour gérer le contenu.

Mise en page "Amis"

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

.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;
}
Utilisation du mode Appareil des outils pour les développeurs Chrome pour mettre en surbrillance 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 lignes et de colonnes.
  • auto-flow est traduit par grid-auto-flow: column
  • Le modèle de flux automatique est 100%, qui correspond dans ce cas à la largeur de la fenêtre de défilement.

Sur un téléphone mobile, considérez la taille de ligne comme la hauteur de la fenêtre d'affichage et chaque colonne comme la largeur de la fenêtre d'affichage. Poursuivant l'exemple des stories Snapchat et Instagram, chaque colonne correspond à la story 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 l'écran. Grid crée autant de colonnes qu'il en faut pour mettre en page votre code HTML pour chaque histoire d'un ami, créant ainsi un conteneur de défilement dynamique et responsif. La grille nous a permis de centraliser l'ensemble de l'effet.

Empilement

Pour chaque ami, nous avons besoin que ses stories soient prêtes à être paginées. Pour préparer l'animation et d'autres motifs amusants, j'ai choisi une pile. Lorsque je parle de pile, je veux dire que vous regardez un sandwich de haut en bas, et non 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 attribué à cet espace à une seule cellule avec un 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 de maintenir tous les éléments dans le flux. Notez que nous n'avons pas eu à faire quoi que ce soit avec le positionnement absolute ou z-index, et que nous n'avons pas eu à corriger la mise en forme avec height: 100% ou width: 100%. La grille parente a déjà défini la taille du viewport de l'image de la story. Aucun de ces composants de la story n'a donc besoin d'être invité à le remplir.

Points d'ancrage de défilement CSS

La spécification des points d'ancrage de défilement CSS permet de verrouiller facilement les éléments dans la fenêtre d'affichage lors du défilement. Avant l'existence de ces propriétés CSS, vous deviez utiliser JavaScript, et c'était… délicat, pour le moins. Consultez Présentation des points d'ancrage de défilement CSS de Sarah Drasner pour découvrir comment les utiliser.

Défilement horizontal avec et sans styles scroll-snap-points. Sans elle, les utilisateurs peuvent faire défiler l'écran librement. Le navigateur repose alors 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 peuvent activer la fonctionnalité de cible de capture.

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

  • Accessibilité sans frais. La spécification des points d'ancrage de défilement indique que l'appui sur les touches Flèche vers la gauche et Flèche vers la droite doit faire défiler les points d'ancrage par défaut.
  • Une spécification qui ne cesse de s'étoffer : de nouvelles fonctionnalités et des améliorations sont régulièrement apportées à la spécification des points d'ancrage de défilement, ce qui signifie que mon composant Stories va probablement s'améliorer à partir de maintenant.
  • Facilité d'implémentation Les points de repère de défilement sont conçus pour le cas d'utilisation de la pagination horizontale axée sur le toucher.
  • Inertie libre comme celle d'une plate-forme : Chaque plate-forme défilera et se reposera dans son style, contrairement à l'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'Android et iOS. Voici un bref récapitulatif des fonctionnalités Web pour lesquelles nous avons constaté des différences de fonctionnalités et de prise en charge.

Cependant, certains CSS ne s'appliquent pas, ce qui fait que certaines plates-formes ne bénéficient pas actuellement d'optimisations de l'expérience utilisateur. J'ai apprécié de ne pas avoir à gérer ces fonctionnalités et je suis persuadé qu'elles arriveront à destination d'autres navigateurs et plates-formes.

scroll-snap-stop

Les carrousels étaient l'un des principaux cas d'utilisation de l'expérience utilisateur qui ont conduit à la création de la spécification CSS Scroll Snap Points. Contrairement aux stories, un carrousel n'a pas toujours besoin de s'arrêter sur chaque image après qu'un utilisateur a interagi avec elle. Il peut être bon ou encouragé de faire défiler rapidement le carrousel. En revanche, il est préférable de les parcourir une par une, et c'est exactement ce que scroll-snap-stop fournit.

.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 page Compatibilité des navigateurs pour en savoir plus. Ce n'est toutefois pas un problème bloquant. Cela signifie simplement que sur les navigateurs non compatibles, les utilisateurs peuvent ignorer accidentellement un ami. Les utilisateurs devront donc être plus prudents, ou nous devrons écrire du code JavaScript pour nous assurer qu'un ami ignoré n'est pas marqué comme vu.

Pour en savoir plus, consultez la spécification.

overscroll-behavior

Avez-vous déjà fait défiler une modale lorsque vous commencez soudainement à faire défiler le contenu derrière la modale ? overscroll-behavior permet au développeur de piéger ce défilement et de ne jamais le laisser partir. Il est adapté à toutes sortes d'occasions. Le composant "Mes stories" l'utilise pour empêcher les balayages et les gestes de défilement supplémentaires de quitter le composant.

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

Safari et Opera étaient les deux navigateurs qui n'étaient pas compatibles avec cette fonctionnalité, et c'est tout à fait acceptable. Ces utilisateurs bénéficieront d'une expérience de défilement 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 excessif que j'implémente. Il s'agit d'un ajout inoffensif qui ne peut qu'améliorer l'expérience utilisateur.

scrollIntoView({behavior: 'smooth'})

Lorsqu'un utilisateur appuie ou clique et qu'il a atteint la fin de l'ensemble d'histoires d'un ami, il est temps de passer au prochain ami dans l'ensemble de points d'ancrage de défilement. Avec JavaScript, nous avons pu faire référence à l'ami suivant et demander à ce qu'il soit affiché à l'écran. La compatibilité avec les principes de base est excellente. Chaque navigateur a fait défiler l'élément pour l'afficher. Cependant, tous les navigateurs ne l'ont pas fait 'smooth'. Cela signifie simplement qu'il est affiché à l'écran au lieu d'être épinglé.

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

Safari est le seul navigateur à ne pas prendre en charge behavior: 'smooth' dans ce cas. Consultez la page Compatibilité des navigateurs pour en savoir plus.

Activités pratiques

Maintenant que tu sais comment j'ai fait, comment faire ?! Diversifiez nos approches et découvrons toutes les méthodes de développement sur le Web. Créez un Glitch, tweetez-moi votre version, et je l'ajouterai à la section Remix de la communauté ci-dessous.

Remix de la communauté