Présentation de base sur la façon de créer une vue à défilement horizontal responsif pour les téléviseurs, les téléphones, les ordinateurs de bureau, etc.
Dans cet article, je souhaite partager des idées sur la façon de créer des expériences de défilement horizontal pour le Web qui soient minimalistes, responsives, accessibles et qui fonctionnent sur tous les navigateurs et plates-formes (comme les téléviseurs !). Essayez la démonstration.
Si vous préférez les vidéos, voici une version YouTube de cet article :
Présentation
Nous allons créer une mise en page à défilement horizontal destinée à héberger des miniatures de contenus multimédias ou de produits. Le composant commence par une simple liste <ul>
, mais est transformé avec CSS en une expérience de défilement satisfaisante et fluide, affichant des images et les alignant sur une grille. JavaScript est ajouté pour faciliter les interactions avec l'index de déplacement, ce qui permet aux utilisateurs de clavier d'éviter de parcourir plus de 100 éléments.
De plus, une requête média expérimentale, prefers-reduced-data
, est utilisée pour transformer le carrousel média en un carrousel de titres léger.
Commencer par un balisage accessible
Un sélecteur de contenu multimédia est composé de quelques composants de base, à savoir une liste avec des éléments. Une liste, dans sa forme la plus simple, peut voyager dans le monde entier et être clairement consommée par tous. Un utilisateur qui arrive sur cette page peut parcourir une liste et cliquer sur un lien pour afficher un élément. Il s'agit de notre base accessible.
Fournissez une liste avec un élément <ul>
:
<ul class="horizontal-media-scroller">
<li></li>
<li></li>
<li></li>
...
<ul>
Rendez les éléments de la liste interactifs avec un élément <a>
:
<li>
<a href="#">
...
</a>
</li>
Utilisez un élément <figure>
pour représenter sémantiquement une image et sa légende :
<figure>
<picture>
<img alt="..." loading="lazy" src="https://picsum.photos/500/500?1">
</picture>
<figcaption>Legends</figcaption>
</figure>
Notez les attributs alt
et loading
sur <img>
. Le texte alternatif d'un carrousel multimédia est une opportunité UX pour fournir un contexte supplémentaire à la miniature ou un texte de remplacement si l'image ne s'est pas chargée. Il fournit également une interface utilisateur vocale pour les utilisateurs qui s'appuient sur une technologie d'assistance comme un lecteur d'écran. Pour en savoir plus, consultez Cinq règles d'or pour un texte alternatif conforme.
L'attribut loading
accepte le mot clé lazy
pour indiquer que cette source d'image ne doit être récupérée que lorsque l'image se trouve dans la fenêtre d'affichage. Cela peut être très utile pour les longues listes, car les utilisateurs ne téléchargeront les images que pour les éléments qu'ils ont fait défiler dans l'affichage.
Assurer la compatibilité avec le jeu de couleurs préféré de l'utilisateur
Utilisez color-scheme
comme balise <meta>
pour indiquer au navigateur que votre page souhaite utiliser les styles d'agent utilisateur clairs et sombres fournis. Il s'agit d'un mode sombre ou clair sans frais, selon votre point de vue :
<meta name="color-scheme" content="dark light">
La balise meta fournit le signal le plus précoce possible, de sorte que le navigateur peut sélectionner une couleur de canevas sombre par défaut si l'utilisateur a une préférence pour le thème sombre. Cela signifie que les navigations entre les pages du site n'afficheront pas de fond blanc entre les chargements. Thème sombre fluide entre les chargements, beaucoup plus agréable pour les yeux.
Pour en savoir plus, consultez l'article de Thomas Steiner sur https://web.dev/color-scheme/.
Ajouter du contenu
Compte tenu de la structure de contenu ul > li > a > figure > picture > img
ci-dessus, la tâche suivante consiste à ajouter des images et des titres à parcourir. J'ai rempli la démo avec des images et du texte d'espace réservé statiques, mais n'hésitez pas à l'alimenter à partir de votre source de données préférée.
Ajouter un style avec CSS
Il est maintenant temps pour CSS de prendre cette liste de contenu générique et de la transformer en expérience. Netflix, les plates-formes de téléchargement d'applications et de nombreux autres sites et applications utilisent des zones de défilement horizontal pour remplir la fenêtre d'affichage avec des catégories et des options.
Créer la mise en page du carrousel
Il est important d'éviter de couper le contenu dans les mises en page ou de s'appuyer sur la troncature du texte avec des points de suspension. De nombreux téléviseurs disposent de sélecteurs de contenu multimédia comme celui-ci, mais ils ont trop souvent recours à l'ellipse pour afficher le contenu. Ce n'est pas le cas de cette mise en page. Il permet également au contenu multimédia de remplacer la taille de la colonne, ce qui rend une mise en page suffisamment flexible pour gérer de nombreuses combinaisons intéressantes.
Le conteneur permet de remplacer la taille de la colonne en fournissant la taille par défaut en tant que propriété personnalisée. Cette mise en page en grille est spécifique à la taille des colonnes. Elle ne gère que l'espacement et la direction :
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2); /* parent owned value for children to be relative to*/
margin: 0;
}
La propriété personnalisée est ensuite utilisée par l'élément <picture>
pour créer notre format de base : une boîte :
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2);
margin: 0;
& picture {
inline-size: var(--size);
block-size: var(--size);
}
}
Avec quelques styles mineurs supplémentaires, complétez les bases du carrousel de contenu multimédia :
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2);
margin: 0;
overflow-x: auto;
overscroll-behavior-inline: contain;
& > li {
display: inline-block; /* removes the list-item bullet */
}
& picture {
inline-size: var(--size);
block-size: var(--size);
}
}
La définition de overflow
définit <ul>
pour autoriser le défilement et la navigation au clavier dans sa liste. Ensuite, la propriété ::marker
de chaque élément enfant direct <li>
est supprimée en lui attribuant un nouveau type d'affichage inline-block
.
Cependant, les images ne sont pas encore responsives et sortent des boîtes dans lesquelles elles se trouvent. Domptez-les avec des styles de taille, d'ajustement et de bordure, ainsi qu'un dégradé d'arrière-plan pour le chargement différé :
img {
/* smash into whatever box it's in */
inline-size: 100%;
block-size: 100%;
/* don't squish but do cover the space */
object-fit: cover;
/* soften the edges */
border-radius: 1ex;
overflow: hidden;
/* if empty, show a gradient placeholder */
background-image:
linear-gradient(
to bottom,
hsl(0 0% 40%),
hsl(0 0% 20%)
);
}
Marge intérieure de défilement
L'alignement sur le contenu de la page et une surface de défilement bord à bord sont essentiels pour un composant harmonieux et minimaliste.
Pour obtenir une mise en page à défilement bord à bord qui s'aligne sur notre typographie et nos lignes de mise en page, utilisez padding
qui correspond à scroll-padding
:
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2);
margin: 0;
overflow-x: auto;
overscroll-behavior-inline: contain;
padding-inline: var(--gap);
scroll-padding-inline: var(--gap);
padding-block: calc(var(--gap) / 2); /* make space for scrollbar and focus outline */
}
Correction du bug de marge intérieure de défilement horizontal L'exemple ci-dessus montre à quel point il devrait être facile d'ajouter une marge intérieure à un conteneur de défilement, mais il existe des problèmes de compatibilité en suspens (corrigés dans Chromium 91 et versions ultérieures). Consultez cet article pour en savoir plus sur l'historique, mais en bref, la marge intérieure n'a pas toujours été prise en compte dans une vue de défilement.
Pour inciter les navigateurs à placer la marge intérieure à la fin du défilement, je vais cibler la dernière figure de chaque liste et ajouter un pseudo-élément correspondant à la marge intérieure souhaitée.
.horizontal-media-scroller > li:last-of-type figure {
position: relative;
&::after {
content: "";
position: absolute;
inline-size: var(--gap);
block-size: 100%;
inset-block-start: 0;
inset-inline-end: calc(var(--gap) * -1);
}
}
L'utilisation de propriétés logiques permet au sélecteur de défilement de contenu multimédia de fonctionner dans n'importe quel mode d'écriture et sens de lecture du document.
Défilement scroll-snap
Un conteneur de défilement avec un dépassement peut devenir une fenêtre d'affichage avec alignement magnétique avec une seule ligne de CSS. Ensuite, c'est aux enfants de spécifier comment ils souhaitent s'aligner sur cette fenêtre d'affichage.
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2);
margin: 0;
overflow-x: auto;
overscroll-behavior-inline: contain;
padding-inline: var(--gap);
scroll-padding-inline: var(--gap);
padding-block-end: calc(var(--gap) / 2);
scroll-snap-type: inline mandatory;
& figure {
scroll-snap-align: start;
}
}
Concentration
Ce composant s'inspire de sa grande popularité sur les téléviseurs, dans les plates-formes de téléchargement d'applications et ailleurs. De nombreuses plates-formes de jeux vidéo utilisent un sélecteur de contenu multimédia très semblable à celui-ci comme mise en page principale de leur écran d'accueil. La mise au point est un élément essentiel de l'UX, et non une simple fonctionnalité supplémentaire. Imaginez que vous utilisiez ce sélecteur de défilement multimédia depuis votre canapé avec une télécommande. Apportez quelques petites améliorations à cette interaction :
.horizontal-media-scroller a {
outline-offset: 12px;
&:focus {
outline-offset: 7px;
}
@media (prefers-reduced-motion: no-preference) {
& {
transition: outline-offset .25s ease;
}
}
}
Cela définit le style de contour de mise au point 7px
en dehors de la boîte, ce qui lui donne un bel espace. Si l'utilisateur n'a aucune préférence concernant la réduction du mouvement, le décalage est transféré, ce qui donne un mouvement subtil à l'événement de sélection.
Index itinérant
Les utilisateurs de manettes de jeu et de claviers ont besoin d'une attention particulière dans ces longues listes de contenus et d'options à faire défiler. Le modèle courant pour résoudre ce problème est appelé index de déplacement. C'est lorsqu'un conteneur d'éléments est sélectionné au clavier, mais qu'un seul enfant peut être sélectionné à la fois. Cette expérience, qui permet de se concentrer sur un seul élément à la fois, est conçue pour contourner la liste potentiellement longue d'éléments, au lieu d'appuyer sur la touche de tabulation plus de 50 fois pour atteindre la fin.
Le premier carrousel de la démo contient 300 éléments. Nous pouvons faire mieux que de leur faire parcourir tous les éléments pour atteindre la section suivante.
Pour créer cette expérience, JavaScript doit observer les événements de clavier et de focus. J'ai créé une petite bibliothèque Open Source sur npm pour faciliter cette expérience utilisateur. Voici comment l'utiliser pour les trois sélecteurs :
import {rovingIndex} from 'roving-ux';
rovingIndex({
element: someElement
});
Cette démo interroge le document pour trouver les éléments de défilement et appelle la fonction rovingIndex()
pour chacun d'eux. Transmettez rovingIndex()
à l'élément pour obtenir l'expérience de déplacement, comme un conteneur de liste, et un sélecteur de requête cible, au cas où les cibles de mise au point ne seraient pas des descendants directs.
document.querySelectorAll('.horizontal-media-scroller')
.forEach(scroller =>
rovingIndex({
element: scroller,
target: 'a',
}))
Pour en savoir plus sur cet effet, consultez la bibliothèque Open Source roving-ux.
Format
Au moment de la rédaction de cet article, la prise en charge de aspect-ratio
est masquée par un indicateur dans Firefox, mais disponible dans les navigateurs Chromium ou les boîtiers décodeurs. Étant donné que la mise en page en grille du carrousel de contenus multimédias ne spécifie que la direction et l'espacement, la taille peut changer à l'intérieur d'une requête média qui vérifie la compatibilité avec le format.
Amélioration progressive de certains carrousels de contenu multimédia plus dynamiques.
@supports (aspect-ratio: 1) {
.horizontal-media-scroller figure > picture {
inline-size: auto; /* for a block-size driven ratio */
aspect-ratio: 1; /* boxes by default */
@nest section:nth-child(2) & {
aspect-ratio: 16/9;
}
@nest section:nth-child(3) & {
/* double the size of the others */
block-size: calc(var(--size) * 2);
aspect-ratio: 4/3;
/* adjust size to fit more items into the viewport */
@media (width <= 480px) {
block-size: calc(var(--size) * 1.5);
}
}
}
}
Si le navigateur est compatible avec la syntaxe aspect-ratio
, les images du carrousel multimédia sont redimensionnées en aspect-ratio
. En utilisant la syntaxe d'imbrication des brouillons, chaque image change de format en fonction de sa position (première, deuxième ou troisième ligne). La syntaxe imbriquée permet également de définir de petits ajustements de la fenêtre d'affichage, en même temps que la logique de dimensionnement.
Avec ce CSS, à mesure que la fonctionnalité sera disponible dans davantage de moteurs de navigateur, une mise en page facile à gérer, mais plus attrayante visuellement, sera affichée.
Préfère les données réduites
Bien que cette technique ne soit disponible que derrière un indicateur dans Canary, je voulais vous montrer comment j'ai pu économiser un temps de chargement de page et une utilisation de données considérables avec quelques lignes de CSS. La requête média prefers-reduced-data
du niveau 5 permet de déterminer si l'appareil est dans un état de données réduites, comme le mode Économiseur de données. Si c'est le cas, je peux modifier le document et, dans ce cas, masquer les images.
figure {
@media (prefers-reduced-data: reduce) {
& {
min-inline-size: var(--size);
& > picture {
display: none;
}
}
}
}
Le contenu reste navigable, mais sans le coût du téléchargement des images lourdes. Voici le site avant l'ajout du code CSS prefers-reduced-data
:
(7 demandes, 100 ko de ressources en 131 ms)
Voici les performances du site après l'ajout du code CSS prefers-reduced-data
:
(71 requêtes, 1,2 Mo de ressources en 1,07 s)
Cela représente 64 requêtes en moins, soit environ 60 images dans la fenêtre d'affichage (tests effectués sur un écran large) de cet onglet de navigateur, une amélioration du chargement de page d'environ 80 % et 10 % des données sur le réseau. C'est un CSS assez puissant.
Conclusion
Maintenant que vous savez comment j'ai fait, comment feriez-vous ? 🙂
Diversifions nos approches et découvrons toutes les façons de créer sur le Web. Créez une démo sur CodePen ou hébergez-la vous-même, tweetez-la moi et je l'ajouterai à la section "Remix de la communauté" ci-dessous.
Source
Remix de la communauté
Aucun élément à afficher pour le moment.