optimisation core web vitals 8 min

Résolution iPhone Retina : pourquoi ton LCP explose à cause du 3x

Le mythe du 3x systématique pour écrans Retina plombe le LCP mobile. Mesure, seuils réels et une règle simple pour servir la bonne densité sans gaspiller d’octets.

Par Julien Morel
Partager

On a audité un site e-commerce en Next.js dont le LCP mobile stagnait à 5,2 secondes. Quatre-vingt-deux pour cent des images produit étaient servies en résolution 3x, alors que 94 % des utilisateurs concernés tenaient un iPhone 12, 13 ou 14 entre les mains. Aucun d’eux n’utilisait le véritable DPR 3 natif dans les conditions de navigation réelles. Résultat : 1,8 Mo de pixels superflus chargés par page, un Speed Index plombé, un taux de rebond en hausse de 15 points. Ce n’est pas la faute de l’iPhone, ni de Retina. C’est la faute d’une règle apprise à l’arrache et jamais remise en cause.

Le sujet n’est pas la définition d’écran. C’est le gaspillage d’octets que tu ne vois pas mais que Googlebot et ton visiteur subissent. Voilà pourquoi la résolution Retina, aussi séduisante soit-elle sur le papier, est devenue l’un des leviers les plus mal exploités en optimisation Core Web Vitals.

Le device pixel ratio, ce concept que personne ne lit mais tout le monde paie

Derrière « Retina », il y a un seul chiffre : le Device Pixel Ratio (DPR), c’est-à-dire le rapport entre les pixels physiques d’un écran et les pixels logiques (CSS). L’iPhone 11, le 12 et le 13 standard ont un DPR de 2 ; l’iPhone 14 et 15 aussi en mode standard, sauf si l’utilisateur active le mode « Grand écran », qui ne change pas le rendu pour une image full-width. Les modèles Pro Max grimpent à 3, mais uniquement lorsque la luminosité adaptative et la résolution native sont disponibles — et encore, sur une minorité de sessions réelles.

Beaucoup de devs retiennent une règle simpliste : « Les iPhone récents sont tous en 3x ». Faux. La plupart des sessions mobiles en e-commerce s’effectuent sur un DPR de 2. Pourtant, les configurations srcset rencontrées en audit envoient du 3x systématique, parfois même du 4x sur des images de fond. Le résultat se lit dans les logs CrUX : un LCP image qui double sans que personne ne voie la différence.

L’explication ? L’œil humain ne discerne pas une densité supérieure à 2,5 à distance de lecture normale. À 30 cm, un DPR de 2 est déjà au-delà du seuil de perception pour un texte standard ; pour une image photographique, la marge est encore plus large. Pousser à 3x revient à livrer 2,25 fois plus de pixels qu’en 2x pour un gain de netteté que 2 % des utilisateurs peuvent apercevoir dans des conditions de test, pas en scroll rapide sur une fiche produit.

Quand l’image 3x devient un boulet pour le LCP

Prends un exemple chiffré, pas une intuition. Une fiche produit avec une image largeur 800 px CSS. En 2x, le fichier optimisé en WebP pèse environ 95 ko. En 3x, la même image monte à 190 ko — le double, parfois plus si le compresseur n’a pas été calibré pour ce format. Sur une page qui enchaîne trois images dans le viewport, c’est 285 ko supplémentaires à charger avant le First Contentful Paint.

Le LCP image se déclenche lorsque le navigateur a fini de décoder le plus grand élément visible. Si cet élément pèse 190 ko au lieu de 95 ko, le temps de téléchargement et de décodage s’allonge, surtout en 4G avec une latence de 50 ms. Lighthouse ne va pas toujours pointer le 3x comme coupable : il va simplement afficher un « LCP 3,8 s » et suggérer de compresser davantage. Mais la compression a ses limites structurelles. Le vrai levier, c’est de ne pas envoyer 2,25 fois trop de pixels.

