Ouvrir la navigation secondaire

Ce billet a plus de deux ans. S'il contient des informations techniques elles sont peut être obsolètes.

Précédent Rencontres Django 2012, It's Over 9000!
Suivant Django 1.4, MySQL et les dates en UTC

Développement web haute résolution

Nous fûmes prévenus en 2006 : la haute résolution arrive et on nous rappelait qu'un pixel CSS n'équivaut pas automatiquement à un pixel d'écran. L'exemple du zoom est devenu classique pour illustrer ce propos.

La résolution augmente dans l'industrie et la technologie Super High Aperture permet de caser de plus en plus de pixels dans des quantités d'espace toujours réduites. C'est à priori cette technique qu'utilise Apple pour ses écrans Retina. Tout porte à croire que c'est Samsung qui aurait décroché le contrat de fabrication des écrans de l'iPad. Plutôt comique quand, dans le même temps, les deux sociétés se font la guerre des brevets.

Quelque chose m'échappe encore dans la communication des constructeurs concernant la résolution des écrans. Pourquoi communiquent-ils sur la densité de pixels (nombre de pixels par pouce) et pas uniquement sur la taille des écrans (nombre de pixels en largeur et en hauteur) ? Ma compréhension du problème est la suivante : la densité de pixels (PPI) définit les dimensions d'impression uniquement et n'a pas d'impact sur la taille d'une image. La qualité d'une image numérique dépend uniquement du nombre de pixels dont elle est composée. Voir Pixel Density & the Web: Out with Myth, In with Truth et PPI & DPI is Irrelevant par exemple. Bref, pour nous développeurs web le nombre de pixels par pouce est hors de propos.

Alors comment proposer du contenu haute résolution à vos utilisateurs ? Les conférences données pendant la WWDC 2012 sont en lignes et notamment Delivering Web Content on High Resolution Displays mais il faut un Apple ID pour la visualiser. Diantre quelle mauvaise habitude ! Vous en êtes dépourvu ? Consolez-vous avec cet organigramme dernier cri, ou bien alors, continuez votre passionnante lecture car je m'en vais vous en faire un résumé agrémenté de liens formidables.

Merveille de technologie, pour 1 pixel sur un écran normal il y en a désormais 4 sur un écran Retina. Cela ne va pas sans poser quelques problèmes au contenu de vos sites existants. Ce contenu peut être de différents natures :

  • éléments natifs dessinés par Webkit (textes, boutons de formulaire, etc.)
  • images vectorielles (SVG)
  • images matricielles (bitmap) et canvas

Pas de problème pour les éléments natifs dessinés par Webkit, le software scale factor se charge de tout :)

Pas de problème non plus pour les images vectorielles. SVG est à ce titre un premier pas vers la résolution indépendante. Par contre ne vous attendez pas à du pixel perfect à coup sûr. Et puis tout le monde aime la syntaxe XML, non ?

Pour les images bitmap, et bien c'est là que ça se corse...

Sur les écrans classiques nous avons été habitués à la correspondance entre les pixels CSS, les pixels de l'image et les pixels de l'écran, chaque pixel de l'image est rendu sur 1 pixel de l'écran. Le temps de la correspondance 1 pour 1 est révolu avec les écrans haute définition : taille CSS != taille de l'image != taille de l'écran. Si vous suivez les techniques de Responsive Web Design (taille CSS de 100%) ou que vous avez dû jouer avec -ms-interpolation-mode pour les images de fond plein écran vous avez déjà compris la différence entre taille CSS et taille de l'image.

Si vous avez une image de dimension 100 x 100 pixels que vous affichez avec une largeur et une hauteur CSS de 100px sur un écran Retina, elle va donner une impression de mauvaise qualité à cause des nouveaux pixels créés par l'interpolation numérique car elle va en fait occuper 40.000 pixels (200 x 200) sur l'écran de l'appareil alors qu'elle n'en est composée que de 10.000 (100 x 100). Le nombre de pixels de l'écran a quadruplé, pas le nombre de pixels de l'image, l'interpolation comble les pixels manquants.

En attendant un algorithme imparable d'interpolation, Apple conseille dans ses astuces, et vous l'avez déjà compris, d'augmenter la taille des images bitmap en appliquant un facteur de 2 à leurs dimensions : une image de 100 x 100 pixels devient une image de 200 x 200 pixels (soit quadrupler le nombre de pixels). Vous allez devoir créer et maintenir deux versions de vos images bitmap et du code associé pour satisfaire les deux types d'écrans. Vous imaginez le surcoût en termes de mise en place et de maintenance. Notez que la situation est pire si vous travaillez depuis un écran Retina.

Mais trêve de lamentations, énumérons les techniques disponibles pour Retina-iser et tester les images bitmap de nos sites.

Utiliser uniquement des images bitmap haute résolution est une solution mais au prix du sacrifice de la performance. A vous de peser le pour et le contre à la lumière de l'explosion du web mobile.

