Créer un composant de défilement multimédia

Présentation des principes de base pour créer une vue de défilement horizontale responsive pour les téléviseurs, les téléphones, les ordinateurs de bureau, etc.

Dans cet article, je souhaite partager des réflexions sur la façon de créer des expériences de défilement horizontal pour le Web qui sont minimalistes, responsives, accessibles et compatibles avec tous les navigateurs et plates-formes (comme les téléviseurs). Essayez la démo.

Démo

Si vous préférez regarder une vidéo, 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é en une expérience de défilement satisfaisante et fluide à l'aide du CSS, en affichant des images et en les ajustant à une grille. JavaScript est ajouté pour faciliter les interactions avec l'index itinérant, ce qui permet aux utilisateurs de clavier de ne pas parcourir plus de 100 éléments. De plus, une requête multimédia expérimentale, prefers-reduced-data, est utilisée pour transformer le défilement multimédia en une expérience de défilement de titres légère.

Commencer par le balisage accessible

Un défilement multimédia ne comporte que quelques composants de base, une liste d'éléments. Dans sa forme la plus simple, une liste peut voyager dans le monde entier et être consommée par tous. Un utilisateur qui accède à cette page peut parcourir une liste et cliquer sur un lien pour afficher un élément. Il s'agit de notre base accessible.

Envoyez une liste avec un élément <ul>:

<ul class="horizontal-media-scroller">
  <li></li>
  <li></li>
  <li></li>
  ...
<ul>

Rendre les éléments de 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 défileur multimédia est une opportunité d'expérience utilisateur pour fournir un contexte supplémentaire à la vignette, ou comme texte de remplacement si l'image ne s'est pas chargée, ou encore pour fournir une UI vocale aux utilisateurs qui s'appuient sur des technologies d'assistance telles qu'un lecteur d'écran. Pour en savoir plus, consultez les 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 extraite que lorsque l'image se trouve dans le viewport. Cela peut être très utile pour les longues listes, car les utilisateurs ne téléchargeront que les images des éléments qu'ils ont fait défiler.

Respecter la préférence de jeu de couleurs de l'utilisateur

Utilisez color-scheme comme balise <meta> pour indiquer au navigateur que votre page souhaite utiliser les styles d'agent utilisateur clair et sombre 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 méta fournit le signal le plus précoce possible afin que le navigateur puisse sélectionner une couleur de canevas sombre par défaut si l'utilisateur préfère un thème sombre. Cela signifie que les navigations entre les pages du site ne clignoteront pas d'arrière-plan de canevas blanc entre les chargements. Thème sombre fluide entre les chargements, beaucoup plus agréable pour les yeux.

Pour en savoir plus, consultez Thomas Steiner sur https://web.dev/color-scheme/.

Ajouter du contenu

Compte tenu de la structure de contenu ci-dessus de ul > li > a > figure > picture > img, la tâche suivante consiste à ajouter des images et des titres à faire défiler. J'ai rempli la démonstration d'images et de 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 que le CSS prenne cette liste générique de contenus et la transforme 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 le viewport de catégories et d'options.

Créer la mise en page du défilement

Il est important d'éviter de couper le contenu dans les mises en page ou de recourir à la troncation du texte avec des points de suspension. De nombreux téléviseurs sont équipés de défileurs multimédias comme celui-ci, mais ils ont trop souvent recours à des ellipses pour le contenu. Cette mise en page ne le fait pas. 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.

Affichage de deux lignes de défilement. L&#39;un ne comporte pas d&#39;ellipses, ce qui signifie qu&#39;il est plus haut et que chaque titre est entièrement lisible. L&#39;autre est plus court, et de nombreux titres sont tronqués par des points de suspension.

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 de grille est orientée sur 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: un cadre:

.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, vous pouvez terminer la structure de base du défileur 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);
  }
}

Le paramètre overflow configure <ul> pour permettre le défilement et la navigation au clavier dans sa liste. Ensuite, le ::marker de chaque élément <li> enfant direct est supprimé en obtenant un nouveau type d'affichage de inline-block.

Les images ne sont pas encore responsives et sortent directement des boîtes dans lesquelles elles se trouvent. Apprivoisez-les avec des tailles, des styles d'ajustement et de bordure, ainsi qu'un dégradé d'arrière-plan pour le chargement paresseux:

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, ainsi qu'une surface de défilement de bord à bord, sont essentiels pour obtenir un composant harmonieux et minimaliste.

Pour obtenir une mise en page de défilement de 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 d'un bug de marge intérieure de défilement horizontal La section ci-dessus montre à quel point il devrait être facile de mettre en place une marge intérieure pour un conteneur de défilement, mais il existe des problèmes de compatibilité non résolus (mais résolus dans Chromium 91 et versions ultérieures). Consultez cette page pour en savoir plus sur l'historique, mais en résumé, la marge intérieure n'était pas toujours prise en compte dans une vue de défilement.

Une zone est mise en surbrillance du côté de la fin en ligne du dernier élément de liste, ce qui montre que la marge intérieure et l&#39;élément ont la même largeur pour créer l&#39;alignement souhaité.