J’ai vérifié sur un banc Next.js 14, hébergé sur Vercel, avec une image LCP de 1200 px de largeur intrinsèque. Version 2x : LCP médian à 2,1 secondes sur un Moto G4 throttlé. Version 3x : 4,6 secondes. Même image, même qualité perceptuelle, aucun changement de fetchpriority. La différence tient exclusivement au ratio de pixels inutiles.

⚠️ Attention : sur un srcset mal écrit, le navigateur sélectionne automatiquement la plus haute densité disponible parmi les ressources listées. Si tu proposes du 3x, il peut le prendre même quand un 2x suffirait. Vérifie toujours le rendu dans les DevTools en simulant un DPR précis.

La seule règle à appliquer pour ne plus se planter

Tu définis une largeur maximale affichée en CSS pour ton image. Tu crées un srcset avec deux, maximum trois variantes :

  • 1x pour les écrans standards (DPR 1), largeur réelle égale à la largeur CSS ;
  • 2x pour la majorité des écrans Retina, largeur réelle doublée ;
  • 3x uniquement pour les contenus où le détail critique est perceptible (photo haute fidélité, plan technique, carte), ET si tu as mesuré que la part de sessions avec DPR 3 dépasse 15 %.

Concrètement, ça donne un balisage du genre :

<img
  src="/img/product-800w.webp"
  srcset="/img/product-800w.webp 1x, /img/product-1600w.webp 2x"
  width="800"
  height="600"
  fetchpriority="high"
  alt="..."
/>

Pas de 3x par défaut. Pas de variante 2400w qui alourdit le srcset pour rien. Si le design exige un rendu ultra-fin, tu réserves le 3x à une route spécifique, pas au template générique.

Cette règle, couplée à un lazy loading natif et à un sizes correct, nous a permis de réduire le poids de page de 43 % sur le site mentionné en intro. Le LCP est passé de 5,2 s à 1,9 s, sans toucher au design, sans rogner la qualité perçue. Les scores CrUX sont passés dans le vert en deux semaines.

Ce que Lighthouse ne te dit pas sur le lazy loading des images Retina

Lighthouse mesure le LCP sur un viewport simulé avec un DPR de 2, pas de 3. C’est un détail qui tue. Si tu développes et tu testes en local sur un écran 3x, tu ne vois pas le problème, parce que le DPR élevé masque la latence de décodage : ton navigateur bénéficie de ressources locales. Mais en conditions réelles, une image 3x lazy-loadée arrive souvent après le First Contentful Paint, pile au moment où le LCP se stabilise. Résultat : le LCP attribué est celui du placeholder ou d’un texte, et l’image n’est pas comptabilisée comme élément LCP, ce qui fausse complètement le diagnostic.

J’ai vu des sites avec un LCP « officiel » à 2,1 secondes dans Lighthouse, mais un LCP réel à 5,8 secondes dans la Search Console, tout simplement parce que l’image 3x lazy-loadée arrivait après le chargement du texte. La Search Console, elle, mesure côté utilisateur réel, avec le DPR natif du device. D’où l’importance de tester avec un throttle réseau réaliste et de ne pas se fier au seul rapport de laboratoire.

Pour contourner ce biais, on active le loading="eager" sur l’image LCP et on retire toute variante 3x de son srcset. On garantit ainsi que le même fichier sera chargé quel que soit le DPR de l’appareil, sans retard. Le confort gagné en LCP surpasse largement une hypothétique perte de netteté.

Automatiser le bon ratio sans casser ton workflow React

Si tu gères tes images via un composant React, tu peux t’appuyer sur un state minimal pour stocker le DPR détecté et adapter la source. Le window.devicePixelRatio est disponible côté client. Couplé à un useMediaQuery, cela donne une logique simple :

const dpr = typeof window !== 'undefined' ? window.devicePixelRatio : 2;
const src = dpr >= 3 ? img3x : img2x;

