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" />
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 :
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.
Bonjour, chez moi avec :
j'ai deux images qui s'affichent...que ce soit sur mobile ou ordi... une idée du problème ? merci
Bonjour Gaeil,
je suis désolé, vous avez dû mettre du code dans votre message mais celui-ci a été "digéré" et du coup je ne le vois pas. Pouvez-vous rééssayer de me le renvoyer en remplaçant les caractères < et > par des parenthèses ou des crochets par exemple ?
Bonjour, oui désolé..le filtre ne laisse pas passer le html (tant mieux !)
En fait c'est moi qui avait laissé trainé une première ligne d'un essai précédent (vu qu'il y a plusieurs versions possible,j'en ai essayé 2 ou 3.
et forcément il affiche les 2 lignes de codes...donc 2 images...
Comme on dit, en informatique, le problème, il est souvent sur la chaise LOL
Alors j'ai deux images en header.
pour la première j'ai mis ce code
[source srcset="../images/bandeau_haut_1140x124_br.webp" type="image/webp"]
[source srcset="../images/bandeau_haut_1140x124_br.jpg" type="image/jpg"]
<img src="../images/bandeau_haut_1140x124_br.jpg" width="1140" height="124" alt="Logo Les Chemins Vers Compostelle" title="Les Chemins Vers Compostelle" class="img-responsive" /]
[/picture]
------
et pour la deuxième image (pour essayer de charger une image moins lourde sur les mobiles )
picture]
[img srcset="images/villar_de_Mazarife_mob_330x52-br.webp 350w,
images/villar_de_Mazarife_br_1142x180.webp 1260w"
sizes="(max-width: 600px) 350px,800px"
src="images/villar_de_Mazarife_br_1142x180.jpg" width="1140" height="180" alt="Villar de Mazarife Compostelle" title="Villar de Mazarife Chemin Vers Compostelle"/]
[/picture]
Mais quand je consulte avec mon mobile (6"), et que je regarde quelle est l'image que je peux enregistrer (quand je laisse mon doigt sur l'écran du mobile) je vois que l'image qu'il me propose d'enregistrer et celle de 1142x180...du coup je ne sais pas si cette instruction fonctionne vraiment...
du coup je vais essayer votre code avec les instructions du type chemin/mon-image-S.jpg,chemin/mon-image-M.jpg etc.
rebonjour,
donc j'ai testé votre code (ci-dessous) fonctionne parfaitement pour ma deuxième image. sur le mobile il affiche bien la petite image prévue pour les mobiles.
[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" /....
merci !
Haha oui, j'entends souvent la variante "entre la chaise et la souris" aussi :)
Après selon les navigateurs il peut aussi arriver que ce soit une image plus grande qui est utilisée, parce qu'elle a été enregistrée dans le cache du navigateur précédemment (notamment quand on fait des tests comme ça parce qu'en production c'est moins probable), et donc c'est plus intéressant d'utiliser cette image en cache plutôt que d'en charger une autre, même plus petite.
Super intéressant comme article et très clair! Je recherchais justement comment optimiser l’affichage de l’image de la home page selon qu’on visualise sur desktop, tablette graphique ou mobile.
Pourquoi avoir choisi en particulier les valeurs max-width: 340px, 1260px et 1920px? Est ce le bon compromis en pensant paysage et portrait?
Merci !
Bonjour Vincent, et merci pour le retour !
Ce sont des valeurs plus ou moins arbitraires, sans aucun lien particulier avec l'orientation (portrait/paysage).
Dans mon cas, je conçois en général le responsive design de mes sites par paliers de largeur via des media queries, ces valeurs pourraient par exemple correspondre à ces paliers. Par exemple dans une tranche de tailles d'écran disons de 601px à 980px de large de large, on peut imaginer un contenu de largeur fixée à 580px, et donc les images n'ont pas besoin d'être plus larges que ça, on pourra alors leur attribuer un srcset de cette dimension entre autres.
Dans tous les cas, je me base sur la hauteur, donc que l'image soit horizontale ou verticale m'importe peu :)
Bonne journée !