Une image toujours adaptée avec srcset et sizes

Saviez-vous que le responsive design n'est pas qu'une histoire de CSS ? Il y a des cas où l'on peut également utiliser du javascript, mais aussi directement du HTML. C'est ce que l'on va voir ici à propos des images.

Concrètement, vous gérez comment vos images lorsque vous voulez les adapter au mobile ? On peut se contenter d'une grande image, que l'on réduit en version mobile. Classique, la plupart du temps adapté (les écrans haute définition étant généralement sur smartphone, on fait d'une pierre deux coup car en réduisant la taille on augmente la densité de pixels). Mais pas optimisé. D'autres vont traiter ça en javascript : on vérifie la taille d'écran, et on remplace l'attribut src d'une image en conséquent. C'est peut-être pire, car à moins que le script ne crée également l'élément <img> ou son src, le navigateur va charger l'image originale puis l'image appelée via le script.

Eh bien sachez qu'il est possible, avec seulement du HTML, de proposer au navigateur différentes images avec des indications comme la taille d'écran, sa résolution, ou le type de fichier. Ensuite, le navigateur se débrouillera comme un grand pour choisir celle qu'il juge la mieux appropriée.

Dans cet article, nous allons jouer avec trois images. "S", qui fait 300px de large, conçue pour un smartphone : format carré, poids léger... "M", qui est une image classique adaptée pour un écran "desktop", d'une largeur de 1024px. Et enfin, "L", une image panoramique de 1920px de large, conçue pour les grands écrans.

Utilisation des attributs srcset et sizes dans la balise <img>

De base, nous utiliserions notre image ainsi :

<img src="/chemin/mon-image.jpg" width="1024" height="768" alt="Un exemple" />

L'image mon-image.jpg sera alors chargée dans tous les contextes d'affichage. Mais l'attribut srcset va permettre de proposer plusieurs images au navigateur, qui va choisir celle qu'il juge la mieux adaptée. L'attribut srcset s'écrit de cette façon : url-de-l-image.xxx indication.

Pour l'url de l'image je ne vous fais pas de dessin, vous connaissez :). Quant à l'indication, elle peut être de deux types :

Cibler la densité de pixels

Vous pouvez choisir une image en fonction de la densité de pixels de l'écran (par exemple écran classique ou écran retina). Pour cela, on cible avec ce qui s'appelle un "x-descriptor". Il suffit alors de mettre le rapport de densité, par défaut 1, suivi de "x" :

<img srcset="/chemin/mon-image.jpg 1x,
             /chemin/mon-image-HD.jpg 2x"
     src="/chemin/mon-image.jpg" alt="Un exemple" />

