Les Images Responsives

Comment fonctionne le Web Responsive ? Comment gérer les images sur des périphériques de hautes définitions type Retina Display pour qu’on puisse parler d’images responsives ? Comment appréhender l’affichage d’images sur des périphériques de type smartphone ? Comment gérer la bande-passante ? Tout est lié et pas si simple que cela. Je vous propose une plongée dans ce monde merveilleux pour faire le point des possibilités !

Au départ il y a les Media Queries…

La multiplication des périphériques (écrans, tablette, smartphones, télés…) nécessite une adaptation des interfaces web utilisateur, potentiellement en temps réel ; ainsi il suffit de faire pivoter le périphérique pour que largeur et hauteur soient inversées, nécessitant peut-être d’agencer différemment les informations à l’écran. Deux approches sont alors possibles : soit on fait un aller-retour vers le serveur pour qu’il renvoie la vue adaptée, soit on adapte l’interface côté client en profitant d’informations telles que les dimensions de l’espace d’affichage. On imagine vite que cette seconde approche est plus attrayante pour les graphistes et les développeurs si on dispose des bons outils. Depuis 2008 les travaux du W3C ont débouché concrètement sur les spécifications des Media Queries (définitivement adoptées en juin 2012) permettant de rendre dynamique l’application des CSS selon des paramètres variés tels que la hauteur, la largeur ou les couleurs disponibles sur un périphérique: le Web Responsive pouvait prendre son envol.

En quelques lignes d’exemples, tout semble compréhensif et facile à mettre en oeuvre :

L’attribut media définit le contexte d’application de la feuille de style, sachant que les règles habituelles de cascades CSS continuent de s’appliquer. Ici example.css s’applique aux périphériques de type écrans qui ont au moins 4 couleurs et d’une définition maximale en largeur de 799 pixels. A noter l’existence d’opérateurs (AND, NOT et ONLY), et aussi que le type de media peut prendre des valeurs diverses telles que screen, tv, projection, handled, print, braille ou all pour représenter tout type. En passant, débuter l’attribut media par ONLY permet d’écarter IE6 qui ne le reconnaît pas.
L’exemple précédent implique la définition maximale du device, mais pas la largeur en cours d’utilisation : une fenêtre de navigateur qui change de taille, un smartphone qu’on passe en mode paysage pourraient voir leur affichage évoluer par l’application dynamique d’autres feuilles de style :

De même, ces directives peuvent être directement définies dans l’élément style de la page web :

