Publié le 22 août 2012, dernière mise à jour le 14 avril 2025
Avec autant d'appareils sur le marché, il existe une très large gamme de densités de pixels d'écran. Les développeurs d'applications doivent prendre en charge un éventail de densités de pixels, ce qui peut s'avérer très difficile. Sur le Web mobile, les défis sont aggravés par plusieurs facteurs:
- Grande variété d'appareils avec différents facteurs de forme.
- Bande passante réseau et autonomie de la batterie limitées.
En termes d'images, l'objectif des développeurs Web est de diffuser les images de la meilleure qualité possible, de la manière la plus efficace possible. Nous allons ici vous présenter quelques techniques utiles pour le faire maintenant et à l'avenir.
Éviter les images lorsque cela est possible
Avant de supposer que vous devez inclure une image, n'oubliez pas que le Web dispose de nombreuses technologies puissantes qui sont largement indépendantes de la résolution et du PPP.
Plus précisément, le texte, le SVG et une grande partie du CSS fonctionnent simplement grâce à la fonctionnalité de mise à l'échelle automatique des pixels du Web avec devicePixelRatio
.
Toutefois, vous ne pouvez pas toujours éviter les images matricielles. Par exemple, vous pouvez recevoir des éléments qui seraient très difficiles à reproduire en SVG ou en CSS purs. Il se peut que vous utilisiez une photo. Bien que vous puissiez convertir automatiquement une image en SVG, la vectorisation de photographies n'a guère de sens, car les versions agrandies ne sont généralement pas esthétiques.
Historique de la densité de pixels
Au début, les écrans d'ordinateur avaient une densité de pixels de 72 ou 96 points par pouce (ppp).
La densité de pixels des écrans s'est progressivement améliorée, en grande partie grâce à l'avancement des appareils mobiles, car les utilisateurs tiennent généralement leur téléphone plus près de leur visage, ce qui rend les pixels plus visibles. En 2008, les téléphones 150 dpi sont devenus la nouvelle norme. La densité d'affichage a continué d'augmenter, et les téléphones d'aujourd'hui sont dotés d'écrans 300 dpi.
En pratique, les images à faible densité devraient être identiques sur les nouveaux écrans que sur les anciens. Toutefois, par rapport aux images nettes que les utilisateurs sont habitués à voir sur les écrans à haute densité, les images à faible densité semblent choquantes et pixellisées. Voici une simulation approximative de l'apparence d'une image 1x sur un écran 2x. En revanche, l'image 2 x est plutôt réussie.
1 x pixels | 2 x pixels |
![]() |
![]() |
Pixels sur le Web
Lorsque le Web a été conçu, 99% des écrans affichaient 96 dpi, et peu de dispositions ont été prises en compte pour les variations. Maintenant que les tailles et densités d'écran varient beaucoup, nous avons besoin d'une méthode standard pour que les images soient agréables à regarder sur tous les écrans.
La spécification HTML a résolu ce problème en définissant un pixel de référence que les fabricants utilisent pour déterminer la taille d'un pixel CSS.
À l'aide du pixel de référence, un fabricant peut déterminer la taille du pixel physique de l'appareil par rapport au pixel standard ou idéal. Ce rapport est appelé "rapport de pixels de l'appareil".
Calculer le rapport de pixels de l'appareil
Supposons qu'un téléphone mobile dispose d'un écran dont la taille physique en pixels est de 180 pixels par pouce (ppp). Le calcul du rapport de pixels de l'appareil se fait en trois étapes:
Comparez la distance réelle à laquelle l'appareil est tenu à la distance du pixel de référence.
D'après les spécifications, nous savons qu'à 28 pouces, l'idéal est de 96 pixels par pouce. Avec un téléphone mobile, nous savons que le visage des utilisateurs est plus proche de leur appareil que sur un ordinateur portable ou de bureau. Pour les équations suivantes, nous estimons cette distance à 45 cm.
Multipliez le ratio de distance par la densité standard (96 ppp) pour obtenir la densité de pixels idéale pour la distance donnée.
idealPixelDensity = (28/18) * 96 = 150 pixels par pouce (environ)
Prenez le rapport entre la densité de pixels physique et la densité de pixels idéale pour obtenir le rapport de pixels de l'appareil.
devicePixelRatio = 180/150 = 1,2

