Syntaxes descriptives

Dans ce module, vous allez apprendre à laisser au navigateur le choix des images pour qu'il puisse prendre les meilleures décisions concernant les éléments à afficher. srcset n'est pas une méthode permettant de permuter des sources d'image au niveau de points d'arrêt spécifiques. Elle n'est pas non plus destinée à remplacer une image par une autre. Ces syntaxes permettent navigateur pour résoudre un problème très complexe, indépendamment de nous: demander et afficher de manière transparente une source d'images adaptée au contexte de navigation de l'utilisateur, comme la taille de la fenêtre d'affichage, la densité d'affichage, les préférences des utilisateurs, la bande passante et d'innombrables autres facteurs.

C'est un enjeu majeur : il ne s'agit pas seulement de baliser une image pour le Web, mais une bonne pratique implique davantage d’informations auxquelles nous ne pouvons pas accéder.

Décrire la densité avec x

Un élément <img> de largeur fixe occupera la même partie de la fenêtre d'affichage quel que soit le contexte de navigation, quelle que soit la densité de l'utilisateur display : le nombre de pixels physiques qui composent leur écran. Par exemple, une image dont la largeur inhérente est de 400px occupera presque toute la fenêtre d'affichage du navigateur sur le Google Pixel d'origine ainsi que sur le Pixel 6 Pro, qui est beaucoup plus récent, les deux appareils ont un 412px normalisé fenêtre d'affichage avec une largeur de pixels logiques.

Le Pixel 6 Pro dispose toutefois d'un écran beaucoup plus net: le Pixel 6 Pro a une résolution physique de 1 440 × 3 120 pixels, tandis que le Pixel mesure 1 080 × 1 920 pixels, c'est-à-dire le nombre de pixels matériels qui composent l'écran lui-même.

Le rapport entre les pixels logiques et les pixels physiques d'un appareil correspond au rapport de pixels de l'appareil pour cet écran. La valeur "RDP" est Il est calculé en divisant la résolution réelle de l'écran de l'appareil par les pixels CSS d'une fenêtre d'affichage.

Un DPR de 2 affiché dans une fenêtre de console.

Ainsi, le Pixel d'origine a un DPR de 2,6, tandis que le Pixel 6 Pro a un DPR de 3,5.

L'iPhone 4, le premier appareil dont le DPR est supérieur à 1, enregistre un ratio de pixels de 2, c'est-à-dire la résolution physique de l'écran. soit le double de la résolution logique. Tous les appareils antérieurs à l'iPhone 4 présentaient un DPR de 1: un pixel logique par pixel physique.

Si vous affichez cette image de largeur 400px sur un écran avec un DPR de 2, chaque pixel logique est affiché sur quatre des pixels physiques de l'écran: deux horizontaux et deux verticaux. L'affichage haute densité n'est pas utile pour cette image. comme sur un écran avec un DPR de 1. Bien sûr, tout ce qui est « dessin » par le moteur de rendu du navigateur (texte, formes CSS ou SVG), par exemple, s'affiche pour s'adapter à l'affichage avec une densité plus élevée. Mais comme vous l'avez appris dans la section Formats et compression des images, les images matricielles sont fixes des grilles de pixels. Même si ce n'est pas toujours évident, une image matricielle améliorée pour s'adapter à un écran haute densité aura l'air en basse résolution par rapport à la page environnante.