Pour inciter les navigateurs à placer la marge intérieure à la fin du défileur, je ciblerai le dernier chiffre de chaque liste et ajouterai un pseudo-élément correspondant à la quantité de 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 défileur multimédia de fonctionner dans n'importe quel mode d'écriture et dans n'importe quelle orientation de document.

Défilement scroll-snap

Un conteneur à défilement avec débordement peut devenir une vue d'affichage avec une seule ligne de CSS. Il appartient ensuite aux enfants de spécifier comment ils souhaitent s'aligner sur cette vue 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;
  }
}

Mise au point

Ce composant s'inspire de sa popularité massive sur les téléviseurs, dans les plates-formes de téléchargement d'applications, etc. De nombreuses plates-formes de jeux vidéo utilisent un défilement multimédia très semblable à celui-ci comme mise en page principale de l'écran d'accueil. La concentration est un moment important de l'expérience utilisateur, et non un simple ajout. Imaginez que vous utilisez ce défileur multimédia depuis votre canapé avec une télécommande. Améliorez 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 à l'écart de la zone, ce qui lui laisse un espace agréable. Si l'utilisateur n'a pas de préférences de mouvement concernant la réduction du mouvement, le décalage est mis en transition, ce qui donne un mouvement subtil à l'événement de mise au point.

Indice itinérant

Les utilisateurs de manettes de jeu et de clavier 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é indice itinérant. Il se produit lorsqu'un conteneur d'éléments est sélectionné au clavier, mais qu'un seul enfant est autorisé à le maintenir à la fois. Cette expérience d'un seul élément à la fois est conçue pour permettre de contourner la liste potentiellement longue d'éléments, au lieu d'appuyer sur la touche Tabulation plus de 50 fois pour atteindre la fin.

Ce premier scroller de la démonstration contient 300 éléments. Nous pouvons faire mieux que de les faire traverser toutes pour atteindre la section suivante.

Pour créer cette expérience, JavaScript doit observer les événements de clavier et les événements 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 défileurs:

import {rovingIndex} from 'roving-ux';

rovingIndex({
  element: someElement
});

Cette démonstration interroge le document pour les barres de défilement et appelle la fonction rovingIndex() pour chacune d'elles. Transmettez à rovingIndex() l'élément pour obtenir l'expérience de balayage, comme un conteneur de liste, et un sélecteur de requête cible, au cas où les cibles de focus 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 compatibilité avec aspect-ratio est derrière un indicateur dans Firefox, mais disponible dans les navigateurs Chromium ou les box. Étant donné que la mise en page de la grille du défileur multimédia ne spécifie que la direction et l'espacement, la taille peut changer dans une requête multimédia qui vérifie la prise en charge du format. Amélioration progressive de certains défileurs multimédias plus dynamiques.

Une boîte au format 4:4 est affichée à côté des autres formats de conception utilisés, à savoir 16:9 et 4:3.

@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 défileur multimédia sont mises à niveau vers la taille aspect-ratio. Avec la syntaxe d'imbrication de la version préliminaire, le format de chaque image change selon qu'elle se trouve sur la première, la deuxième ou la troisième ligne. La syntaxe imbriquée permet également de définir de petits ajustements de la vue, avec l'autre logique de dimensionnement.

Avec ce CSS, comme la fonctionnalité est disponible dans davantage de moteurs de navigateur, une mise en page facile à gérer, mais plus attrayante visuellement, s'affiche.

Préférence pour les données réduites

Bien que cette technique ne soit disponible que derrière un indicateur dans Canary, je voulais vous expliquer comment j'ai pu réduire considérablement le temps de chargement des pages et l'utilisation des données avec quelques lignes de CSS. La requête multimédia prefers-reduced-data du niveau 5 permet de demander si l'appareil se trouve dans un état de données réduites, comme un mode d'économie de données. Si c\'est le cas, je peux modifier le document et, dans ce cas, masquer les images.

ALT_TEXT_HERE

figure {
  @media (prefers-reduced-data: reduce) {
    & {
      min-inline-size: var(--size);

      & > picture {
        display: none;
      }
    }
  }
}

Le contenu reste accessible, mais sans le coût du téléchargement des images lourdes. Voici le site avant l'ajout du CSS prefers-reduced-data:

(7 requêtes, 100 ko de ressources en 131 ms)

ALT_TEXT_HERE

Voici les performances du site après l'ajout du CSS prefers-reduced-data:

ALT_TEXT_HERE

(71 requêtes, 1,2 Mo de ressources en 1,07 s)

64 requêtes en moins, soit environ 60 images dans le viewport (tests effectués sur un écran grand écran) de cet onglet de navigateur, une augmentation du chargement de la page d'environ 80 % et 10% des données transmises par ligne. CSS assez puissant.

Conclusion

Maintenant que vous savez comment j'ai fait, comment pourriez-vous faire ? 🙂

Diversifions nos approches et découvrons toutes les façons de créer sur le Web. Créez un Codepen ou hébergez votre propre démonstration, tweetez-moi avec, et je l'ajouterai à la section "Remix de la communauté" ci-dessous.

Source

Remix de la communauté

Aucun élément à afficher pour l'instant.