Un nouvel élément d’intérêt pour les sites adaptatifs a été
formalisé dans la version 5.1 de la norme HTML5. Il s’agit de l’élément
picture
et il permet de spécifier une série d’images en
fonction de la résolution de l’écran mais aussi de la densité des pixels
à l’écran.
Les sites adaptatifs (responsive) sont un incontournable aujourd’hui pour livrer un contenu confortable pour l’usager que ce soit sur un écran de bureau, une tablette ou un appareil mobile. Les éléments clés pour la création de sites adaptatifs sont :
Le tout parfois épicé avec un peu de JavaScript.
Pour un meilleur affichage, la résolution de l’image doit être adaptée à l’écran. Une résolution trop grande consommera de la bande passante inutilement et une résolution trop faible donnera des problèmes de netteté au rendu. Avec les écrans à haute et ultra haute densité, la résolution doit être plus forte pour assurer une netteté de l’image1. Un écran à simple densité d’un petit appareil se contentera d’une faible résolution. Envoyer une résolution trop forte à un tel appareil augmentera inutilement le temps de chargement de la ressource. D’un autre point de vue, un écran à ultra haute densité pourrait vouloir une image à plus basse résolution parce que la bande passante n’est pas au rendez-vous. Comment faire pour que l’image téléchargée soit à une résolution optimale pour l’appareil?
Dans le passé, pour pallier au problème, il fallait dynamiquement faire des changements au niveau du Document Object Model (DOM) ou sinon après avoir envoyé un cookie avec les caractéristiques de l’environnement client, laisser le serveur envoyer l’image à la bonne résolution. Le fragment de code ci-dessous montre la méthode avec le DOM. Tout d’abord nous avons le HTML :
<img src="images/cathedrale-paris.jpg" class="hr-js" />
Puis, le JavaScript avec jQuery :
$(document).ready(function(){ if (window.devicePixelRatio > 1) { var lowresImages = $('img.hr-js'); lowresImages.each(function(i) { var lowres = $(this).attr('src'); var highres = lowres.replace(".", "@2x."); $(this).attr('src', highres); }); } });
Sur mon Macbook Pro avec un écran haute densité,
window.devicePixelRatio
retourne la valeur 2, le URL serait
donc changé dynamiquement par le code JavaScript pour faire télécharger
l’image images/cathedrale-paris@2x.jpg
qui serait à haute
résolution.
Il existe d’autres astuces qui vont jouer avec les CSS et les
requêtes média pour cacher le contenu de l’image (celui de l’élément
img
) et remplacer par une image de fond à plus haute
résolution. Pour ce HTML :
<div class="retina-fond"> <img src="images/cathedrale-paris.jpg" width="640" height="480"/> </div>
Nous pourrions mettre les règles CSS suivantes :
@media only screen and (min-device-pixel-ratio: 2) { .retina-fond { background:url(images/cathedrale-paris@2x.jpg) no-repeat center center; background-size:100% 100%; } .retina-fond img { visibility:hidden } }
Le problème avec toutes ces techniques est qu’elles sont des « astuces », et en bout de ligne on se retrouve souvent à charger 2 images : l’image à basse résolution et l’image adéquate pour les caractéristiques de l’écran de l’appareil.
Le standard HTML5.1 a un nouvel élément qui permet au navigateur de
demander la bonne image dans le bon contexte. Il s’agit de l’élément
picture
. Cet élément permet de mettre une cascade
d’éléments source
. L’élément source
a un
attribut media
qui correspond à une requête média et un
attribut srcset
qui spécifie une liste de URL pour chaque
niveau de densité de l’écran. L’attribut srcset
est une liste
séparée par des virgules de chemins de fichiers (URL) avec un code pour la
densité de pixels. Le navigateur choisira la première option dans la liste
qui est conforme avec la contrainte média.
<picture> <source media="(max-width: 767px)" srcset="images/bonhomme-br@1x.png 1x, images/bonhomme-br@2x.png 2x, images/bonhomme-br@3x.png 3x"> <source media="(min-width: 768px) and (max-width: 991px)" srcset="images/bonhomme-mr@1x.png 1x, images/bonhomme-mr@2x.png 2x, images/bonhomme-mr@3x.png 3x"> <source media="(min-width: 992px)" srcset="images/bonhomme-hr@1x.png 1x, images/bonhomme-hr@2x.png 2x, images/bonhomme-hr@3x.png 3x"> <img src="images/bonhomme.png"> </picture>
Le code ci-dessus offre trois séries d’images. La première pour des
petits écrans avec une largeur maximale de 767px. La deuxième est pour une
largeur d’écran supérieure à 768px mais inférieure à 991px. La dernière
est pour une largeur d’écran supérieure à 992px Pour chaque
srcset
nous avons trois possibilités de densité (simple avec
1x, haute avec 2x et ultra haute avec 3x) avec le URL qui correspond à
chacune. Finalement, un dernier élément, img
, permet une
reprise si l’élément picture
n’est pas supporté. Au total
dans notre exemple nous aurions besoin de notre image à 10
résolutions.
Quelle est la conséquence de cette nouvelle construction? Le navigateur fera de façon native une requête pour l’image appropriée sans recours au JavaScript, ni travail de reconnaissance côté serveur. Aucune image surdimensionnée ne sera envoyée : le téléchargement sera donc optimal.
Dans la même veine de changements, le HTML5.1 a aussi introduit ce
même attribut srcset
pour l’élément img
. Ainsi
nous pouvons mettre :
<img src="images/bonhomme-br@1x.jpg" srcset="images/bonhomme-br@1x.jpg 1x, images/bonhomme-br@2x.jpg 2x, images/bonhomme-br@3x.jpg 3x">
Les conditions peuvent inclure des éléments tels que la densité de pixels ou encore la largeur et la hauteur. Cependant, seule la densité de pixels bénéficie, à ce jour, d’une vaste prise en charge.
L’élément img
a aussi la possibilité d’accueillir un
attribut sizes
qui permet de spécifier la taille relative de
l’image dans l’écran (p.ex. une image qui couvrirait la moitié de la
largeur de l’écran) et en fonction de ça, le choix du fichier approprié
pour l’image sera déterminé par les options dans l’attribut
srcset
. Pour des détails sur l’usage l’attribut
sizes
, consultez la section Images
à dimensionnement relatif de l’article sur les images sur le blogue
de Google.
Comme l’élément picture
est relativement nouveau, il
est toujours de recommandé d’aller voir son support dans les navigateurs
avant de l’utiliser. Un bel outil pour ceci est le site caniuse.com. À la Figure 2, nous voyons une capture
du verdict de caniuse.com pour l’élément picture
à la date de
l’écriture de cet article. Comme nous pouvons le voir, le plus embêtant
est que cet élément n’est pas supporté dans IE 11 (mais il est disponible
dans Edge depuis la version 13).
Lorsque le support est absent sur certaines plates-formes nous
pouvons essayer de trouver un correctif pour l’utiliser dès maintenant. En
anglais, les correctifs sont appelés les polyfills. À cet effet, il existe un correctif pour
l’élément picture. Mais nous pourrions décider de ne pas utiliser
le correctif et plutôt de laisser l’élément img
dans la
construction de picture
prendre le relais. Si nous testons
l’exemple de code avec l’élément picture
dans IE 11 sans
mettre de correctif, nous voyons l’image
images/bonhomme.png
.
Cet article a présenté un petit truc qui permet d’améliorer fortement le téléchargement des pages d’un site Web adaptatif à une époque où la vitesse de téléchargement des pages est récompensée par Google, mais aussi très appréciée des internautes.
C’est certain que ceci vous demandera de faire générer une brochette d’images à toutes les résolutions nécessaires, mais c’est une opération assez commune à configurer dans tout CMS qui se respecte. Le prix à payer sera l’espace disque. Dans les cas où l’image est une forme assez simple à vectoriser, il est certain qu’il serait avantageux d’utiliser le format SVG car dans ce cas nous n’aurions besoin que d’une image unique.
Noter que si vous faites un travail plus manuel, Photoshop CC2017 a une nouvelle fonction pour produire et sauvegarder d’un coup une série d’images pour les écrans haute densité. Une capture d’écran de l’outil d’export est présentée à la Figure 4. C’est d’ailleurs comme ça que les images de l’exemple dans cet article ont été créées.
Pour ceux qui veulent plus de détails sur la technique, le sujet est brièvement couvert dans le cours d’HTML5, mais le cours Responsive Web Design est celui qui est le plus indiqué car le contexte de l’usage de cet élément est couvert en profondeur.