Placer iconographie du dossier ici English speaking audience : a translation is available here.
Ce billet fait partie de la série en <img /> :
  1. Histoires en <img />
  2. Manuel en <img />
  3. Ressources en <img />
  4. Bricolages en <img />
  5. Progressivement en <img />
  6. Finesse en <img />
  7. Proposition en <img /> / English version

Maintenant que j'ai bien expliqué les soucis de l'affichage d'une image en fonction de la finesse du support, et présenté différents hacks pour y arriver, voyons la proposition du W3C, là où elle me fait tiquer… et proposons quelque chose de constructif.

Sherlock à la loupe en contreplongée
© BBC. Source : Perfect Benny

Au sein des communautés W3C, le groupe Responsive Image réfléchit à trouver une solution élégante au problème des finesses d'images. C'est comme ça qu'après de nombreuses négociations est arrivé l'attribut <img srcset="" />. La fonction de l'attribut consiste à remplacer à la volée la ressource indiquée en src="" en fonction de différentes règles d'affichage, dont la finesse de la résolution. L'idée originelle ne travaillait que cette question.

srcset="" selon sa doc

Attention : Cet attribut est en chantier, ni sa notation, ni son adoption ne sont définitives, et la version la plus récente est actuellement chez le Responsive Image Community Group. En fait, il doit être vu avec la même précaution qu'une expérimentation et avec les mêmes retenues que pour tout préfixe propriétaire javascript ou css, dont il n'existe malheureusement pas de notation expérimentale en html5.

La syntaxe de l'attribut repose sur une liste, séparée par des ,. Chaque élément de la liste est une url ressource, suivi par des règles en fonction de la largeur disponible (640w) ou de la finesse de la résolution d'affichage (4x)

Si je reprends le brouillon de référence du W3C, on peut donc avoir soit une discrimination en fonction de la largeur disponible :
<img src="pear-desktop.jpeg" srcset="pear-mobile.jpeg 720w, pear-tablet.jpeg 1280w" />
soit du pitch de l'écran :
<img src="pear-desktop.jpeg" srcset="pear-mobile.jpeg 2x, pear-tablet.jpeg 4x" />
soit des deux :
<img src="pear-desktop.jpeg" srcset="pear-mobile.jpeg 720w, pear-tablet.jpeg 1280w, pear-desktop.jpeg 1x" />

Vous l'avez compris, on a à la fois des redites, et mélangé les problématiques de finesse d'affichage et de responsive webdesign. Avouez que dans une telle cafouillade, on n'est vraiment sûr de rien, une chatte y perdrait ses petits.

<img src="/vrac/.blog2/webdev/1403-Img/.1406-Img-KittyPrinter_s.jpg" srcset="/vrac/.blog2/webdev/1403-Img/.1406-Img-KittyPrinter_m.jpg 2x , /vrac/.blog2/webdev/1403-Img/1406-Img-KittyPrinter.jpg 4x" alt="" />
« Our kitty printer is running out of toner »
Tu m'étonnes.

Une idée qui risque de tourner à l'échec

L'attribut est déjà implémenté sur certains navigateurs, enfin surtout Chrome quand ils étaient encore avec le moteur webkit. Firefox vient de le mettre en place en Nightly la semaine dernière, donc arrivera probablement avec Firefox 32 dans 3 mois, Apple le promet pour iOS8. L'équipe IETeam de Microsoft considère d'implémenter l'attribut.

Capture d'une partie d'écran, extrait du tweet d'Addy Osmani annonçant la fonction dans Firefox Nightly

Franchement, dire que srcset="" est la meilleure alternative sur la gestion du HiDPI, j'ai vraiment du mal à le croire et Geoffroy Crofte d'Alsacréations trouve lui aussi la syntaxe contre-intuitive. La question titille de nombreuses personnes depuis deux ans.

À relire, j'ai peur que nous ne retombons dans les mêmes travers que les déclarations de favicons. Celle qui entraîne une inflation de la <head></> qui fait peur :

code source imposant à mettre pour toutes les déclarations
15 formats, autant de déclarations différentes pour exactement la même ressource !
Source : Tweet de @Judofyr

À mon sens, cet attribut html risque n'engendrer plus de problèmes qu'en résoudre. Déjà, il parle plus de cas de présentation que de sémantique du document lui-même, donc kesk'il me fout là en n'html, purin ?. Si on ajoute la balise <picture>/</>, on arrive à un niveau inquiétant de verbosité, alors que cela pourrait être évitée.

Et quand on connaît les conventions de code html qu'utilise Google, tellement concis qu'il ne reste plus grand chose, on est surpris que Chrome accepte autant de redites. Décidez-vous, ou prenez le temps de réfléchir...

Réfléchir aux usages actuels d'images

Et attention, je ne parle pas sociologie ou quoi que ce soit, je parle de l'organisation des assets dans un site web, tel qu'il est monté en l'état de l'art. Dans les images, nous avons celles qui nous décrivent quelque chose, et celles qui ne sont qu'un insignifiant décor…

