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

Présentation des principes de base de la création d'une vue à défilement horizontal responsive pour les téléviseurs, les téléphones, les ordinateurs de bureau, etc.

Dans cet article, je souhaite partager nos réflexions sur les moyens de créer des expériences de défilement horizontal pour le Web qui soient minimales, réactives, accessibles et compatibles avec tous les navigateurs et plates-formes (comme les téléviseurs). Essayez la démonstration.

Démonstration

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

Présentation

Nous allons créer une mise en page à défilement horizontal pour héberger les miniatures de contenus multimédias ou de produits. Le composant commence par une liste <ul> simple, mais est transformé par CSS en une expérience de défilement satisfaisante et fluide, qui affiche des images et les ancre dans une grille. JavaScript est ajouté pour faciliter les interactions dans l'index, ce qui permet aux utilisateurs de clavier d'éviter de passer par plus de 100 éléments. De plus, une requête média expérimentale, prefers-reduced-data, permet de transformer le conteneur de défilement multimédia en une expérience de défilement de titre légère.

Commencez avec un balisage accessible

Un conteneur de défilement multimédia ne se compose que de quelques composants principaux : une liste d'éléments. Dans sa forme la plus simple, une liste peut voyager à travers le monde et être clairement utilisé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.

Diffusez une liste comportant un élément <ul>:

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

Rendez 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 conteneur de défilement multimédia est une opportunité UX qui permet d'apporter plus de contexte à la miniature, ou comme texte de remplacement si l'image ne s'est pas chargée ou fournit une UI vocale aux 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 la conformité du texte alternatif.

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 listes volumineuses, car les utilisateurs ne téléchargent que les images des éléments qu'ils ont affichés en faisant défiler l'écran.

Prendre en charge les préférences de jeu de couleurs de l'utilisateur

Utilisez color-scheme en tant que balise <meta> pour signaler au navigateur que votre page souhaite utiliser à la fois les styles clair et sombre fournis pour les user-agents. Il s'agit d'un mode sombre sans frais ou d'un mode clair, selon votre apparence:

<meta name="color-scheme" content="dark light">

La balise Meta fournit le signal le plus tôt possible. Ainsi, 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 ne clignotent pas d'arrière-plan blanc de canevas entre les chargements. Thème sombre fluide entre les chargements, bien plus agréable à regarder.

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

Ajouter du contenu

Compte tenu de la structure de contenu de ul > li > a > figure > picture > img ci-dessus, la tâche suivante consiste à ajouter des images et des titres à faire défiler. J'ai empaqueté la démonstration avec des images et du texte d'espace réservé statiques, mais n'hésitez pas à l'alimenter depuis votre source de données préférée.

Ajouter un style avec CSS

Il est maintenant temps pour les CSS de transformer cette liste de contenus générique 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 empaqueter la fenêtre d'affichage avec des catégories et des options.

Créer la mise en page de la zone de défilement

Il est important d'éviter de couper du contenu dans les mises en page ou de vous appuyer sur la troncation de texte avec des points de suspension. De nombreux téléviseurs disposent de défilements multimédias semblables à celui-ci, mais trop souvent, des points de suspension s'appliquent. Ce n'est pas le cas de cette mise en page. Elle 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.

2 lignes défilantes affichées. L&#39;un n&#39;a pas de points de suspension, ce qui signifie qu&#39;il est plus grand et que chaque titre est entièrement lisible. L&#39;autre est plus court et de nombreux titres sont délimité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 en grille est déterminée par la taille des colonnes. Elle ne gère que l'espacement et l'orientation:

.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 le format de base, à savoir une zone :

.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);
  }
}

Il ne reste plus que quelques styles mineurs pour compléter les éléments essentiels du conteneur de défilement 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);
  }
}

Définir overflow configure <ul> pour permettre le défilement et la navigation au clavier dans sa liste, puis chaque élément <li> enfant direct voit son ::marker supprimé en obtenant un nouveau type d'affichage de inline-block.

Les images ne sont cependant pas encore réactives et jaillissent directement des boîtes dans lesquelles elles se trouvent. Approfondissez-les avec des tailles, des ajustements et des styles de bordure, ainsi qu'un dégradé d'arrière-plan pour les chargements différés:

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 par rapport au contenu de la page, ainsi qu'une surface de défilement bord à bord, sont essentiels pour créer un composant minimal et harmonieux.

Pour obtenir la mise en page de défilement bord à bord qui est alignée 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 lié à la marge intérieure du défilement horizontal Ce qui précède montre à quel point il est facile d'ajouter une marge intérieure à un conteneur de défilement, mais il présente des problèmes de compatibilité en suspens (résolus dans Chromium 91 et versions ultérieures). Consultez cette page pour obtenir un aperçu de l'historique. La version abrégée indique que la marge intérieure n'a pas toujours été prise en compte dans une vue de défilement.

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