Si vous décidez de gérer 2 formats d'images à la mode @2x vous avez des outis CSS et JavaScript pour vous y aider.

Avec CSS vous pouvez détecter le nombre de pixels de l'écran par pixel CSS avec la media query Device Pixel Ratio imposée par Apple et fortement vendeur préfixée qui ne semble standardisée nulle part pour le moment. Voir à ce sujet Device Pixel Ratio Timeline très instructif sur le process de standardisation. Je pense qu'Apple a eu raison de ne pas utiliser la media query resolution qui prend pour le moment en unité des dpi ou des dpcm qui me semblent plus appropriés au monde de l'impression. Cela dit Firefox 16 (sic) va intégrer le dppx en nouvelle unité pour resolution et il y a des chances pour qu'à terme ça mette tout le monde d'accord.

Conséquence si vous voulez faire les choses à peu près correctement :

@media
    only screen and (-webkit-min-device-pixel-ratio: 2),
    only screen and (min--moz-device-pixel-ratio: 2),
    only screen and (-o-min-device-pixel-ratio: 2/1),
    only screen and (min-device-pixel-ratio: 2) {
        ...
    }

Holy shit s'écria la baronne en voyant tous ces préfixes vendeurs !

Du côté du JavaScript vous pouvez utiliser la propriété window.devicePixelRatio qui est plutôt bien implémentée sur mobile. C'est utilisé pour servir des images haute résolution sur le site de l'iPad Retina et aussi par retina.js par exemple. Vous avez aussi la méthode window.matchMedia() qui est moins disponible mais avec laquelle vous pouvez agir lorsqu'un évènement se produit :

window.matchMedia('(-webkit-device-pixel-ratio:1)').addListener(myFunc);

Enfin vous avez ce qu'Apple nomme Image Set, une solution proposée pendant The Great Responsive Images Brouhaha :) C'est la solution qui présente la plus grande facilité d'implémentation, malheureusement elle est encore loin d'être cross-browser.

Au moment de la sortie de l'iPad Retina, il a été observée une sorte de come-back du JPEG progressif. Mon sentiment sur la question est qu'il s'agit probablement d'exports malheureux de graphistes pressés.
Mise à jour : L'utilisation du JPEG progressif est une astuce pour pallier un bug de downscale/upscale d'iOS des images trop lourdes, le bug semble référencé sur Radar (rdar://problem/11097671) mais on ne peut pas consulter et il n'est pas référencé sur Open Radar.

Il nous reste à parler de Canvas qui n'est pas du vectoriel comme on le lit souvent mais un moyen de générer dynamiquement en JavaScript des images ou des graphes en bitmap. Sa précision est dépendante de la résolution. Peu avant la sortie de l'iPad Retina le WHATWG demandait des APIs haute-résolution pour Canvas. Il est question du backing store et je vous avoue que j'ai un peu de mal à comprendre ce que c'est exactement. Toujours est-il que ce backing store est doublé automatiquement dans Webkit sur les écrans Retina gérés par OSX. Par contre Webkit avec un écran Retina géré par iOS ne double pas automatiquement la taille pour des raisons de consommation mémoire et de performance de rendu ! Le choix d'augmenter la résolution est dans ce cas laissé au développeur et il va falloir vérifier le devicePixelRatio (ratio nombre de pixels de l'écran par pixel CSS) et le context.webkitBackingStorePixelRatio (ratio nombre de pixels du backing store par pixel CSS) le context étant celui du Canvas.

if (window.devicePixelRatio > 1 && context.webkitBackingStorePixelRatio < 2) {
    // retina non auto-doubled
}

La situation n'est donc pas optimale comme dans toutes les périodes de transition. La mise en place et la maintenance d'un site haute définition s'en trouvent complexifiées. Un conseil sensé est de se reposer au maximum sur le rendu natif des navigateurs (dégradés, ombre portées, web fonts etc.) et de limiter les bitmaps dans la mesure du possible. C'est en somme un véritable art !

#1

Digitalcoder

23.07.12 01:38

Merci beaucoup pour ces informations utiles.

Je travaille actuellement sur des versions de site spécial Ipad et iphone, avec une contrainte Retina avec des images HD;

Je dois jongler avec des maquettes en 2048x1345, transformer les valeurs css en 1/1 ainsi que les images pour écran non retina et exporter les images en HD @2x qui seront chargées via un javascript qui détectera window.devicePixelRatio et qui chargera les images en HD identifiées si elles existent en HD dans le répertoire image (via script PHP/JSON).

Côté css il faudra je pense passer par les mediaqueries pour charger les images de fond en @2x avec background-size:100%

@media
only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and (min--moz-device-pixel-ratio: 2),
only screen and (-o-min-device-pixel-ratio: 2/1),
only screen and (min-device-pixel-ratio: 2){}

Je fais le constat que la charge de travail est beaucoup plus lourde.

Mais bon cela ne fait qu'apporter l'eau au moulin du Dev-Front ^^