Variation autour de « La Trahison des images » de Magritte.
Source : l'excellent billet sur le sujet par le blog Du bleu dans mes nuages

Nous avons quatre trois principales sources d'images :

  1. celles appelées en CSS, purement décoratives et qui ne sont pas destinées à être modifiées par les utilisateurs du site ;
  2. celles en <img /> mais qui sont appelées via des templates ou des manipulations d'éléments DOM du document ;
  3. les emoji, noyés dans le texte par quelque hypster qui se croit à 原宿 ;
  4. celles en <img /> résultantes d'un envoi par l'utilisateur via un CMS (ou parfois front-office pour les réseaux sociaux ou les sites de petites annonces) et qui sont conformées par le site (anti-intrusion, retaillage, éventuellement filigranage,…).

Dans le premier cas qui regorge de background-image, on ne se pose pas de questions puisque les media-queries CSS peuvent détecter la densité des pixels logiques via le paramètre resolution, ou alors utiliser directement les .svg de l'artiste designer.

C'est surtout dans ce dernier cas que la balise srcset="" devient particulièrement compliqué et contre-productif : Comment gérer l'existant ? Comment mettre à jour si de nouvelles finesses de résolution doivent être gérées pour ce site ?
Nous travaillons nettement plus souvent avec des CMS, comme le moteur de ce blog par exemple, qui génèrent à la volée plein de sous-formats d'images selon des contraintes d'aspects programmables, un classique des CMS. On ne peut mettre en place rapidement cet attribut sans un important travail de re-conformation du contenu existant. J'imagine déjà la complexité pour mon blog qui comporte plus de 2000 billets en 10 ans, et dont toutes les sources en très hautes résolutions ne sont pas forcément disponibles. Alors imaginez la situation pour un site d'e-commerce qui possède plus de 10 000 références ou pour un quotidien régional qui produit des dizaines d'articles par jour.
Et encore, La Dépêche a arrêté la rubrique des blagues mails suite à la concurrence frontale.

Sincèrement, ne prenez que cet article et imaginez que chaque image dont j'ai fait mention dans sa source doit avoir des définitions multiples, alors que la création de ses sous-formats a été automatisée/normalisée par le CMS que j'utilise.

NON P☵⚧⚼☭N NON srcset="" n'est pas du tout « …a good thing » de cette manière-là.

Ce qu'aurait dû être le cahier des charges

Un grand classique : Le cahier des charges tel qu'il a été compris

Pour moi, les règles de bases devraient être :

  • Pas de redites, l'URL de la ressource ne devrait pas être démultipliée dans le code source, surtout quand ces multiples adresses sont générées automatiquement. Moins on a de verbosité, plus on a de chance de convertir des utilisateurs
  • Le nombre d'éléments construits en DOM doit rester succinct
  • En restant simple, le code doit aussi inciter aux bonnes pratiques
  • Les dimensions doivent être implicites, le navigateur les connaît forcément en décodant le fichier image, et les css peuvent les changer pour des contraintes de présentation. Forcer les dimensions peut générer des aberrations insolubles
  • Tout ce qui concerne la gestion de résolution en fonction de la finesse de l'écran devrait être gérée naturellement. Comme cela fait partie non pas de la sémantique du document, mais de la présentation, cela devrait être délégué à la CSS
  • En termes de maintenabilité, l'ajout d'un nouveau sous-format d'images en fonction de la finesse de l'écran ne devrait pas demander plus de 5 lignes en tout et pour tout, même si on parle de milliers d'images.
  • La solution doit être indépendante du protocole, ne pas demander de modifications côté serveur, ni même de reconfiguration. Il faut que cela marche aussi bien sur un serveur dynamique, qu'un serveur statique ou en ressource stockée localement.
  • Elle doit être facilement réalisable par un webmestre lambda
  • Et évidemment, elle doit être facile à coder pour ceux qui écrivent les navigateurs, parce que sinon, c'est peine perdue

Si on reprend les astuces présentées dans le précédent chapitre, on verrait que srcset="" ne score pas forcément mieux...

Et si plutôt on passait par les CSS ?

un chat qui joue et gagne au bonneteau
Source : Vancoosh, starring Frida

Si je m'étais bougé dans les temps, que j'aurais choppé les discussions du W3C et mis mon ptit grain de sel de Guérande, j'aurais fait la proposition suivante : on devrait proposer de pouvoir modifier à la volée l'URL de source par une regex, puisque la grande majorité des sous-formats d'images sont automatisés jusqu'à leur stratégie de nommage.

Cela demande beaucoup de nouveautés :

Proposition : srcset en css

Toutes nos chaussettes au même endroit.
Source : AngryJulieMonday

En fait, le mieux serait d'indiquer une règle de ressource en fonction de la finesse de l'écran. Et quitte à avoir srcset="" en html, autant le remonter en css, non ?

srcset : "img-4x.jpg" 4x;

Où l'on pourrait chaîner plusieurs scénarii :