Pour inciter les navigateurs à placer la marge intérieure à la fin du conteneur de défilement, je vais cibler la dernière figure de chaque liste et ajouter 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 conteneur de défilement multimédia de fonctionner dans n'importe quel mode d'écriture et quelle que soit la direction du document.

Ancrage par défilement

Un conteneur de défilement avec dépassement peut devenir une fenêtre d'affichage ancrée avec une ligne de code CSS, puis c'est sur les enfants qui spécifient l'alignement avec 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;
  }
}

Objet

Ce composant s'inspire de sa popularité massive sur les téléviseurs, dans l'App Store, etc. De nombreuses plates-formes de jeux vidéo utilisent un conteneur de défilement multimédia très semblable à celui-ci, comme disposition principale de l'écran d'accueil. La concentration est un énorme moment UX ici, pas seulement un petit ajout. Imaginez que vous utilisiez ce défilement multimédia depuis votre canapé avec une télécommande et 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;
    }
  }
}

Le style de contour de la mise au point 7px s'éloigne ainsi de la zone, ce qui lui donne un peu d'espace. Si l'utilisateur n'a pas de préférences de mouvement pour réduire le mouvement, le décalage est modifié, ce qui crée un mouvement subtil pour l'événement de sélection.

Indice itinérant

Les utilisateurs de manettes de jeu et de claviers requièrent une attention particulière dans ces longues listes d'options et de contenus à faire défiler. Le modèle courant permettant de résoudre ce problème est appelé index mobile. Cela se produit lorsqu'un conteneur d'éléments est sélectionné au clavier, mais qu'un seul enfant est autorisé à le faire à la fois. Cet élément sélectionnable à la fois est conçu pour permettre de contourner la liste d'éléments potentiellement longue, plutôt que d'appuyer sur la touche de tabulation plus de 50 fois pour atteindre la fin.

Le premier conteneur de la démo 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 sélection. J'ai créé une petite bibliothèque Open Source sur npm pour rendre cette expérience utilisateur facile à mettre en œuvre. Voici comment l'utiliser pour les trois défileurs:

import {rovingIndex} from 'roving-ux';

rovingIndex({
  element: someElement
});

Cette démonstration interroge le document à la recherche des éléments de défilement et, pour chacun d'eux, appelle la fonction rovingIndex(). Transmettez à rovingIndex() l'élément pour obtenir l'expérience mobile, telle qu'un conteneur de liste et un sélecteur de requête cible, au cas où les cibles cibles 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 protégé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 de défilement multimédia ne spécifie que la direction et l'espacement, le dimensionnement peut changer dans une requête média qui vérifie la compatibilité avec les formats. Amélioration progressive dans des éléments de défilement multimédia plus dynamiques.

Une case au format 4:4 est affichée à côté des autres formats de conception utilisés (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 accepte la syntaxe aspect-ratio, les images du conteneur de défilement multimédia sont redimensionnées au format aspect-ratio. Avec la syntaxe d'imbrication brouillon, chaque image modifie son format selon qu'il s'agit de la première, deuxième ou troisième lignes. La syntaxe imbriquée permet également de définir de petits ajustements de la fenêtre d'affichage, directement 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, s'affichera.

Préfère les données réduites

Bien que la technique suivante ne soit disponible que derrière un indicateur dans Canary, je souhaitais vous expliquer comment réduire considérablement le temps de chargement de la page et l'utilisation des données avec quelques lignes de code CSS. La requête média prefers-reduced-data du niveau 5 permet de demander si l'appareil se trouve dans des états de données réduits, par exemple en mode Économiseur 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;
      }
    }
  }
}

Il est toujours possible de parcourir le contenu, mais sans le coût des images lourdes qui sont téléchargées. Voici le site avant d'ajouter le 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 de moins, ce qui représente environ 60 images dans la fenêtre d'affichage (tests effectués sur un grand écran) de cet onglet de navigateur, une accélération du chargement de la page d'environ 80 % et 10% des données sur le réseau C'est un code CSS assez puissant.

Conclusion

Maintenant que tu sais comment j'ai fait, comment tu en ferais ?! 🙂

Diversissons nos approches et apprenons toutes les façons de créer sur le Web. Créez un Codepen ou animez votre propre démo. Envoyez-moi un tweet à mon adresse e-mail pour que je l'ajoute à la section "Remix de la communauté" ci-dessous.

Source

Remix de la communauté

Aucun élément à afficher pour l'instant