Entre les images floues sur écrans rétina, mal adaptées ou trop lourdes, il n'est pas toujours évident de gérer les différentes ressources graphiques sur l'ensemble des surfaces et des périphériques. Les techniques de Responsive Web Design tiennent parfois (souvent) de la bidouille et il est difficile de distinguer les bonnes pratiques d'intégration.
Au sein des différentes spécifications existantes et des techniques utilisables en production, srcset
, sizes
et <picture>
sortent du lot aujourd'hui. Dans cet article, nous allons tenter de mieux comprendre comment fonctionne vraiment srcset
.
Note : cet article a été initialement rédigé en avril 2014 par Geoffrey Crofte. Il a subi une refonte intégrale en mai 2017 pour se mettre à jour et s'étoffer considérablement.
Images fluides, l'échauffement
Lorsque vous insérez une image dans votre page web, il y a de fortes chances pour que vous utilisiez un code semblable à :
<img src="mon-image.jpg" width="850" height="475" alt="">
Ce code vous permet de charger une image en réservant un espace de 850 pixels de large aussi bien sur un écran classique que sur un écran de smartphone. Avec un peu de prévoyance, vous avez un code CSS bien construit qui vous permet de redimensionner l'image pour éviter les débordements.
img {
max-width: 100%;
height: auto;
}
Mais vous conviendrez que charger une image de 850 x 475 px n'est pas très adapté sur un écran de 320 px de large (si on prend comme exemple la largeur actuelle gérée par l'iPhone). Une image de cette taille pèse environ 150 Ko (compression de 40% sur une photographie), là où une image adaptée de 320 x 179 px ferait environ 23 Ko avec la même compression. Soit une différence de 127 Ko, multiplié par le nombre d'images du même genre dans votre page.
srcset
, pour piocher la bonne ressource
L'attribut srcset
vient apporter une solution à ce problème en vous permettant de définir une image adaptée au terminal de consultation en ciblant la taille de l'écran, et également la densité de pixels.
Au sein de cet attribut srcset
, les spécifications prévoient deux types de descripteurs permettant de conditionner le chargement des ressources :
- le descripteur "x" sélectionne l'image en fonction de la densité de pixel (pixel ratio) de l'écran
- le descripteur "w" sélectionne l'image en fonction de sa taille et de l'adéquation à la surface de l'écran
srcset
et le descripteur "x"
Le descripteur "x", appelé officiellement "pixel density descriptor" correspond - sans surprise - au pixel ratio de l'écran. C'est un bon moyen de cibler les écrans dits rétina (pixel-ratio 2) ou HD notamment.
Le nombre exprimé dans ce descripteur peut contenir des décimales mais doit forcément être positif. La valeur par défaut de ce descripteur, s'il est absent est "1x".
Voici par exemple une utilisation envisageable de l'attribut srcset
combiné au descripteur "x" :
<img src="mon-image.jpg" srcset="mon-imageHD.jpg 2x" alt="">
Dans cet exemple, voici ce qui se passe :
- si le navigateur ne reconnaît pas
srcset
, il charge et affiche l'image proposée dans l'attributsrc
- sinon, dans le cas où le navigateur se sent proche d'un pixel-ratio de 2, il chargera mon-imageHD.jpg et sinon il choisira mon-image.jpg.
srcset
et le descripteur "w"
Le descripteur "w", pour "width descriptor" informe le navigateur de la largeur de l'image proposée. La valeur précédant "w" désigne bien la taille de l'image et non du viewport ou de la surface de l'écran.
Voici par exemple une utilisation envisageable de l'attribut srcset
combiné au descripteur "w" :
<img src="mon-image.jpg"
srcset="mon-image-320.jpg 320w,
mon-image-640.jpg 640w"
alt="">
Dans cet exemple, j'indique clairement au navigateur : "je dispose de deux images dont la première a une largeur de 320px et l'autre 640px, débrouille-toi avec ça pour piocher la meilleure".
Selon les spécifications, le navigateur va devoir tenir compte de plusieurs paramètres dans son choix :
L’agent utilisateur va calculer la densité de pixel réelle de chaque image à partir du descripteur w spécifié et des tailles de rendus spécifiées dans l’attribut sizes. Il peut ensuite choisir n’importe quelle ressource en fonction de la densité de pixels de l’écran de l’utilisateur, de son niveau de zoom, ou peut-être d’autres facteurs comme les conditions de réseau de l’utilisateur.En gros, si l'utilisateur dispose d'un device de 320px de large, l'image chargée sera mon-image-320.jpg; Par contre, sur une surface plus vaste, le choix risque de se porter plutôt sur mon-image-640.jpg.
Les choses se compliquent un peu en sachant que si descripteur "w" est employé, alors l'attribut sizes
s'applique forcément.
Notez qu'il n'est pas autorisé de combiner un descripteur "x" et un descripteur "w" dans la même condition d'un srcset
.
srcset
et l'attribut sizes
L'attribut sizes permet d'indiquer au navigateur quelle doit être la largeur finale de l'image à l'affichage.
Par exemple :
sizes="1000px"
précise au navigateur que l'image au final occupera 1000px de large sur l'écransizes="100vw"
indique que l'image choisie devra occuper toute la largeur du viewport
Il s'agit d'une information essentielle pour permettre au navigateur de choisir la bonne ressource, car il devra jongler entre sa largeur effective, la largeur souhaitée de l'image mais aussi de sa densité de pixel.
Voici par exemple une utilisation envisageable de l'attribut srcset
combiné au descripteur "w" et à l'attribut sizes
:
<img src="mon-image.jpg"
srcset="mon-image-320.jpg 320w,
mon-image-640.jpg 640w"
sizes="100vw"
alt="">
Dans cet exemple, nous indiquons au navigateur que l'image devra au final occuper toute la surface. Son choix risque d'être celui-ci :
- un iPhone 3 dont la taille est de 320px chargera mon-image-320.jpg
- un iPhone 4 dont la taille est de 320px mais où la densité de pixels est de 2 chargera mon-image-640.jpg
Notez les informations complémentaires suivantes :
- Il n'est pas autorisé d'employer l'unité % en valeur de
sizes
(les unités courantes sontvw
oupx
) - la valeur par défaut de
sizes
est 100vw - si
sizes
est présent dans l'élément<img>
, alors le descripteur "w" est obligatoire
Image affichée VS image(s) chargée(s) ?
L'un des intérêt de cet attribut est qu'il prenne la place de l'attribut src
si l'un des critères est validé, l'avantage étant, de ce fait, de ne charger que l'image la plus intéressante pour le terminal qui consulte votre page web. D'ailleurs le processus est détaillé sur la page du W3C.
Figurez-vous que c'est exactement ce que font les navigateurs actuels (desktop et mobile).
Mais comment réagit le navigateur s'il rencontre deux images dont les critères correspondent ?
Très bonne question, nous nous la sommes posée. Pour effectuer le test, nous avons regroupé plusieurs images identiques dans leurs proportions et ajouté un mot dessus pour détecter rapidement laquelle est chargée. Puis nous avons appliqué des critères bidons et des critères correspondant à notre terminal de test (viewport 1920px, densité de 1.0).
Test N°1 : La densité
<img src="mon-image.jpg"
srcset="mon-image-big.jpg 1x,
mon-image-hd.jpg 2x"
width="850" height="475" alt="">
L'image "big" correspondant au critère "1x" est chargée, donc tout va bien.
Test N°2 : L'absent
<img src="mon-image.jpg"
srcset="mon-image-hd.jpg 2x"
width="850" height="475" alt="">
Ici aucun critère de srcset
ne correspond, l'image du src
est chargée.
Test N°3 : Le viewport
<img src="mon-image.jpg"
srcset="mon-image-320.jpg 320w,
mon-image-big.jpg 1920w"
width="850" height="475" alt="">
L'image "big" est chargée, ce qui est le comportement attendu dans notre cas.
Il est important de retenir que srcset
offre au navigateur une information sur les images et leur utilisation attendue. Une image de 500px (500w
) de large proposée à un iPhone 4S (viewport 320px avec ratio de 2) ne satisfait pas pleinement le ratio de 2, il se pourrait donc que le terminal s'oriente vers une image plus grande si vous en proposez d'autres.
Support et limites
Le support de srcset
est aujourd’hui assez large.
Navigateurs | Versions supportées | Détails / Commentaires |
---|---|---|
Internet Explorer |
Non supporté sur Internet Explorer Supporté depuis Edge 15 |
|
Firefox 38+ Firefox Mobile | OK |
|
Chrome 38+ Chrome Mobile |
OK OK |
|
Opera 25+ Opera Mobile |
OK
OK |
|
Safari 7.1+ |
Support partiel avant Safari 9, complet ensuite
Support partiel avant Safari Mobile 9.2, complet ensuite
|
|
Android Browser Chrome for Android |
Pas de support Android Browser Support depuis Chrome Mobile |