Ici, le navigateur utilisera mon-image.jpg sur un écran normal, et mon-image-HD sur un écran haute résolution (en l'occurrence, un écran qui fait deux fois la résolution standard ou plus). Si vous souhaitez utiliser des décimales, mettez un point et non une virgule : 1.5x.

Dans ce cas là, l'attribut sizes n'a aucune utilité, mais j'en parle dans la partie suivante ;)

Vous avez également dû remarquer que j'ai laissé l'attribut src. Celui-ci vient tout simplement prendre le relais quand le navigateur ne supporte pas srcset (au hasard, Internet Explorer), histoire d'avoir quand même une image !

Cibler la largeur d'écran

L'autre alternative, c'est d'utiliser un "w-descriptor". Le principe consiste alors à indiquer au navigateur la taille de l'image, sans unité, suivie de "w" :

<img srcset="/chemin/mon-image-S.jpg 300w,
             /chemin/mon-image-M.jpg 1024w,
             /chemin/mon-image-L.jpg 1920w"
     src="/chemin/mon-image.jpg" alt="Un exemple" />

Mais il est possible d'affiner le choix des tailles en utilisant en parallèle l'attribut sizes. Celui-ci permet de dire, via une media query suivie d'une taille, à quelle taille afficher l'image en fonction du contexte.

<img srcset="/chemin/mon-image-S.jpg 300w,
             /chemin/mon-image-M.jpg 1024w,
             /chemin/mon-image-L.jpg 1920w"
     sizes="(max-width: 340px) 300px,
            (max-width: 1260px) 1000px,
            1920px"
     src="/chemin/mon-image.jpg" alt="Un exemple" />

Un coin sympa mais frisquet

Dans cet exemple, le navigateur utilisera l'image qu'il juge la plus adaptée et l'affiche avec une largeur de 300px sur une fenêtre d'une taille inférieure à 340px, une largeur de 1000px pour une fenêtre qui fait entre 341 et 1260px de large, et une largeur de 1920px dans les autres cas.

Je ne comprends pas, quand je change la taille de mon écran, la taille de l'image change bien, mais c'est toujours L qui est utilisée...

C'est normal ! Comme je vous le disais, c'est le navigateur qui choisis l'image la plus adaptée. À l'heure où je vous écris ces lignes, on aura par exemple Firefox qui se dira "Tiens, on est à la taille d'écran pour l'image M, je vais donc lui afficher M avec la largeur définie". Et Chrome, qui lui se dira "Tiens (oui, les navigateurs se disent beaucoup "tiens"), on est à une largeur adaptée pour la taille M, mais j'ai déjà L en cache qui est de meilleure qualité. Je ne vais donc pas charger une ressource supplémentaire, mais plutôt afficher L avec la largeur définie pour M".

Vous voyez la petite subtilité ? C'est pourquoi mes images ne sont pas adaptées à cette utilisation, car elles ont des formats différents (carré/standard/panoramique).

Ici, l'utilisation la plus adaptée serait d'avoir des images proportionnellement et visuellement identiques. Seules leurs dimensions changeraient. Ainsi, le but est vraiment de limiter l'impact du poids d'une image au chargement de la page.

Notez bien que dans l'éventualité où vous ne précisez aucun "descriptor", ça sera "1x" qui sera utilisé par défaut. Autre point, on ne peut pas combiner plusieurs types de "descriptor" dans un même srcset, ni en utiliser deux identiques.

Utilisation de l'attribut srcset dans la balise <picture>

Si, comme moi, vous vouliez utiliser différents formats d'image en fonction de la taille de l'écran, alors il vous faudra plutôt utiliser la balise <picture> et ses enfants <source>.

Le principe est légèrement différent. Il ne s'agit plus d'une seule et même balise qui contient plusieurs attributs, mais d'une imbrication de plusieurs balises.

Pour commencer avec une transition, voici l'utilisation avec <picture> qui reproduit exactement le même comportement que ce que l'on vient de voir avec <img> :

<picture>
    <source srcset="/chemin/mon-image-S.jpg 300w,
             /chemin/mon-image-M.jpg 1024w,
             /chemin/mon-image-L.jpg 1920w"
     sizes="(max-width: 340px) 300px,
            (max-width: 1260px) 1000px,
            1920px" />
    <img src="/chemin/mon-image.jpg" alt="Un exemple" />
</picture>

Ici, c'est <source> qui permet de définir l'image à utiliser, et <img> qui sert de fallback si le navigateur ne connaît pas <picture> et <source>. Mais cet exemple n'est pas intéressant, car ici l'utilisation que l'on a vue juste avant serait plus simple.

Dans le cas qui nous intéresse, à savoir utiliser des images de formats différents (même sur Chrome, entre autres), on construira plutôt notre code ainsi :

<picture>
    <source srcset="/chemin/mon-image-S.jpg" media="(max-width: 340px)" />
    <source srcset="/chemin/mon-image-M.jpg" media="(max-width: 1260px)" />
    <source srcset="/chemin/mon-image-L.jpg" />
    <img src="/chemin/mon-image.jpg" alt="Un exemple" />
</picture>

On utilise donc plusieurs balises <source>, dont l'attribut media permet son activation ou non en fonction d'une media query. Ce code pourrait être traduit ainsi : "Si ton viewport a une largeur maximale de 340px, tu affiches l'image S. Si sa largeur maximale est de 1260px, alors utilise plutôt l'image M. Sinon, utilise l'image L". En tout cas pour les cas où le navigateur connaît ces instructions, sinon il se dira simplement "Picture ? j'sais pas ce que c'est, on va dire un bloc. Source ? Ils parlent bizarrement les gens de nos jours... Ah, img ! Ok, alors je dois afficher mon-image.jpg".

Le résultat sera donc le suivant :

Un coin sympa mais frisquet

Bien sûr, comme on utilise des media queries, les possibilités sont assez grandes en terme de sélection d'images.

En savoir plus sur les Media queries

Que ce soit directement dans une balise <img> ou dans <picture>, cette fonctionnalité qui permet de ne charger que l'image adaptée est très pratique. Mais en pratique, ce n'est pas toujours adaptable au CMS que vous utilisez (si vous en utilisez un), et moins simple à mettre en place qu'une simple balise <img> avec son attribut src.

Si vous avez trouvé cet article intéressant, pourquoi ne pas le partager ? :)
Facebook Messenger Twitter LinkedIn Viadeo Reddit Email

Vous avez une remarque, une précision à apporter, ou quelque-chose vous échappe ?
N'hésitez pas à participer à cet article, cet espace est pour vous !

Personne n'a encore commenté cet article.

Mais il faut bien un début à tout, pas vrai ?

Commenter, poser une question...

 

Ces articles pourraient également vous intéresser

Tout savoir sur les media queries pour un site responsive design réussi

Sur les media-quoi ? Responsive design ? Bon, si vous êtes ici c’est que vous avez déjà au moins entendu parler de ces termes, et probablement que vous savez également de quoi il s’agit. Pour les autres, voici un petit récapitulatif !

Lire l'article Tout savoir sur les media queries pour un site responsive design réussi
Remonter