Ainsi, lorsqu'un navigateur doit savoir comment redimensionner une image pour l'adapter à l'écran, en fonction de la résolution idéale ou standard, il se réfère au format de pixel de l'appareil de 1,2. Cela signifie que pour chaque pixel idéal, cet appareil dispose de 1,2 pixel physique. La formule permettant de passer des pixels idéaux (tels que définis par les spécifications Web) aux pixels physiques (points sur l'écran de l'appareil) est la suivante:
physicalPixels = window.devicePixelRatio * idealPixels
Historiquement, les fournisseurs d'appareils ont tendance à arrondir les devicePixelRatios
(DPR). L'iPhone et l'iPad d'Apple affichent un DPR de 1, et leurs équivalents Retina affichent 2. La spécification CSS recommande les éléments suivants :
L'unité de pixel fait référence au nombre entier de pixels de l'appareil qui se rapproche le plus du pixel de référence.
Les ratios arrondis peuvent être meilleurs, car ils peuvent entraîner moins d'artefacts sous-pixels.
Toutefois, la réalité du paysage des appareils est beaucoup plus variée, et les téléphones Android ont souvent un DPR de 1,5. La tablette Nexus 7 a un DPR d'environ 1,33, obtenu par un calcul semblable à l'exemple précédent. Vous verrez de plus en plus d'appareils avec des DPR variables à l'avenir. Par conséquent, vous ne devez jamais supposer que vos clients ont des DPR entiers.
Techniques d'image HiDPI
Il existe de nombreuses techniques pour résoudre le problème de l'affichage des images de la meilleure qualité le plus rapidement possible. Elles se divisent en deux grandes catégories:
- Optimiser des images uniques
- Optimisation de la sélection entre plusieurs images.
Approches à image unique: utilisez une seule image, mais faites-en quelque chose d'intelligent. Ces approches ont l'inconvénient que vous devez inévitablement sacrifier les performances, car vous devez télécharger des images HiDPI, même sur les appareils plus anciens dont le DPI est inférieur. Voici quelques approches pour le cas d'une seule image:
- Image HiDPI fortement compressée
- Format d'image totalement génial
- Format d'image progressif
Plusieurs approches d'images: utilisez plusieurs images, mais faites preuve d'ingéniosité pour choisir celles à charger. Ces approches impliquent des coûts inhérents pour le développeur, qui doit créer plusieurs versions du même composant, puis élaborer une stratégie de décision. Les différentes options proposées sont les suivantes :
- JavaScript
- Diffusion côté serveur
- Requêtes multimédias CSS
- Fonctionnalités du navigateur intégrées (
image-set()
,<img srcset>
)
Image HiDPI fortement compressée
Les images représentent déjà 60% de la bande passante utilisée pour télécharger un site Web moyen. En diffusant des images HiDPI auprès de tous les clients, nous augmentons ce nombre. Quelle est la taille maximale qu'il peut atteindre ?
J'ai effectué des tests qui ont généré des fragments d'image 1x et 2x avec une qualité JPEG de 90, 50 et 20.
D'après cet échantillonnage restreint et non scientifique, il semble que la compression des grandes images offre un bon compromis qualité/taille. À mon avis, les images 2x fortement compressées sont en fait plus belles que les images 1x non compressées.
Toutefois, diffuser des images de qualité inférieure et fortement compressées en double résolution sur des appareils en double résolution est moins efficace que de diffuser des images de meilleure qualité. Cette approche entraînerait des pénalités de qualité d'image. Si vous comparez des images quality: 90
à des images quality: 20
, la netteté de l'image diminue et le grain augmente. Les artefacts avec quality:20
peuvent ne pas être acceptables lorsque des images de haute qualité sont importantes (par exemple, une application de visionneuse de photos) ou pour les développeurs d'applications qui ne veulent pas faire de compromis.
Cette comparaison a été entièrement effectuée avec des fichiers JPEG compressés. Il est à noter qu'il existe de nombreux compromis entre les formats d'image largement implémentés (JPEG, PNG, GIF), ce qui nous amène à…
WebP: un format d'image vraiment génial
WebP est un format d'image attrayant qui compresse très bien les images tout en conservant une fidélité élevée.
Pour vérifier la compatibilité avec WebP, vous pouvez utiliser JavaScript. Chargez une image de 1 px avec data-uri
, attendez que des événements de chargement ou d'erreur soient déclenchés, puis vérifiez que la taille est correcte. Modernizr est fourni avec un tel script de détection de fonctionnalités, qui est disponible avec Modernizr.webp
.
Toutefois, il est préférable de le faire directement en CSS à l'aide de la fonction image(). Par conséquent, si vous disposez d'une image WebP et d'un remplacement JPEG, vous pouvez écrire ce qui suit:
#pic {
background: image("foo.webp", "foo.jpg");
}
Cette approche pose un certain nombre de problèmes. Tout d'abord, image()
n'est pas du tout largement implémenté. Deuxièmement, bien que la compression WebP surpasse le format JPEG, il s'agit toujours d'une amélioration relativement incrémentielle (environ 30% de plus petite taille d'après cette galerie WebP). Par conséquent, WebP seul ne suffit pas à résoudre le problème de haute résolution.
Formats d'image progressifs
Les formats d'image progressifs tels que JPEG 2000, JPEG progressif, PNG progressif et GIF présentent l'avantage (quelque peu discuté) de voir l'image se mettre en place avant qu'elle ne soit entièrement chargée. Ils peuvent entraîner des frais supplémentaires, bien que des preuves contradictoires soient disponibles à ce sujet. Jeff Atwood a déclaré que le mode progressif "ajoute environ 20% à la taille des images PNG et environ 10% à la taille des images JPEG et GIF". Toutefois, Stoyan Stefanov a affirmé que pour les fichiers volumineux, le mode progressif est plus efficace (dans la plupart des cas).
À première vue, les images progressives semblent très prometteuses pour diffuser des images de la meilleure qualité aussi rapidement que possible. L'idée est que le navigateur peut arrêter de télécharger et de décoder une image une fois qu'il sait que les données supplémentaires n'amélioreront pas la qualité de l'image (c'est-à-dire que toutes les améliorations de fidélité sont inférieures au pixel).
Bien que les connexions soient rapidement interrompues, leur redémarrage est souvent coûteux. Pour un site contenant de nombreuses images, l'approche la plus efficace consiste à maintenir une seule connexion HTTP active, en la réutilisant aussi longtemps que possible. Si la connexion est interrompue prématurément parce qu'une image a été suffisamment téléchargée, le navigateur doit alors créer une nouvelle connexion, ce qui peut être très lent dans les environnements à faible latence.
Pour contourner ce problème, vous pouvez utiliser la requête HTTP Range, qui permet aux navigateurs de spécifier une plage d'octets à extraire. Un navigateur intelligent peut envoyer une requête HEAD pour accéder à l'en-tête, le traiter, décider de la partie de l'image réellement nécessaire, puis l'extraire. Malheureusement, la plage HTTP n'est pas bien prise en charge par les serveurs Web, ce qui rend cette approche peu pratique.
Enfin, une limite évidente de cette approche est que vous ne pouvez pas choisir l'image à charger, mais seulement les fidélités différentes de la même image. Par conséquent, cela ne répond pas au cas d'utilisation de la direction artistique.
Déterminer quelle image charger à l'aide de JavaScript
La première approche la plus évidente pour choisir l'image à charger consiste à utiliser JavaScript dans le client. Cette approche vous permet de tout savoir sur votre user-agent et de prendre les mesures appropriées. Vous pouvez déterminer le format de l'appareil en pixels avec window.devicePixelRatio
, obtenir la largeur et la hauteur de l'écran, et même effectuer une analyse de la connexion réseau avec navigator.connection ou émettre une fausse requête, comme le fait la bibliothèque foresight.js. Une fois que vous avez collecté toutes ces informations, vous pouvez choisir l'image à charger.
Environ un million de bibliothèques JavaScript utilisent cette technique. Malheureusement, aucune d'elles n'est particulièrement remarquable.
L'inconvénient majeur est que vous retardez le chargement des images jusqu'à la fin de l'analyseur d'anticipation. Cela signifie essentiellement que le téléchargement des images ne commencera même pas tant que l'événement pageload
ne se déclenchera pas. Pour en savoir plus, consultez cet article de Jason Grigsby.
Décider de l'image à charger sur le serveur
Vous pouvez différer la décision côté serveur en écrivant des gestionnaires de requêtes personnalisés pour chaque image que vous diffusez. Un tel gestionnaire vérifie la compatibilité avec Retina en fonction de l'User-Agent (la seule information partagée avec le serveur). Ensuite, selon que la logique côté serveur souhaite diffuser des éléments HiDPI, vous chargez l'élément approprié (nommé selon une convention connue).
Malheureusement, l'User-Agent ne fournit pas nécessairement suffisamment d'informations pour déterminer si un appareil doit recevoir des images de haute ou de basse qualité. De plus, toute solution qui utilise User-Agent
pour prendre des décisions de style doit être évitée.
Utiliser des requêtes multimédias CSS
Étant déclaratives, les requêtes multimédias CSS vous permettent d'indiquer votre intention et de laisser le navigateur faire ce qu'il faut en votre nom. En plus de l'utilisation la plus courante des requêtes multimédias (correspondance à la taille de l'appareil), vous pouvez également faire correspondre devicePixelRatio
. La requête multimédia associée est "device-pixel-ratio" et comporte des variantes minimales et maximales, comme vous pouvez vous y attendre.
Si vous souhaitez charger des images haute résolution et que le format de pixel de l'appareil dépasse un seuil, procédez comme suit:
#my-image { background: (low.png); }
@media only screen and (min-device-pixel-ratio: 1.5) {
#my-image { background: (high.png); }
}
Cela devient un peu plus compliqué avec tous les préfixes du fournisseur mélangés, en particulier en raison des grandes différences d'emplacement des préfixes "min" et "max" :
@media only screen and (min--moz-device-pixel-ratio: 1.5),
(-o-min-device-pixel-ratio: 3/2),
(-webkit-min-device-pixel-ratio: 1.5),
(min-device-pixel-ratio: 1.5) {
#my-image {
background:url(high.png);
}
}
Avec cette approche, vous retrouvez les avantages de l'analyse anticipée, qui ont été perdus avec la solution JavaScript. Vous bénéficiez également de la flexibilité de choisir vos points d'arrêt responsifs (par exemple, vous pouvez avoir des images à faible, moyen et haut DPI), ce qui était perdu avec l'approche côté serveur.
Malheureusement, il est encore un peu lourd, et donne un CSS étrange ou nécessite un prétraitement. De plus, cette approche est limitée aux propriétés CSS. Il n'est donc pas possible de définir un <img src>
, et vos images doivent toutes être des éléments avec un arrière-plan. Enfin, en vous appuyant strictement sur le format de pixel de l'appareil, vous pouvez vous retrouver dans des situations où votre téléphone mobile haute résolution finit par télécharger un élément image massif 2 x sur une connexion EDGE. Ce n'est pas la meilleure expérience utilisateur.
Étant donné que image-set()
est une fonction CSS, elle ne résout pas le problème pour les balises <img>
. Saisissez @srcset pour résoudre ce problème.
La section suivante présente plus en détail image-set
et srcset
.
Fonctionnalités du navigateur pour la compatibilité avec les écrans haute résolution
En définitive, la façon dont vous abordez la prise en charge du DPI élevé dépend de vos exigences particulières. Toutes les approches mentionnées ci-dessus présentent des inconvénients.
Maintenant que image-set
et srcset
sont largement compatibles, ce sont les meilleures solutions. D'autres bonnes pratiques peuvent nous rapprocher pour les anciens navigateurs.
En quoi ces deux éléments sont-ils différents ? image-set()
est une fonction CSS, qui peut être utilisée comme valeur de la propriété CSS d'arrière-plan.
srcset
est un attribut spécifique aux éléments <img>
, avec une syntaxe similaire.
Ces deux balises vous permettent de spécifier des déclarations d'images, mais l'attribut srcset
vous permet également de configurer l'image à charger en fonction de la taille de la fenêtre d'affichage.
Bonnes pratiques pour les ensembles d'images
La syntaxe image-set()
accepte une ou plusieurs déclarations d'images séparées par une virgule, qui consistent en une chaîne d'URL ou en une fonction url()
suivie de la résolution appropriée. Exemple :
image-set(
url("image1.jpg") 1x,
url("image2.jpg") 2x
);
/* You can also include image-set without `url()` */
image-set(
"image1.jpg" 1x,
"image2.jpg" 2x
);
Cela indique au navigateur qu'il a le choix entre deux images. L'une est optimisée pour les écrans 1 x, et l'autre pour les écrans 2 x. Le navigateur peut ensuite choisir laquelle charger en fonction de divers facteurs, y compris la vitesse du réseau, s'il est suffisamment intelligent.
En plus de charger l'image appropriée, le navigateur la met à l'échelle en conséquence. En d'autres termes, le navigateur suppose que les images 2 sont deux fois plus grandes que les images 1, et réduit donc l'image 2 d'un facteur 2, de sorte que l'image semble avoir la même taille sur la page.
Au lieu de spécifier 1x, 1,5x ou Nx, vous pouvez également spécifier une certaine densité de pixels de l'appareil en DPI.
Si vous êtes préoccupé par les anciens navigateurs qui ne sont pas compatibles avec la propriété image-set
, vous pouvez ajouter un élément de remplacement pour vous assurer qu'une image s'affiche. Exemple :
/* Fallback support. */
background-image: url(icon1x.jpg);
background-image: image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x
);
image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x
);
Cet exemple de code charge l'élément approprié dans les navigateurs compatibles avec image-set et utilise l'élément 1x dans le cas contraire.
À ce stade, vous vous demandez peut-être pourquoi ne pas simplement polyfiller (c'est-à-dire créer un shim JavaScript pour) image-set()
et en finir ? Il s'avère qu'il est assez difficile d'implémenter des polyfills efficaces pour les fonctions CSS. (Pour une explication détaillée, consultez cette discussion sur le style www.)
Image srcset
En plus des déclarations fournies par image-set
, l'élément srcset
prend également des valeurs de largeur et de hauteur qui correspondent à la taille de la fenêtre d'affichage, en essayant de diffuser la version la plus pertinente.
<img alt="my awesome image"
src="banner.jpeg"
srcset="banner-HD.jpeg 2x, banner-phone.jpeg 640w, banner-phone-HD.jpeg 640w 2x">
Cet exemple affiche banner-phone.jpeg
sur les appareils dont la largeur de la fenêtre d'affichage est inférieure à 640 px, banner-phone-HD.jpeg
sur les appareils à petit écran et haute résolution, banner-HD.jpeg
sur les appareils à haute résolution dont l'écran est supérieur à 640 px et banner.jpeg
sur tous les autres appareils.
Utiliser image-set pour les éléments image
Vous pourriez être tenté de remplacer vos éléments img par des <div>
avec des arrière-plans et d'utiliser l'approche image-set. Cela fonctionne, mais avec des réserves. L'inconvénient est que la balise <img>
a une valeur sémantique à long terme. En pratique, cela est important pour l'accessibilité et les robots d'exploration Web.
Vous pouvez utiliser la propriété CSS de contenu, qui met automatiquement à l'échelle l'image en fonction de devicePixelRation
. Exemple :
<div id="my-content-image"
style="content: -webkit-image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x);">
</div>
Polyfill srcset
srcset
est pratique, car il est fourni avec un remplacement naturel.
Si l'attribut srcset n'est pas implémenté, tous les navigateurs savent traiter l'attribut src. De plus, comme il ne s'agit que d'un attribut HTML, il est possible de créer des polyfills avec JavaScript.
Ce polyfill est fourni avec des tests unitaires pour s'assurer qu'il est aussi proche que possible de la spécification. De plus, des vérifications sont en place pour empêcher le polyfill d'exécuter du code si le srcset est implémenté en mode natif.
Conclusion
La meilleure solution pour les images haute résolution consiste à opter pour les SVG et les CSS. Cependant, ce n'est pas toujours une solution réaliste, en particulier pour les sites Web contenant de nombreuses images.
Les approches JavaScript, CSS et les solutions côté serveur ont leurs forces et leurs faiblesses. L'approche la plus prometteuse consiste à utiliser image-set
et srcset
.
Pour résumer, voici mes recommandations:
- Pour les images de fond, utilisez image-set avec les solutions de remplacement appropriées pour les navigateurs qui ne le prennent pas en charge.
- Pour les images de contenu, utilisez un polyfill srcset ou utilisez image-set (voir ci-dessus).
- Si vous êtes prêt à sacrifier la qualité de l'image, envisagez d'utiliser des images 2 x compressées.