HTML

Responsive Images – L'arrivée de srcset

Article par (WebDesigner grapilleur de Kiwiz, Strasbourg)
Créé le , mis à jour le (98120 lectures)
Tags : image, performance, responsive, srcset, picture

Le gros problème du Responsive Web Design tient probablement dans la gestion des ressources chargées et utilisées sur une page web, utiles à notre terminal et adaptées à notre écran ou notre fenêtre de consultation. Stéphanie nous en parlait déjà avec Responsive Webdesign - présent et futur de l'adaptation mobile.

Je vous avais parlé l'an dernier de l'annonce du moteur WebKit (12 août 2013) concernant son support de l'attribut srcset ; c'est aujourd'hui Google qui publie la version 34.0.1847.116 (retenez 34, ça suffira) de son navigateur Chrome (qui est passé sous moteur Blink, fork récent de WebKit). Parmi les mises à jour, on retrouve les corrections de sécurité habituelles, mais également la prise en charge partielle de l'attribut srcset pour les éléments images <img>.

L'attribut srcset, principes

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.

Attribut srcset : exemple

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. Voici par exemple une utilisation envisageable de l'attribut srcset :

<img src="mon-image.jpg" srcset="mon-imageHD.jpg 2x" width="" height="" alt="">

Et un peu plus élaboré :

<img src="mon-image.jpg"
     srcset="mon-image.jpg 1x,
             mon-image-320.jpg 320w 1x,
             mon-image-640.jpg 320w 2x"
     width="850" height="475" alt="">

Dans cet exemple, une image de 850 pixels de large est chargée grâce à src. Cela permet aux navigateurs ne prenant pas en charge l'attribut srcset de charger une image de contenu. Les autres navigateurs vont vérifier s'ils trouvent une correspondance dans les critères de srcset, s'ils ne trouvent rien ils chargeront l'image de base, autrement ils chargeront une image adaptée.

La syntaxe de la valeur d'attribut est la suivante :

<adresse-de-l-image> [critère( critère)](, <adresse-de-l-image> [critère( critère)])

Si le ou les critères (entre crochets) correspondent au terminal qui consulte la page web, alors l'image (entre crochet) sur la gauche du critère sera chargée.

Dans l'exemple précédent nous avons plusieurs alternatives pour chaque image :

  • 1x : cas d'une densité de pixels égale à 1 (correspondant en fait à notre valeur de src ici)
  • 320w 1x : propose une image dont la largeur est égale à 320px (iPhone 3 pourrait l'apprécier par exemple)
  • 320w 2x : propose une image dont la largeur est égale à 320px et où la densité de pixels est inférieure ou égale à 2 (iPhone 4 par exemple)

Une image correspondante sera chargée, et uniquement celle-ci afin d'éviter le chargement des images inutilisées.

À ce niveau, la spécification offre quelques libertés d'interprétation et donc d'implémentation, puisqu'elle dit la chose suivante :

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.

Démonstration

Particularité et problèmes à prévoir

La syntaxe n'est pas forcément intuitive et ne nous dit rien sur le sens des critères attribués à chaque image.
S'agit-il d'une égalité à la valeur du critère, d'une limite haute ou d'une limite basse ? Pour comprendre le comportement attendu, il faut... lire la doc ! (qui peut rapidement changer sur ce genre de module)

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 fait Chrome 34+ (j'avais bien le droit d'en douter !), et c'est une bonne nouvelle. Il ne reste plus qu'à voir cela appliqué aux navigateurs "mobiles" (cela commence doucement avec iOS 8)

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="">

Chrome charge ici l'image Big, ce qui est le comportement attendu dans notre cas. (la version 32 était boguée et ne prenait en compte que la première image mentionnée dans srcset)

Test N°4 : Les correspondances multiples

Ici je me concentre principalement sur un test (idiot, certes) avec le descripteur x.

<img src="mon-image.jpg"
     srcset="mon-image-big.jpg 1x,
             mon-image-hd.jpg 1x"
     width="850" height="475" alt="">

L'image "big" est bien chargée et affichée, aucun autre chargement d'image n'est effectué. le navigateur utilise donc la première image qui satisfait ses critères.

Test N°5 : Les correspondances multiples (2è test)

Cette fois je teste une correspondance en densité (descripteur x) et suivie d'une correspondance en taille (descripteur w), puis j'inverse l'ordre dans la seconde image

<img src="images/logo-nope.png"
     srcset="images/logo-big.png 1x,
          images/logo-hd.png 1920w"
     width="1824" height="499" alt="">

<img src="images/logo-nope.png"
     srcset="images/logo-big.png 1920w,
          images/logo-hd.png 1x"
     width="1824" height="499" alt="">

À chaque fois, la première image satisfaisant aux critères est affichée (dans une lecture linéaire de la valeur de l'attribut srcset).

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

L'attribut srcset peut être couplé à l'attribut sizes dont nous vous proposerons un article prochainement.

Le support commence à être interessant, attendons de voir ce que vont proposer les prochaines implémentations.

Navigateurs Versions Détails
Internet Explorer Internet Explorer Non supporté
Firefox Firefox
Firefox Mobile
Firefox 38 + 

Non supporté
Supporté

Chrome Chrome 34+
Chrome Mobile 34+

Chrome Mobile 38+
Partiellement supporté
Partiellement supporté
Supporté
Opera Opera 26+
Opera Mobile 24+
Supporté
Partiellement supporté
Safari

Safari 7.1+
Safari Mobile 8.0+

Partiellement supporté
Partiellement supporté
Android Browser Android Browser 37 + 
Chrome for Android 4.0
Supporté

3 octobre 2014 : cet article a été mis à jour pour correspondre à la dernière version de la spécification et des supports. Merci à HTeuMeuLeu pour son coup de pied aux fesses pour la mise à jour de cet article

5 mars 2015 : mise à jour de l'article suite au passage officiel de srcset dans la spécification HTML5, mise à jour du tableau de support 

Ressources

Commentaires

Manumanu a dit le

Très bon article, merci !

Jconline a dit le

Article excellent :)
Mais d'un côté vue la situation actuelle c'est un peu con.
C'est un attribut qui serait excellent pour les mobiles et divers autres supports. Alors que pour l'instant il n'y a que la toute dernière version de Chrome version bureau qui le gère. Et j'ai pas souvent un écran 5 pouces sur mon PC portable ou fixe.
Par contre, dès que les navigateurs mobile l'implémenteront ça sera super :)

sizvix a dit le

Je gérais ça avec les média queries, mais donc ce n'était pas une balise "img"
Dans l'idée, je me demandais si la gestion de tailles d'image n'avait pas plus sa place dans le CSS ( gestion de Style ) ? ( c'est une question que je me pose ... )