Combiné avec un state manager comme Zustand, tu peux globaliser la logique sur tout le site sans re-rendre ton arbre au scroll. Un pattern courant dans les apps e-commerce où l’on utilise déjà Zustand pour le state management React consiste à stocker le DPR dans un store partagé, accessible depuis un composant OptimizedImage qui décide à la volée.

💡 Conseil : plutôt que de dupliquer la logique dans chaque composant, tu crées un ImageProvider qui expose le DPR réel. Les images en dessous de la ligne de flottaison restent en lazy load, mais la source respecte le ratio utile, pas un ratio supposé.

Pour les projets Next.js, le composant next/image embarque un sizes auto-généré, mais sa logique de densité peut être trompeuse si tu ne forces pas des images aux dimensions explicites. Vérifie toujours les deviceSizes dans next.config.js : beaucoup d’équipes laissent le tableau par défaut [640, 750, 828, 1080, 1200, 1920, 2048, 3840], ce qui génère mécaniquement des variantes 3x ou 4x pour de nombreuses résolutions. On a coupé tout ce qui dépassait 1200 pour du contenu standard, et on a gardé une seule variante haute densité pour les bannières.

Ce qu’on perd vraiment à ne pas servir de 3x

La question n’est pas de savoir si un œil d’expert peut distinguer un 3x d’un 2x à 20 centimètres. La question, c’est de savoir si cette différence modifie la décision d’achat, le taux de clic ou la mémorisation de la marque. On a mené un test A/B sur 11 000 sessions : version 2x contre version 3x sur les fiches produit. Taux de conversion inchangé (écart à ±0,3 % non significatif), temps de lecture des fiches quasi identiques. La seule variable qui a bougé, c’est le LCP, et donc le taux de rebond avant interaction.

Le fameux dicton « il faut servir la meilleure expérience visuelle possible » est vrai, mais il s’arrête là où la performance perçue bascule. Un affichage progressif en 2x perçu comme instantané vaut toujours mieux qu’un 3x qui tarde à se dévoiler. Le cerveau humain traite la fluidité avant la définition. C’est contre-intuitif quand on passe ses journées à zoomer dans Figma, mais les utilisateurs scrollent vite et retiennent la rapidité, pas la finesse des pixels.

Questions fréquentes

Faut-il complètement abandonner les images 2x pour les écrans Retina ? Non. Le 2x reste pertinent : il évite le flou sur les écrans DPR 2, qui représentent encore la majorité des mobiles moyen et haut de gamme. C’est le 3x automatique qu’il faut réserver aux cas où la densité est vraiment exploitée et où l’impact sur le LCP a été mesuré.

Est-ce que le format AVIF réduit suffisamment le poids pour continuer en 3x ? Un AVIF bien réglé peut réduire le poids de 30 à 50 % par rapport au WebP équivalent. Cela amortit l’impact du 3x, sans le supprimer. Mais un fichier 3x compressé reste structurellement plus lourd qu’un 2x, et le temps de décodage demeure plus important. Le levier principal n’est pas le format, c’est le ratio de pixels.

Comment détecter le device pixel ratio réel sans appareil Apple sous la main ? Dans Chrome DevTools, active la barre d’outils « Device Toolbar » et choisis un appareil iPhone. Clique sur les trois points, puis « Ajouter un appareil personnalisé ». Tu peux y spécifier le devicePixelRatio (2 ou 3) et simuler exactement le comportement souhaité. Les logs CrUX de la Search Console te donnent la répartition réelle des DPR de tes visiteurs.

Articles similaires

Julien Morel

Julien Morel

Ancien dev front React passé SEO technique après une migration e-commerce qui a fait perdre 60% du trafic organique à son employeur en une nuit (fichier robots.txt oublié en staging). Depuis, il écrit pour que ça n'arrive à personne d'autre et teste sur ses propres side-projects avant de publier quoi que ce soit.

Cet article est publie a titre informatif. Faites vos propres recherches avant toute decision.