Ce billet fait partie de la série en <img /> :
- Histoires en <img />
- Manuel en <img />
- Ressources en <img />
- Bricolages en <img />
- Progressivement en <img />
- Finesse en <img />
- 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.
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.
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.
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 :
À 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…
Nous avons quatre trois principales sources d'images :
- celles appelées en CSS, purement décoratives et qui ne sont pas destinées à être modifiées par les utilisateurs du site ;
- celles en
<img />
mais qui sont appelées via des templates ou des manipulations d'éléments DOM du document ; les emoji, noyés dans le texte par quelque hypster qui se croit à 原宿 ;- 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
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 ?
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
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
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"
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
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 ;)
6 réactions
1 De Nico - 17/06/2014, 21:48
Pour ton histoire d'attribut async en CSS, je crois que Steeve Souders m'avait répondu dans un billet où j'avais suggéré un système genre load: defer ; en CSS : et ça serait à l'étude dans un module CSS4. Je n'arrive plus à trouver le lien :-/
2 De Frédéric Kayser - 17/06/2014, 22:50
On peut aussi se demander pourquoi le PDF ou le standard d'imagerie médicale DICOM ont recours au JPEG2000 alors que le Web continue à lui tourner le dos...
3 De Da Scritch - 18/06/2014, 07:45
Nico : mmmhhhh, intéressant. Tiens, j'ai pas parlé des spécificités css de <img>, comme l'absence de :before et :after.
Frédéric : Je crois que j'en ai parlé, mais alors, très très succinctement http://dascritch.net/post/2014/04/2...
4 De Boris - 19/06/2014, 08:37
Au niveau des alternatives à srcset, je pense qu'il peut être intéressant de jeter un oeil à <a href="https://github.com/BBC-News/Imager...." title="Imager.JS sur GitHub">Imager.js</a>. La syntaxe est vraiment agréable et laisse la place à du templating d'URI d'images, plus simple à mon avis que de la RegEx comme tu le proposes.
Autre avantage, il est possible d'y définir des points de rupture Responsive différents de ceux de la CSS, ce qui peut être interressant pour avoir des images d'une qualité quasi-constante, si tant est qu'on puisse les générer bien sûr, sans pour autant avoir 25 déclinaisons de layouting CSS.
5 De enflammee - 19/06/2014, 15:24
Y'a même des photos de chatons >^o^<
6 De sylvainpv - 20/06/2014, 16:00
Je suis d'accord avec les défauts exposés de srcset, mais je ne suis pas d'accord sur ta proposition. Déplacer srcset en CSS impliquerait de bloquer le chargement de l'image (qui a toujours son attribut src, rétrocompatibilité oblige) tant que toutes les CSS n'ont pas été chargées et interprétées, pour ne pas requêter inutilement l'url dans src. S'il faut indiquer plusieurs sources, il faut le faire au même endroit que l'attribut src originel.
Je ne pense pas qu'on puisse faire beaucoup mieux que la proposition actuelle, malgré ses défauts. Personnellement j'utilise une approche différente pour les images responsive : je mets la version de plus basse résolution en src, puis avec une petite fonction JavaScript, je charge l'une après l'autre les versions de plus en plus grande résolution, jusqu'à ce qu'on ait dépassé les dimensions du viewport ou que le chargement de l'image ait pris plus de 1 seconde. Du coup, on a les images très rapidement et elles s'affinent sous nos yeux, donnant un effet sympa. On peut aussi lancer le chargement des résolutions supérieures en détectant le survol de la souris ou la position après scroll. Bien sûr, cette technique est très consommatrice en bande passante, mais c'est la meilleure que j'ai trouvé pour afficher le plus rapidement possible les images.