Geoffrey C. a dit le

Merci pour vos commentaires.

@Jconline : On vient de me préciser que la dernière version de Chrome Mobile (34 également) supporte srcset et les critères de densité de pixels. :) (merci @eQRoeil sur Twitter)

@sizvix : d'un point de vue visuel oui, mais là on parle d'une possibilité de distribuer la bonne image au bon terminal (suivant ses capacités d'affichage). C'est davantage un problème de performance qu'un problème de style. Après CSS peu intervenir en complément pour gérer les problèmes de débordement, mais ce sont deux choses distinctes.

Olivier C a dit le

Génial. Maintenant il va juste falloir attendre 5 ans pour en tirer avantage. Encore prématuré pour l'implémentation en prod', mais merci pour la veille techno.

Geoffrey C. a dit le

@Olivier C : le seul point qui m'intéresserait serait le support des critères de viewport, et pour le moment c'est un peu caca... du coup oui, il va falloir attendre un peu. (5 ans je ne pense pas :p)

zemax a dit le

Si 2x c'est une limite haute, ça veut dire que les devices 3x (comme le Galaxy S4, le Nexus 5, etc...) chargeront l'image par défaut ?

Didodu258 a dit le

Sinon faut le faire en javascript et php (ou autre langage utilisé côté serveur), on commence par charger du js côté client qui va nous donner la taille de l'image voulu (sa qualité aussi pourquoi pas en fonction de la densité de pixels) et on va cherche l'image en question via AJAX, PHP se charge de compiler l'image tout comme il faut. Et ça marchera même sous ie6 :)

deejay-bee a dit le

Avoir ce que ça va donner avec un éditeur wysiwyg !

Geoffrey C. a dit le

@Didodu258 : et pour les utilisateurs sans JS ? Pas d'image ?

@deejay-bee : une fois que le support sera meilleur, des solutions vont naître, je ne me fais pas de souci pour cela :)

Didodu258 a dit le

@Geoffrey C. : Non il faut réussir à détecter l'utilisation de javascript ou non. Il y a des solutions proposées ici : http://stackoverflow.com/questions/121203/how... (je n'ai pas fait de tests mais à priori les balises noscript peuvent nous être très utile...)
Si j'ai le temps je ferais peut-être une librairie pour gérer tout ça.

Timothee a dit le

nope sur Tab Samsung 10'

JeanMarc_D a dit le

Merci pour cet article fort inintéressant.
A en croire cet article : http://www.w3.org/community/respimg/2013/10/1...
IL n'est pas certain que l'attribut srcset devienne la norme.
A suivre donc.

JeanMarc_D a dit le

Toute mes excuses, ah l'autocorrection je voulais dire intéressant bien entendu !
ça serait tout de même sympa de pouvoir rééditer son message après envoi.