Pour éviter cette augmentation, l'image en cours de rendu doit avoir une largeur intrinsèque d'au moins 800 pixels. En cas de réduction de la taille de l'image pour remplir un espace dans une mise en page de 400 pixels logiques de largeur logique, cette source d'image de 800 pixels présente une densité de pixels doublée (sur un écran avec un DPR de 2, le rendu sera beau et net.

Gros plan sur un pétale de fleur présentant une densité disparate.

Étant donné qu'un écran avec un DPR de 1 ne peut pas utiliser la densité accrue d'une image, il sera réajusté pour correspondre à la et comme vous le savez, une image réduite fera parfaitement l'affaire. Sur un écran basse densité, une image adaptée à une densité plus élevée ressemblent à n'importe quelle autre image basse densité.

Comme vous l'avez appris dans la section Images et performances, un utilisateur disposant d'un écran de faible densité affichant une source d'image en taille réduite à 400px n'aura besoin que d'une source ayant une largeur inhérente de 400px. Même si une image beaucoup plus grande fonctionnerait visuellement pour tous les utilisateurs, une image Une source d'image haute résolution affichée sur un petit écran à faible densité ressemblera à n'importe quelle autre image basse densité, mais sera beaucoup plus lente.

Comme vous pouvez le deviner, les appareils mobiles dont le DPR est de 1 sont rarement rares, même s'il est encore courant dans "ordinateur", différents contextes de navigation. D'après les données partagé par Matt Hobbs, environ 18% des sessions de navigation sur GOV.UK enregistrées en novembre 2022 indiquent un DPR de 1. Même si les images haute densité ressemblent à ce à quoi ces utilisateurs peuvent s'attendre, elles auront une quantité de bande passante et un coût de traitement beaucoup plus élevés. s'inquiète particulièrement pour les utilisateurs d'appareils plus anciens et moins puissants, susceptibles d'avoir des écrans basse densité.

L'utilisation de srcset garantit que seuls les appareils dotés d'écrans haute résolution reçoivent des sources d'image suffisamment grandes pour obtenir un rendu net, sans dépasser cette le coût de la bande passante ainsi que les utilisateurs avec des écrans basse résolution.

L'attribut srcset identifie un ou plusieurs candidats séparés par une virgule pour le rendu d'une image. Chaque candidat se compose deux éléments: une URL, comme vous l'utiliseriez dans src, et une syntaxe qui décrit cette source d'image. Chaque candidat du groupe srcset est décrit par sa largeur inhérente ("syntaxe w") ou par sa densité prévue ("syntaxe x").

La syntaxe x est un raccourci pour "cette source est adaptée à un affichage avec cette densité". Un candidat suivi de 2x est convient pour un écran avec un DPR de 2.

<img src="low-density.jpg" srcset="double-density.jpg 2x" alt="...">

Les navigateurs qui prennent en charge srcset seront présentés avec deux propositions: double-density.jpg, que 2x décrit comme approprié. Pour les écrans avec un DPR de 2 et low-density.jpg dans l'attribut src (le candidat est sélectionné si rien de plus approprié n'est trouvé dans srcset. Pour les navigateurs non compatibles avec srcset, l'attribut et son contenu sont ignorés : le contenu de src seront demandées, comme d'habitude.

Il est facile de confondre les valeurs spécifiées dans l'attribut srcset avec les instructions. Ce 2x informe le navigateur que fichier source associé peut être utilisé sur un écran avec un DPR de 2, à savoir des informations sur la source elle-même. Ne dit pas le navigateur comment utiliser cette source, informe simplement le navigateur de la façon dont la source pourrait être utilisée. Il s'agit d'une distinction subtile, mais importante : est une image double densité, et non une image destinée à un écran double densité.

La différence entre une syntaxe qui indique que "cette source est adaptée aux écrans 2x" et une autre indiquant "Utiliser cette source sur les écrans 2x" est légère dans l'édition papier, mais la densité d'affichage n'est que l'un des nombreux facteurs interdépendants que le navigateur utilise pour choisir le candidat. dont vous ne connaissez que certaines. Par exemple, individuellement, vous pouvez déterminer qu'un utilisateur a activé un la préférence de navigateur permettant d'économiser la bande passante via la requête média prefers-reduced-data. Utilisez-la pour toujours activer les images basse densité pour les utilisateurs. quelle que soit leur densité d'affichage. Toutefois, à moins d'une mise en œuvre cohérente par tous les développeurs et sur tous les sites Web, elle ne serait pas très utile pour un utilisateur. Ils peuvent voir leur préférence respectée sur un site et se heurter à un mur d'images qui masque la bande passante d'un autre site.

L'algorithme de sélection des ressources délibérément vague utilisé par srcset/sizes laisse aux navigateurs la possibilité de sélectionner une densité plus faible avec des baisses de bande passante ou basées sur une préférence visant à minimiser l'utilisation des données, sans que nous ne soyons responsables de la manière, du moment ou de pour définir un seuil défini. Il n'est pas judicieux d'assumer des responsabilités (et des tâches supplémentaires) que le navigateur soit mieux à même de gérer pour vous.

Décrire des largeurs avec w

srcset accepte un deuxième type de descripteur pour les candidats de sources d'images. C'est un outil beaucoup plus puissant, et pour les besoins de cet atelier, beaucoup plus facile à comprendre. Plutôt que de signaler un candidat comme ayant les dimensions appropriées pour une densité d'affichage donnée, La syntaxe w décrit la largeur inhérente de chaque source candidate. Là encore, chaque candidat est identique, sauf en ce qui concerne ses dimensions (identique). contenus, recadrage et format. Mais dans ce cas, vous voulez que le navigateur de l'utilisateur ait le choix entre deux propositions: small.jpg, une source avec une largeur inhérente de 600 pixels, et large.jpg, une source avec une largeur intrinsèque de 1 200 pixels.

srcset="small.jpg 600w, large.jpg 1200w"

Cela n'indique pas au navigateur ce qu'il doit faire de ces informations, mais lui fournit simplement une liste d'éléments susceptibles d'afficher l'image. Avant que le navigateur puisse décider de la source à afficher, vous devez lui fournir quelques informations supplémentaires : description du rendu de l'image sur la page. Pour ce faire, utilisez l'attribut sizes.

Décrire l'utilisation avec sizes

Les navigateurs sont incroyablement performants pour le transfert d'images. Les demandes de composants Image seront lancées longtemps avant les requêtes de feuilles de style ou de code JavaScript, souvent même avant que le balisage n'ait été entièrement analysé. Lorsque le navigateur effectue ces demandes, elle ne dispose d'aucune information sur la page elle-même, à l'exception du balisage. Elle n'a peut-être même pas déclenché de requêtes. pour les feuilles de style externes, et encore moins les appliquer. Dès que le navigateur analyse votre balisage et commence à rendre il ne contient que des informations au niveau du navigateur: la taille de la fenêtre d'affichage, la densité en pixels de l'écran les préférences utilisateur, et ainsi de suite.

Cela ne nous dit rien sur la façon dont une image est censée s'afficher dans la mise en page. Elle ne peut même pas utiliser la fenêtre d'affichage. en tant que proxy pour la limite supérieure de la taille img, car elle peut occuper un conteneur à défilement horizontal. Nous devons donc de fournir ces informations au navigateur à l'aide d'un balisage. C'est tout ce que nous pouvons utiliser pour ces requêtes.

Comme srcset, sizes est destiné à rendre les informations sur une image disponibles dès que le balisage est analysé. Tout comme le srcset est l'abréviation de « voici les fichiers sources et leurs tailles inhérentes », L'attribut sizes est un raccourci pour "ici" correspond à la taille de l'image affichée dans la mise en page." La façon dont vous décrivez l'image dépend de la fenêtre d'affichage : la taille est la seule information de mise en page dont dispose le navigateur lorsque la demande d'image est effectuée.

Cela peut sembler un peu compliqué sur papier, mais c'est beaucoup plus facile à comprendre dans la pratique:

<img
 sizes="80vw"
 srcset="small.jpg 600w, medium.jpg 1200w, large.jpg 2000w"
 src="fallback.jpg"
 alt="...">

Ici, cette valeur sizes informe le navigateur que l'espace de notre mise en page occupé par img a une largeur de 80vw, soit 80% de la fenêtre d'affichage. N'oubliez pas qu'il ne s'agit pas d'une instruction, mais d'une description de la taille de l'image dans la mise en page. Elle ne dit pas « faites en sorte que occupe 80% de la fenêtre d'affichage. Toutefois, "cette image finira par occuper 80% de la fenêtre d'affichage une fois la page affichée".

En tant que développeur, vous avez terminé. Vous avez décrit avec précision une liste de sources candidates dans srcset et la largeur de votre image. dans sizes. Tout comme la syntaxe x dans srcset, le reste dépend du navigateur.

Mais pour bien comprendre comment ces informations sont utilisées, prenons un moment pour passer en revue les décisions que le navigateur d'un utilisateur fait lorsqu'il rencontre ce balisage:

Vous avez indiqué au navigateur que cette image occupera 80% de la fenêtre d'affichage disponible. Ainsi, si nous affichions cette img sur un appareil doté d'une fenêtre d'affichage de 1 000 pixels de largeur, cette image occupera 800 pixels. Le navigateur prend ensuite cette valeur et la divise la largeur de chacun des candidats de sources d'image que nous avons spécifiés dans srcset. La plus petite source a une taille inhérente de 600 pixels, soit 600 ÷ 800 = 0,75. Notre image moyenne a une largeur de 1 200 pixels, soit 1 200 ÷ 800=1,5. Notre plus grande image fait 2 000 pixels de largeur, soit 2 000 ÷ 800=2,5.

Les résultats de ces calculs (.75, 1.5 et 2.5) sont des options de DPR spécifiquement adaptées aux la taille de la fenêtre d'affichage. Étant donné que le navigateur dispose également d'informations sur la densité d'affichage de l'utilisateur, il prend une série de décisions:

Avec cette taille de fenêtre d'affichage, le candidat small.jpg est supprimé quelle que soit la densité d'affichage de l'utilisateur (le taux de réponse attendu sur le graphique calculé est plus faible). que 1, cette source nécessite une augmentation pour tous les utilisateurs. Elle n'est donc pas appropriée. Sur un appareil dont le DPR est de 1, medium.jpg fournit le la correspondance la plus proche : cette source peut être affichée à une plage de dates de 1.5. Elle est donc un peu plus grande que nécessaire, mais n'oubliez pas que un processus visuellement fluide. Sur un appareil avec un DPR de 2, large.jpg est la correspondance la plus proche. Il est donc sélectionné.

Si la même image est affichée dans une fenêtre d'affichage de 600 pixels de large, le résultat serait complètement différent: 80 vw est maintenant de 480 pixels. Lorsque nous divisons nos sources nous obtenons 1.25, 2.5 et 4.1666666667. Pour cette taille de fenêtre d'affichage, small.jpg sera choisi sur 1 appareil et medium.jpg sur 2 appareils.

Cette image aura le même aspect dans tous ces contextes de navigation: tous nos fichiers sources sont identiques, indépendamment de leurs dimensions, et chacun d'eux s'affiche aussi précisément que le permet la densité d'affichage de l'internaute. Toutefois, au lieu de diffuser large.jpg auprès de chaque utilisateur Pour s'adapter aux fenêtres d'affichage les plus grandes et à la densité d'affichage la plus élevée, les utilisateurs bénéficieront toujours du candidat le plus adapté. En utilisant une syntaxe descriptive plutôt que normative, vous n'avez pas besoin de définir manuellement des points d'arrêt et de tenir compte des futures fenêtres d'affichage et Il vous suffit de fournir des informations au navigateur et de le laisser déterminer les réponses pour vous.

Étant donné que notre valeur sizes est relative à la fenêtre d'affichage et complètement indépendante de la mise en page, elle ajoute une couche de complication. Il est rare qu'une image n'occupe qu'un pourcentage de la fenêtre d'affichage, sans marges ni marges de largeur fixe, ni aucune influence. à partir des autres éléments de la page. Vous aurez souvent besoin d'exprimer la largeur d'une image à l'aide d'une combinaison d'unités. pourcentages, em, px, etc.

Heureusement, vous pouvez utiliser calc() ici. Tous les navigateurs offrant une compatibilité native avec les images responsives sont également compatibles avec calc(), ce qui nous permet de Associez des unités CSS (par exemple, une image qui occupe toute la largeur de la fenêtre d'affichage de l'utilisateur, moins une marge de 1em de chaque côté) :

<img
    sizes="calc(100vw-2em)"
    srcset="small.jpg 400w, medium.jpg 800w, large.jpg 1600w, x-large.jpg 2400w"
    src="fallback.jpg"
    alt="...">

Décrire les points d'arrêt

Si vous avez passé beaucoup de temps à travailler avec des mises en page responsives, vous avez probablement remarqué qu'il manque quelque chose dans ces exemples: l'espace occupé par une image dans une mise en page est très susceptible de changer entre les points d'arrêt de notre mise en page. Dans ce cas, vous avez besoin pour transmettre un peu plus de détails au navigateur: sizes accepte un ensemble de candidats séparés par une virgule pour la taille de rendu de la image, tout comme srcset accepte des candidats séparés par une virgule pour les sources d'image. Ces conditions utilisent la syntaxe des requêtes média familière. Cette syntaxe est la première correspondance: dès qu'une condition multimédia correspond, le navigateur arrête d'analyser l'attribut sizes et la valeur spécifié est appliqué.

Supposons qu'une image occupe 80% de la fenêtre d'affichage, moins une em de marge intérieure de chaque côté, pour les fenêtres d'affichage supérieures à 1 200 pixels. les fenêtres d'affichage plus petites, elle occupe toute la largeur de celle-ci.

  <img
     sizes="(min-width: 1200px) calc(80vw - 2em), 100vw"
     srcset="small.jpg 600w, medium.jpg 1200w, large.jpg 2000w"
     src="fallback.jpg"
     alt="...">

Si la fenêtre d'affichage de l'utilisateur est supérieure à 1 200 pixels, calc(80vw - 2em) décrit la largeur de l'image dans notre mise en page. Si le la condition (min-width: 1200px) ne correspond pas, le navigateur passe à la valeur suivante. Comme il n'y a pas de condition de contenu multimédia liée à cette valeur, 100vw est utilisé par défaut. Si vous écrivez cet attribut sizes à l'aide de max-width requête média:

  <img
     sizes="(max-width: 1200px) 100vw, calc(80vw - 2em)"
     srcset="small.jpg 600w, medium.jpg 1200w, large.jpg 2000w"
     src="fallback.jpg"
     alt="...">

En langage clair : "Est-ce que (max-width: 1200px) correspond ? Sinon, passez à autre chose. La valeur suivante, calc(80vw - 2em), n'a aucune condition de qualification, c'est donc celui-ci qui est sélectionné.

Maintenant que vous avez fourni au navigateur toutes les informations concernant votre élément img (sources potentielles, largeurs inhérentes, et la manière dont vous comptez présenter l'image à l'utilisateur. Le navigateur utilise un ensemble de règles floues pour déterminer ce qu'il faut faire ces informations. Si cela vous semble vague, c'est parce que c'est par définition. L'algorithme de sélection de la source encodé dans le La spécification HTML est explicitement vague quant à la manière dont une source doit être choisie. Une fois que les sources, leurs descripteurs et la manière L'image à afficher a été analysée, le navigateur est libre de faire ce qu'il veut. Vous ne pouvez pas savoir avec certitude la source choisie par le navigateur.

Une syntaxe qui dit "utiliser cette source sur un écran haute résolution" serait prévisible, mais ne résoudrait pas le problème principal avec des images dans une mise en page responsive, ce qui permet de préserver la bande passante de l'utilisateur. La densité de pixels d'un écran n'est que partiellement liée à Internet la vitesse de connexion, le cas échéant. Si vous utilisez un ordinateur portable haut de gamme, mais que vous naviguez sur le Web au moyen d'une connexion limitée, le partage de connexion est activé. à votre téléphone ou si la connexion Wi-Fi en avion est instable, il peut être préférable de désactiver les sources d'image haute résolution, quel que soit la qualité de votre écran.

Le fait de laisser le dernier mot au navigateur permet d'améliorer les performances de bien plus que ce que nous pourrions gérer avec une syntaxe. Par exemple, dans la plupart des navigateurs, une img utilisant la syntaxe srcset ou sizes ne demandera jamais une source dont la taille est plus petite que celles déjà présentes dans le cache de l'utilisateur. À quoi sert-il d'envoyer une nouvelle demande de source ? Cela semble identique, alors que le navigateur peut facilement réduire la taille de la source d'images qu'il possède déjà ? Mais si l'utilisateur adapte ses jusqu'au moment où une nouvelle image est nécessaire afin d'éviter toute augmentation de la taille de la fenêtre, cette requête est quand même effectuée. Ainsi, tout est conforme à vos attentes.

Ce manque de contrôle explicite peut sembler un peu effrayant au premier abord, mais comme vous utilisez des fichiers sources avec des fichiers contenu, il est peu probable que nous présentions aux utilisateurs qu'avec une src à source unique, les décisions prises par le navigateur.

Utiliser sizes et srcset

Cela représente beaucoup d'informations, à la fois pour vous, le lecteur et pour le navigateur. srcset et sizes sont des syntaxes denses, décrivant une quantité d'informations choquante en relativement peu de caractères. En d'autres termes, pour le meilleur ou pour le pire, ces syntaxes moins simples (et plus facilement analysées par nous, humains), auraient pu les rendre plus difficiles à analyser pour un navigateur. La plus une chaîne est complexe, plus il y a de risques d'erreurs d'analyseur ou de différences de comportement involontaires d'un navigateur à un autre. Il y a cependant un avantage ici: une syntaxe plus facile à lire par les machines est une syntaxe plus facile à écrire par elles.

srcset est un cas d'utilisation clair pour l'automatisation. Il est rare de créer manuellement plusieurs versions de vos images pour environnement de production, mais en automatisant le processus à l'aide d'un exécuteur de tâches comme Gulp, d'un bundler comme Webpack, un CDN comme Cloudinary, ou une fonctionnalité déjà intégrée au CMS de votre choix. Nous disposons de suffisamment d'informations pour générer nos sources. en premier lieu, un système dispose de suffisamment d'informations pour les écrire dans un attribut srcset viable.

sizes est un peu plus difficile à automatiser. Comme vous le savez, un système peut uniquement calculer la taille d'une image la mise en page affichée est l'affichage de la mise en page. Heureusement, de nombreux outils de développement ont fait leur apparition pour éliminer le processus d'écriture manuscrite des attributs sizes, avec une efficacité que vous ne pourriez jamais associer à la main. respImageLint, par exemple, est un extrait de code destiné à vérifier vos attributs sizes pour plus d'exactitude et de fournir des suggestions d'amélioration. Le projet Lazysizes présente des compromissions pour gagner en efficacité en reportant les requêtes d'image jusqu'à ce que la mise en page soit établie, ce qui permet à JavaScript de générer automatiquement des valeurs sizes. Si vous utilisez un framework de rendu entièrement côté client tel que React ou Vue, il existe un Nombre de solutions permettant de créer et/ou de générer des attributs srcset et sizes. Nous en reparlerons dans la section CMS et frameworks.