<style> @media screen and (min-width: 400px) and (max-width: 700px) { #menu { display:none; } body { font-size :0.8em ; } } </style>

Pour être complet, les propriétés normalisées souvent utilisées sont : min-width (en unités css), max-width, min-height, max-height, min-device-width, max-device-width, min-device-height , max-device-height, device-aspect-ratio (16/9, 16/10…), color, min-resolution (en dpi), max-resolution, orientation (portrait ou landscape). Comme à l’accoutumée webkit et mozilla y vont de leurs compléments, par exemple « –moz-touch-enabled » qui renseigne si le device supporte ou pas les événements de type « touch ».

Vous l’aurez compris, en combinant ces propriétés on est capable de proposer des interfaces utilisateurs différentes en fonction du contexte, par exemple selon qu’on consulte la page sur un grand écran ou sur un mobile. Pour illustrer le propos, voici le rendu de l’application Ippon Tatami qui s’adapte selon la largeur d’affichage disponible :

Je vous encourage aussi à découvrir cet excellent poc http://www.thismanslife.co.uk/projects/lab/responsiveillustration/
Rapidement, le Web Responsive a trouvé un écho auprès de ceux qui conçoivent et doivent adapter des applications web aussi bien pour un écran de 24 pouces que pour un mobile. Naturellement, les frameworks HTML/CSS sont alors devenus Responsives (Twitter bootstrap, Less, Skeleton, Initializr, Columnal…), des Patterns Responsives ont aussi vu le jour (http://bradfrost.github.com/this-is-responsive/patterns.html, …), bref l’armada habituelle qui accompagne des nouvelles technos ou des tendances.
Donc en principe, tout va pour le mieux dans le meilleur des mondes Responsives. Sauf pour les images.

Les images et les graphiques chamboulent tout

Appliquer le Web Responsive aux images (on parle alors d’images Responsives) n’est pas aussi trivial que d’appliquer des Media Queries ; enfin pas encore…

Le premier élément de réflexion provient de l’information introduite par l’image : selon les dimensions du périphérique, on ne souhaitera pas obligatoirement afficher la même image. Par exemple sur un mobile on affichera un plan resserré sur l’élément principal, alors que sur une tablette on affichera un plan plus large.


Dans ce cas, un type de media queries peut être utilisé (par exemple sur un élément DIV info) :

@media all and (max-width: 1024px) { 
#info { width:400px; height:320px; background: url(papillon_recadre_400.jpg); background-size:400px 320px; } } 
@media all and (min-width: 1024px) { 
#info { width:600px; height:480px; background:url(papillon_600.jpg); background-size:600px 480px; } }

Malheureusement cette solution n’est pas sémantiquement satisfaisante car l’affichage d’une image devrait être assuré par l’élément IMG, pas par l’intermédiaire d’un background de CSS. Nous y reviendrons.

Le second élément de réflexion concerne l’affichage des images sur un écran de haute densité tel que les Retina Display (iPhone 4 et 5, iPad3) ou les Samsung récents (Galaxy Note, S3). Ainsi, si un écran Retina Display affiche une résolution physique de 2048×1536, sa résolution virtuelle est de 1024×768, soit 4 pixels physiques pour 1 pixel virtuel (2048=2×1024 et 1536=2×768, soit un ratio de 2). Idem pour une tablette Asus Transformer Infinity dont la résolution physique est de 1900×1200 mais dont la résolution virtuelle est de 1280×800, soit 2.25 pixels physiques pour 1 pixel logique (soit un ratio de 1.5). Autrement dit, les largeurs et hauteurs utilisées dans les CSS (de type résolution virtuelle) vont différer de la réalité physique. Pour les fontes, pas de souci, l’OS adapte l’affichage sans grande perte de qualité–vectoriel oblige, mais ce n’est pas le cas pour les images bitmap. Donc pour un affichage optimal, chaque image dans une page web devrait être fournie en autant de résolutions que de densités différentes sur les devices cibles. Dans l’exemple suivant d’un device haute densité de ratio 1.5 l’image de gauche qui est envoyée au navigateur, est en résolution x1, alors que l’image de gauche est envoyée en résolution x2.25 (ratio 1.5 adapté au device); les détails sont bien plus présents dans l’image de droite. Si on affichait ces mêmes images sur un périphérique de densité 1 on ne verrait quasiment pas de différences…

D’un point de vue Media Queries, il faudra alors utiliser une propriété particulière pour différencier les densités des devices et charger les images respectives: c’est l’objet de pixel-ratio.

/* cas general, affichage "standard", image-mobile.png est de taille 64x12 */ .image-class { 
    width:64px; height:12px; background: url(/images/image-mobile.png); 
    background-repeat:no-repeat; } 
/* cas des devices HD, les CSS précédente s’appliquent en cascade (width, height), image-mobile-2x.png est de taille 128x24 mais redimensionnée à une dimension logique de 64x12 */ 
@media screen and (-webkit-min-device-pixel-ratio: 2), screen and (min--moz-device-pixel-ratio: 2) { 
    .image-class { background: url(image-mobile@2x.png); background-size:64px 12px; } }

Note : cette notion de densité est aussi à prendre en considération avec le CANVAS HTML5 lors des sorties graphiques puisque les dimensions du CANVAS relèvent des unités de CSS :

canvas { border: 1px solid black; width: 150px; height: 150px; }

if(window.devicePixelRatio == 2) { canvas.setAttribute('width', 300); canvas.setAttribute('height', 300); ctx.scale(2, 2); //les calculs géométriques sont fondés sur un référentiel //de coordonnées 150x150, mais subissent ensuite une mise //à l'échelle x2 avant leur sortie }

Et la balise IMG dans cette histoire ?

Si nous disposons d’une solution pour mettre en œuvre des images Responsives en utilisant le background d’un élément HTML, celle-ci n’est pas sémantiquement satisfaisante car l’affichage d’une image doit être assuré par l’élément IMG et non un élément DIV. Et c’est là que le bât blesse : un élément IMG déclenche obligatoirement le chargement par le navigateur de l’image référencée par son attribut src. Impossible de faire autrement, les CSS Media Queries n’y peuvent rien… Comment donc demander au serveur de fournir l’image attendue ? Diverses solutions palliatives ont été envisagées, parmi lesquelles (vite vu…):

A base d’URL + cookie + fichier .htaccess

<img src="small.jpg?full=large.jpg" />

Un script JS crée un cookie qui renseigne le type d’image à charger (ici, large ou small) : ce cookie sera géré dans le cadre d’une réécriture d’url sur le server dans un fichier .htaccess.

A base de l’élément NOSCRIPT

 <noscript data-large='Koala.jpg' data-small='Koala-small.jpg' data-alt='Koala'> <img src='Koala.jpg' alt='Koala' /> </noscript>

Simple astuce qui s’appuie sur le fait que l’élément noscript ne sera pas rendu.

à base de détection du device à partir du server

WFURL est une base de données de signatures et de caractéristiques du plus grand nombre de devices (http://wurfl.sourceforge.net/) sur laquelle on peut s’appuyer pour renvoyer l’image la plus adaptée (https://github.com/carsonmcdonald/ServerSideResponsiveImageExample).

Utiliser un module Apache si possible, par exemple mod_pagespeed de Google

Mais foncièrement aucune de ces solutions n’est native, et elles génèrent logiquement d’autres impasses technologiques (cache, proxy etc…). La communauté (au sens large) s’est emparée du problème, en association avec le W3C (ce fût houleux au début…) pour réfléchir à une solution pérenne. Celle retenue induit la création d’un nouvel élément du langage html : PICTURE. Celui-ci pourra référencer plusieurs images selon le pixel-ratio et/ou les medias queries (http://www.w3.org/community/respimg/wiki/Picture_Element_Proposal) :

 <picture> <!-- 1x et 2x renvoient à la densité du device --> <source srcset="small-1.jpg 1x, small-2.jpg 2x"> <source media="(min-width: 18em)" srcset="med-1.jpg 1x, med-2.jpg 2x"> <source media="(min-width: 45em)" srcset="large-1.jpg 1x, large-2.jpg 2x"> <img src="small-1.jpg"> </picture>

Ou

<picture alt=""> <!-- Matches by default: --> <source src="mobile.jpg"> <source src="medium.jpg" media="min-width: 600px"> <source src="fullsize.jpg" media="min-width: 900px"> <img src="mobile.jpg"> </picture>

Une première version de ce comportement a été conceptualisée en javascript avec le projet picturefill (https://github.com/scottjehl/picturefill). Néanmoins, comme la création d’un nouvel élément html n’est pas neutre, Safari (en v6) , Chrome (v >21) et Mozilla envisagent à court terme d’utiliser une nouvelle fonction CSS (image-set) pour mettre en œuvre ce principe :

#info { background-image: url(info.png); background-image: -webkit-image-set(url(info_@1.png) 1x, url(info_@2.png) 2x); background-image: -moz-image-set(url(info_@1.png) 1x, url(info_@2.png) 2x); width:200px; height:75px; }

Cette fonction image-set() est d’ailleurs envisagée aussi dans les CSS4 (http://dev.w3.org/csswg/css4-images/#image-set-notation).

Et la bande passante dans tout ça ?

L’autre point intéressant de ce futur élément PICTURE, c’est qu’on envisage aussi d’y inclure un paramètre relatif à la bande passante disponible : cela permettra par exemple, si la bande passante est moyenne, de télécharger des images en simple qualité sur des devices HD; on pourrait avoir par exemple :

 <picture> <source src="medium.jpg" media="min-bandwidth: 25Mbps and min-width: 600px"> <source media="(min-width: 18em)" srcset="med-1.jpg 1x, med-2.jpg 2x"> <img src="small-1.jpg"> </picture>

Notons par ailleurs qu’il existe aujourd’hui le projet javascript Foresight (https://github.com/adamdbradley/foresight.js), utilisé notamment par le Washington Post sur son site mobile, qui évalue la bande passante en notant la durée de chargement d’un fichier test; la librairie intercepte ensuite les demandes de chargements d’images pour requérir l’image en haute qualité ou en simple qualité, la plus adaptée à la bande passante.

Soyons fous, créons un nouveau format d’image !

On le voit, si tentant qu’il soit, le Web Responsive ne dispose pas encore de toutes les armes idéales pour parer à tous les cas de figure dès qu’on met en jeu des images. Gageons que sous l’impulsion de la communauté et du W3C le nouvel élément PICTURE voit rapidement le jour pour rapprocher CSS Media Queries et sémantique. Enfin, il ressort aussi des différentes options retenues qu’actuellement, l’approche pragmatique consiste à mettre en oeuvre à la fois une partie cliente (CSS Media Queries) et une partie serveur (identification complète du device, gestion de la bande passante).

Finalement la solution idéale serait peut-être de créer un nouveau format d’image, comme Android l’a fait pour ses besoins spécifiques en dérivant du png le Nine-patch (filename.9.png). Un format qui regrouperait par exemple plusieurs représentations de tailles différentes, pour des densités cibles différentes, et qui pourrait délivrer un contenu adapté selon la bande passante, à l’image des flux vidéos en VOD.