srcset : "img-2x.jpg" 2x , "img-4x.jpg" 4x;

Ce qui fait que cette propriété gérerait à la fois la substitution de source et l'échelle à y appliquer. Nous aurions une déclaration générale et beaucoup plus facilement modifiable en cas de modification des règles css, par exemple en cas de changement d'un thème responsive design. D'ailleurs la notation en fonction de la largeur disponible deviendrait caduque.

Bien évidemment, en cas de ressource absente, la propriété serait ignorée.
Nous aurions aussi un gain pour d'autres balises, telles que <video></> ou <iframe></>

Proposition : Intégrer les regex en css

1406-Img-RegEx.gif
Source : Halibustuff.com

La gestion d'un nouveau type d'opération en css, à savoir une regex et son pattern de remplacement. Tous les navigateurs possèdent forcément un moteur javascript, et donc une bibliothèque regex standard. Je pense néanmoins que c'est là qu'il y aura le plus de travail, de débats et de code à écrire car il demandera d'adapter les parsers css à une syntaxe qui leur est inédite.

Par exemple : regex(attr(src) , "^/images(.*)/([^/]+)$" , "/images\1/.\2,x2").
Le premier paramètre indique la chaîne de caractère à traiter, ici le contenu de l'attribut src="" dans le code html, le deuxième indique la formule de travail, et la troisième la formule de remplacement. Dans cet exemple, /images/examples/test.jpg serait remplacé en /images/examples/.test.jpg,x2

Du coup, il suffit de ne décrire qu'en une seule fois les stratégies de nommage des sous-formats d'images, selon que l'on a choisi par sous-répertoires (“/x1/img.jpg”), par suffixe interne (“img_x1.jpg”) ou externe (“img.jpg,x1”).

L'allègement de code du source html serait phénoménal sur bien des sites par rapport à la stratégie srcset="" dans chaque balise.

Proposition : async="no"

un feu rouge
CC0 Auteur : Hans. Source : Pixabay.

Si nous ne voulons pas que le navigateur charge les ressources <img src="" /> par défaut, puis charge celles à la bonne résolution après coup, il faut avoir la possibilité d'indiquer au navigateur qu'un asset (css ou javascript) ne doit pas être traité de façon asynchrone. Et donc proposer un async="no".

Ouais, je sais.

D'ici, je vous entends hurler que cette proposition est totalement contre-productive, vous voulez me jeter à la figure des fruits pas frais, et vous me menacez d'une visite de l'Inquisition Espagnole.
Vous avez presque raison : Cette propriété éviterait que le navigateur appelle des sources d'images qui sont destinées à être invalidées dans une feuille de style. Évidemment, cela va complètement à rebours de tout ce qui est tenté en termes de performances, et il y a des risques d'abus, mais les intégrateurs apprendront à faire attention à leurs dépends. Et puis, si je ne fais pas une proposition totalement ridicule, vous risqueriez de me prendre au sérieux.

Actuellement, la solution adoptée est l'inclusion de js/css dans le html source. Et je ne sais pas pour vous, mais pour moi aussi, ça pique un peu les yeux.

In fine

Jumping water frog par agnatha3141

Je sais, c'est extrêmement prétentieux de faire autant de propositions, et une partie de celles-ci sont à coup sûr complètement erronées. Ensuite, il faudra les proposer indépendemment, les faire éventuellement accepter par les groupes du W3C et du WHAT-WG, les voir peut-être arriver dans les navigateurs et en éviter les abus.

Bref, il y avait du boulot, mais elles aideraiement à rendre la syntaxe html nettement moins verbeuse, l'entretien nettement facilité des ressources et la possibilité d'étendre très facilement pour les très très fortes densités encore à venir. J'ose à peine imaginer des malades capable de nous vendre des écrans à 3200 dpi…

Imaginez :

article img {
    srcset : regex(attr(src) , "^/images/articles/(.*)/([^/]+)$" , "/images/articles/\1/.\2,x2") x2,
          regex(attr(src) , "^/images/articles/(.*)/([^/]+)$" , "/images/articles/\1/.\2,x4") x4;
}
.decor img {
    srcset : regex(attr(src) , "^/images/layout/(.*)/([^/]+)$" , "/images/layout/\1/.\2,x2") x2,
          regex(attr(src) , "^/images/layout/(.*)/([^/]+)$" , "/images/layout/\1/.\2,x4") x4;
}

On ferait difficilement plus simple…

And thank you for all the fish

Ce dossier sur la balise <img /> fut un travail long, et qui n'a pas la prétention d'être exhaustif ou parfait. Donc je remercie tous ceux qui m'auront relus, conseillé, corrigé dans les commentaires. Écrire sur un sujet exige de se remettre en question, de se documenter et à reprendre le désir d'apprendre et de rédiger sans se limiter à caler des jeux de mots foireux.

Je remercie milles fois la syntaxe de l'attribut srcset="" qui m'a donné l'inspiration de m'exprimer à ce sujet.

Sans rancune ;)