Comment les images et les médias provoquent un Layout Shift (et comment le corriger)

Le guide complet pour prévenir le CLS dû aux images, vidéos, iframes, images responsives et intégrations de médias

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-27

Comment les images et les médias provoquent un Layout Shift (et comment le corriger)

Le Web Almanac 2025 chiffre ce que je continue d'observer sur le terrain : 62 % des pages mobiles ont au moins une image sans largeur et hauteur explicites. Cela fait des médias non dimensionnés la cause numéro un du Cumulative Layout Shift sur le web. Et chacun de ces décalages est évitable grâce à des techniques qui existent depuis 2019.

Dernière révision par Arjen Karel en mars 2026

Le navigateur ne sait pas quelle est la taille de votre image

Chaque Layout Shift lié à une image se résume à une chose. Le navigateur ne sait pas combien d'espace réserver avant que l'image ne se charge.

Lorsque le navigateur rencontre une balise <img> sans dimensions, il rend l'image à 0x0 pixels. Le fichier arrive, le navigateur recalcule la mise en page, et tout ce qui se trouve sous l'image saute vers le bas. Ce saut est votre CLS.

Comment width et height préviennent le Layout Shift

En 2019 et 2020, tous les principaux navigateurs ont intégré une fonctionnalité qui a modifié le fonctionnement des attributs width et height. Les navigateurs les utilisent désormais pour calculer un ratio d'aspect avant le téléchargement de l'image.

Quand vous écrivez ceci :

<img src="hero.jpg" width="800" height="450" alt="Description">

Le navigateur génère ceci en interne :

img[Attributes Style] {
    aspect-ratio: auto 800 / 450;
}

Aucune donnée d'image n'est nécessaire. Le navigateur connaît le ratio et réserve l'espace vertical.

Ce ratio interne a la priorité CSS la plus faible, donc toute règle CSS que vous écrivez l'écrase. C'est important car c'est la raison pour laquelle width: auto casse tout (plus d'informations à ce sujet dans un instant).

Le mot-clé auto indique au navigateur : utilisez ce ratio comme espace réservé, mais une fois que l'image réelle se charge, passez aux vraies dimensions. Si vous définissez accidentellement de mauvaises valeurs (par exemple width="4" height="3" sur une image 16:9), le navigateur réserve un espace 4:3 initialement, puis corrige en 16:9 lorsque l'image se charge. Cette correction est un Layout Shift. Utilisez toujours les dimensions réelles en pixels.

Pour les images responsives, ajoutez ce CSS :

<style>
img {
    height: auto;
    max-width: 100%;
}
</style>

height: auto calcule la hauteur à partir du ratio. max-width: 100% empêche l'image de dépasser son conteneur. Le navigateur connaît la largeur et le ratio. C'est suffisant.

Pourquoi width:auto casse votre CLS

C'est celui que je vois le plus souvent et celui qui fait perdre le plus de temps en débogage. Le développeur définit width et height sur chaque image, fait tout correctement dans le HTML, lance Lighthouse, obtient un score vert, et déploie. Ensuite, les plaintes concernant le CLS arrivent de la part des utilisateurs réels.

La cause se trouve toujours quelque part dans le CSS. Une règle globale défait tout :

<style>
img {
    width: auto;
    height: auto;
    max-width: 100%;
}
</style>

Le problème est width: auto. Comme le ratio interne du navigateur a la priorité CSS la plus faible, toute règle le remplace. width: auto supprime la largeur que le navigateur utilisait pour calculer la hauteur. Les deux dimensions deviennent inconnues. L'image est rendue à 0x0 jusqu'au téléchargement du fichier, puis passe brusquement à sa taille réelle.

Définir aspect-ratio en CSS ne corrige pas cela. Avec width: auto, le navigateur traite la largeur comme 0 avant le chargement de l'image. Un ratio d'aspect calculé à partir de 0 produit toujours 0. Zéro multiplié par quoi que ce soit donne zéro.

Voici la partie qui rend cela si difficile à repérer : cela ne cause un décalage que pour les nouveaux visiteurs. Si l'image est dans le cache du navigateur, les dimensions réelles sont disponibles immédiatement et aucun décalage ne se produit. Vous, en tant que développeur, ne le verrez jamais sur votre propre machine. Vos testeurs ne le verront pas. Votre équipe QA ne le verra pas. Seuls vos utilisateurs réels lors de leur première visite le verront, ce qui est exactement la visite que Google mesure pour CrUX.

J'ai passé des heures en appel avec des équipes d'ingénierie qui juraient que leur CLS était corrigé parce qu'elles ne pouvaient pas le reproduire localement. C'était toujours ça. Vérifiez votre CSS. Si vous avez un width: auto global sur les images, c'est ça votre problème.

Le correctif :

<style>
img {
    height: auto;
    max-width: 100%;
}
</style>

Supprimez width: auto. Gardez height: auto et max-width: 100%. C'est le modèle recommandé par web.dev.

Vérification rapide : faites un clic droit sur n'importe quelle image de votre site, choisissez "Inspecter l'élément", et regardez les styles calculés. Si vous voyez width: auto, vous savez maintenant quoi faire. Pour une explication complète, consultez comment corriger le Layout Shift causé par les images à redimensionnement automatique.

Quand l'aspect-ratio CSS est le meilleur choix

Les attributs width/height sont l'approche par défaut. Mais parfois, vous voulez que CSS impose un ratio spécifique quel que soit le contenu de l'image. Une bannière hero qui doit toujours être en 16:9, ou une grille de fiches produits où chaque image nécessite la même forme :

<style>
img {
    aspect-ratio: 16 / 9;
    width: 100%;
}
</style>

Fonctionne dans tous les navigateurs modernes (Chrome 88+, Firefox 87+, Safari 15+) et sur n'importe quel élément, pas seulement les images et les vidéos.

Pour les images de contenu standard, les attributs width/height sont meilleurs. Ils décrivent les dimensions réelles et s'auto-corrigent lorsque l'image se charge.

Vous pouvez combiner les deux :

<style>
img {
    aspect-ratio: auto 16 / 9;
    width: 100%;
}
</style>

Le mot-clé auto ici signifie : utilisez 16/9 avant le chargement de l'image, passez au ratio naturel après. Réservation d'espace avant le chargement, dimensionnement précis après.

Les vidéos ont le même problème

Une vidéo sans width et height est rendue à 0x0 jusqu'à ce que le navigateur télécharge suffisamment du fichier pour lire ses métadonnées. Sur une connexion lente, cela prend des secondes. Le correctif est identique aux images :

<video src="demo.mp4" width="1280" height="720" autoplay muted loop></video>

Les navigateurs calculent un aspect-ratio: auto 1280 / 720 interne à partir des attributs. Ajoutez height: auto; max-width: 100%; dans le CSS et vous avez terminé.

Une chose à surveiller : l'image poster. Si vous définissez un poster mais ne définissez pas les dimensions sur l'élément vidéo, l'élément s'adapte à la taille du poster. Lorsque la vidéo commence à jouer et a une résolution différente, vous obtenez un décalage. Définissez width et height pour correspondre à la résolution de la vidéo, pas à celle du poster.

Les iframes sont par défaut à 300x150 pixels

Une iframe sans dimensions explicites est par défaut à 300x150 pixels. Pour la plupart des intégrations (YouTube, Google Maps, publications sur les réseaux sociaux), c'est incorrect. Au moment où l'intégration se charge et se redimensionne, tout autour se décale.

Contrairement aux images, les iframes ne calculent pas automatiquement un ratio d'aspect à partir de leurs attributs. Vous devez définir le dimensionnement vous-même :

<style>
.responsive-iframe {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
}
</style>

Cela remplace l'ancien hack du padding-top où vous enveloppiez l'iframe dans un conteneur avec padding-top: 56.25% et le positionniez de manière absolue. L'ancien hack fonctionne toujours. aspect-ratio est plus propre et ne nécessite pas de wrapper.

Ou ne chargez pas l'iframe du tout

Pour YouTube, Vimeo, Google Maps et les intégrations sociales, j'ai arrêté de charger les iframes au chargement de la page il y a des années. Le pattern de façade est meilleur à tous points de vue : affichez une image statique en placeholder avec le bon ratio d'aspect. Lorsque l'utilisateur clique, JavaScript l'échange avec la véritable iframe. Zéro iframe, zéro CLS, zéro ressource gaspillée.

Le décalage dû à l'échange se produit dans les 500ms suivant l'interaction de l'utilisateur et est exclu du CLS par conception.

Pour des exemples d'implémentation, consultez intégrations YouTube parfaites et Google Maps sans perdre en PageSpeed.

Direction artistique : quand les recadrages mobile et desktop ont des ratios différents

La direction artistique, c'est quand vous servez différents recadrages selon la largeur du viewport. Paysage large sur desktop, portrait plus serré sur mobile. L'élément <picture> gère cela avec des éléments <source>.

Le problème de CLS : ces recadrages ont généralement des ratios d'aspect différents. Le navigateur doit savoir quelles dimensions correspondent à quel point d'arrêt. Vous pouvez définir width et height sur chaque <source> :

<picture>
    <source
        media="(max-width: 799px)"
        srcset="hero-mobile.jpg"
        width="480" height="600">
    <source
        media="(min-width: 800px)"
        srcset="hero-desktop.jpg"
        width="1200" height="400">
    <img
        src="hero-desktop.jpg"
        width="1200" height="400"
        alt="Product hero image">
</picture>

Chrome et Safari récupèrent la bonne combinaison width/height à partir de la <source> active. Pas Firefox. Il y a un bug (bug 1694741) où Firefox utilise toujours les dimensions de secours de <img>, quelle que soit la source sélectionnée. Si le recadrage mobile a un ratio différent, Firefox affiche un décalage.

Si tous vos recadrages partagent le même ratio (juste des résolutions différentes), ce bug n'a pas d'importance. Il ne se déclenche que lorsque les ratios diffèrent entre les points d'arrêt.

Solution de contournement pour Firefox

En attendant que le correctif soit déployé, utilisez des media queries CSS qui correspondent aux points d'arrêt dans vos éléments <source> :

<style>
picture img {
    width: 100%;
    height: auto;
}
@media (max-width: 799px) {
    picture img {
        aspect-ratio: 480 / 600;
    }
}
@media (min-width: 800px) {
    picture img {
        aspect-ratio: 1200 / 400;
    }
}
</style>

Cela remplace le ratio interne du navigateur par un CSS explicite pour chaque point d'arrêt. Fonctionne dans tous les navigateurs.

Gardez le même ratio sur toutes les sources srcset

Les images responsives avec srcset et sizes peuvent causer un CLS si les attributs width/height ne correspondent pas à la source sélectionnée. La règle est simple : toutes les images d'un srcset doivent partager le même ratio d'aspect. Si c'est le cas, un seul jeu de width/height sur la balise <img> est suffisant :

<img
    src="hero-800.jpg"
    srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1200.jpg 1200w"
    sizes="(max-width: 600px) 100vw, 800px"
    width="800" height="450"
    alt="Hero image">

800:450 est le même ratio sur les trois variantes. Peu importe laquelle le navigateur choisit, l'espace réservé est correct.

Si vous mélangez les ratios dans le même srcset (une source en 16:9, une autre en 4:3), l'espace réservé sera incorrect pour au moins l'une d'entre elles. Ne faites pas cela. Utilisez plutôt l'élément <picture> avec des éléments <source> si vous avez besoin de ratios différents.

Quand sizes est incorrect

L'attribut sizes indique au navigateur la largeur de rendu de l'image pour chaque taille de viewport. S'il ne correspond pas à la mise en page CSS réelle, le navigateur choisira une source trop grande ou trop petite. Cela ne cause pas de CLS (le ratio reste le même), mais cela gaspille de la bande passante ou produit une image floue.

sizes=auto pour les images en lazy loading

Chrome 126+ et Edge 126+ prennent en charge sizes="auto" sur les images en lazy loading. Le navigateur calcule la taille correcte à partir de la mise en page CSS au lieu de se fier à votre attribut sizes écrit manuellement. Cela ne fonctionne pas sur les images chargées immédiatement (eager-loaded) car le navigateur a besoin de la taille de mise en page avant que le CSS ne soit analysé.

Ne faites pas de lazy loading au-dessus de la ligne de flottaison

Le lazy loading d'images au-dessus de la ligne de flottaison cause deux problèmes à la fois. Cela retarde le LCP car loading="lazy" cache la ressource au preload scanner. Le navigateur ne peut pas découvrir l'image avant la mise en page. Et si l'image n'a pas non plus de dimensions, vous obtenez un Layout Shift en plus du chargement retardé.

Le Web Almanac 2025 rapporte que 16 % des pages utilisent encore le lazy loading pour leur image LCP. C'est 16 % du web qui retarde son image la plus importante pour zéro bénéfice.

loading="lazy" n'a sa place que sur les images en dehors du viewport initial. Nulle part ailleurs.

Les placeholders de 1x1 pixel causent des décalages massifs

Les scripts JavaScript de lazy loading utilisent souvent un minuscule GIF transparent de 1x1 pixel comme placeholder dans le src pendant que l'URL réelle se trouve dans data-src. Lorsque IntersectionObserver se déclenche, JavaScript les échange.

Cela cause un CLS car le placeholder 1x1 est rendu avec une hauteur de 1px. Lorsque l'image 800x450 se charge, l'élément saute de 1px à 450px. Si vous utilisez encore une bibliothèque JavaScript de lazy loading en 2026, arrêtez. L'attribut natif loading="lazy" gère le placeholder en interne et respecte les attributs width/height. Il bénéficie d'une prise en charge complète par les navigateurs depuis 2022.

Si vous avez une raison spécifique de conserver un lazy loading JavaScript (seuils d'intersection, animations de fondu), utilisez un placeholder avec le même ratio d'aspect que l'image finale. Un SVG transparent 16x9 au lieu d'un 1x1.

LQIP bien fait

Un placeholder miniature flouté est plus esthétique qu'un espace vide. La clé : préserver le ratio d'aspect. Si votre image finale est de 800x450, votre LQIP devrait être une version minuscule (10x6 ou 20x11) avec le même ratio. Agrandissez-la avec CSS, appliquez un filtre de flou. Lorsque la véritable image se charge, elle remplace le flou avec les mêmes dimensions. Aucun décalage.

Next.js fait cela automatiquement. Le composant Image génère width, height et blurDataURL au moment du build. Zéro CLS.

Utilisez object-fit pour les conteneurs de taille fixe

Les grilles de fiches produits où chaque fiche a la même hauteur mais où les images ont des ratios différents. Je vois constamment ce modèle :

<style>
.product-image {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    object-position: center;
}
</style>
<img
    src="product.jpg"
    width="400" height="600"
    class="product-image"
    alt="Product name">

aspect-ratio: 1 / 1 force un carré. object-fit: cover remplit le carré et recadre ce qui dépasse. La taille est verrouillée avant le chargement de l'image.

C'est également ainsi que vous remplacez les images d'arrière-plan CSS par de véritables éléments <img>. Les images d'arrière-plan ne peuvent pas utiliser le lazy loading, ne peuvent pas utiliser fetchpriority, et le preload scanner ne les trouve pas tant que le fichier CSS n'est pas analysé. Un élément <img> avec object-fit: cover vous donne tous les contrôles de performance qui manquent à une image d'arrière-plan.

Les carrousels en lecture automatique produisent un CLS infini

Les transitions de diapositives qui animent left, width, ou margin déclenchent un recalcul de la mise en page. Puisque la lecture automatique n'est pas une interaction utilisateur, chaque décalage compte dans le CLS. Un carrousel en lecture automatique avec des transitions déclenchant des recalculs de mise en page peut produire du CLS indéfiniment.

Fixez les dimensions du conteneur avec un ratio d'aspect fixe, animez avec transform: translateX() au lieu de left ou margin-left (les transforms s'exécutent sur le GPU et ne déclenchent jamais de recalcul de mise en page), et si vous devez utiliser la lecture automatique, les dimensions du conteneur de diapositives ne peuvent pas changer. Tout redimensionnement compte comme du CLS.

Dans un carrousel sans lecture automatique, la plupart des transitions se produisent dans les 500ms suivant le clic d'un utilisateur et sont exclues du CLS. La lecture automatique supprime cette protection. Le guide web.dev sur les carrousels couvre les détails d'implémentation.

SVG, confinement, et autres cas particuliers

Les SVG chargés via <img> ont besoin de width et height sur la balise, tout comme les images matricielles. Les éléments <svg> en ligne nécessitent des dimensions explicites ou une viewBox avec la propriété CSS aspect-ratio. Un SVG sans aucun des deux est par défaut à 300x150.

Pour les intégrations que vous ne pouvez pas contrôler (emplacements publicitaires, widgets tiers, contenu généré par les utilisateurs), utilisez le confinement CSS (containment) pour empêcher le décalage de se propager :

<style>
.embed-container {
    min-height: 250px;
    contain: layout style;
}
</style>

contain: layout style indique au navigateur que rien à l'intérieur de ce conteneur n'affecte la mise en page à l'extérieur. L'intégration peut se décaler, s'agrandir ou se réduire. Le reste de la page reste en place.

Pour les sections en dessous de la ligne de flottaison comportant des médias lourds, content-visibility: auto combiné avec contain-intrinsic-size ignore la mise en page pour le contenu hors écran. Sans contain-intrinsic-size, l'élément a une hauteur de zéro et l'expansion lorsque l'utilisateur scrolle jusqu'à lui crée un Layout Shift :

<style>
.below-fold-gallery {
    content-visibility: auto;
    contain-intrinsic-size: auto 500px;
}
</style>

Le mot-clé auto signifie : commencez avec 500px comme estimation, mais une fois que le navigateur l'a rendu et connaît la vraie hauteur, mémorisez cette valeur.

Comment trouver le CLS des images

Vous ne détecterez pas le CLS des images sur votre propre machine. Le cache de votre navigateur possède déjà les dimensions. Vous avez besoin des conditions d'un nouveau visiteur ou des données d'utilisateurs réels.

Real User Monitoring

Commencez avec CoreDash ou un autre outil RUM. Les données d'attribution du CLS montrent exactement quels éléments se sont décalés. Accédez simplement au CLS et regardez le tableau d'attribution Element. Il vous dira exactement quels éléments se sont décalés. Pour trouver des images, filtrez simplement par image et vous obtiendrez un tableau de tous les éléments d'image affectés par des Layout Shifts, triés par impact.

Chrome DevTools

Désactivez le cache dans l'onglet Network, limitez la connexion à Slow 4G, activez les captures d'écran, et rechargez. Observez les sauts visuels. Ensuite, ouvrez le panneau Performance et cherchez les entrées "Layout Shift". Cliquez sur un décalage pour voir le nœud, le score et s'il y a eu une interaction utilisateur récente.

Core Web Vitals Visualizer

L'extension Core Web Vitals Visualizer met en évidence chaque Layout Shift avec une superposition colorée. Je l'utilise comme première étape avant d'ouvrir le panneau Performance. Rechargez avec l'extension active et vous verrez exactement ce qui a bougé.

Lighthouse en détecte une partie

Lighthouse signale les images sans width et height. Mais il passe complètement à côté du problème width: auto car les attributs HTML sont présents. Le CSS les écrase, et Lighthouse ne vérifie pas les styles calculés. C'est pourquoi je ne fais jamais confiance à un score CLS vert sur Lighthouse sans vérifier également les données de terrain.

Liste de contrôle des correctifs rapides

Élément Cause du CLS Correctif
<img> width/height manquants Ajoutez width et height ; utilisez height: auto; max-width: 100%; en CSS
<img> Le CSS width: auto écrase les dimensions Supprimez width: auto ; gardez uniquement height: auto
<video> width/height manquants Ajoutez width et height correspondant à la résolution de la vidéo
<iframe> 300x150 par défaut aspect-ratio: 16 / 9; width: 100%; en CSS ou le pattern de façade
<picture> Ratios différents par source (bug Firefox) Définissez width/height sur chaque <source> ; ajoutez des media queries CSS de secours
<img srcset> Ratios mixtes dans srcset Même ratio pour toutes les sources ; définissez width/height sur la balise <img>
Images en lazy loading Au-dessus de la ligne de flottaison sans dimensions Supprimez loading="lazy" ; définissez toujours les dimensions
Lazy loading JS Placeholder 1x1 avec un mauvais ratio Utilisez le loading="lazy" natif ou faites correspondre le ratio du placeholder
Carrousel Lecture automatique + transitions déclenchant des recalculs de mise en page Conteneur avec aspect-ratio fixe ; transform pour les transitions
SVG Pas de dimensions intégrées Width/height sur <img> ou viewBox + aspect-ratio CSS
Emplacements publicitaires / intégrations Dimensions inconnues min-height + contain: layout style

Où en est le web concernant le CLS des images

Les chiffres du Web Almanac 2025 :

  • 62 % des pages mobiles ont au moins une image sans dimensions. En baisse par rapport à 66 % en 2024. Cela reste la majorité.
  • 65 % des pages desktop ont des images sans dimensions. En baisse par rapport à 69 %.
  • Au p75, une page desktop compte 9 images sans dimensions. Le mobile en a 8.
  • Au p90 : 25 sur desktop, 22 sur mobile.
  • Hauteur médiane des images sans dimensions : 111px sur desktop, 98px sur mobile. Assez pour décaler un paragraphe.
  • 72 % des origines desktop et 81 % des mobiles réussissent le test CLS. En hausse par rapport à 62 % en 2021.
  • 40 % des pages mobiles utilisent encore des animations non composites qui causent du CLS à elles seules.

Le CLS s'est plus amélioré que n'importe quel autre Core Web Vital au cours des quatre dernières années. Les images sans dimensions restent le contributeur principal. Corrigez ce seul problème et les Layout Shifts disparaîtront sur la plupart des sites.

Guides liés

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.


Find out what is actually slow.

I map your critical rendering path using real field data. You get a prioritized fix list, not a Lighthouse report.

Get the audit

Questions répondues sur le CLS des images et médias

Pourquoi width:auto sur les images cause-t-il un Layout Shift même lorsque les attributs width et height sont définis ?

Le ratio d'aspect interne du navigateur (calculé à partir des attributs width/height) a la priorité CSS la plus faible. width: auto l'écrase, rendant les deux dimensions inconnues. L'image est rendue à 0x0 jusqu'au téléchargement du fichier. Supprimez width: auto et gardez uniquement height: auto; max-width: 100%;.

Ai-je aussi besoin de width et height sur les éléments vidéo et iframe ?

Oui pour la vidéo. Le même mécanisme width/height fonctionne. Définissez les attributs pour qu'ils correspondent à la résolution de la vidéo, pas à l'image du poster. Les iframes sont différentes : elles ne calculent pas de ratio à partir de leurs attributs et sont par défaut à 300x150. Utilisez aspect-ratio en CSS ou le pattern de façade.

Comment puis-je prévenir le CLS lors de l'utilisation de l'élément picture avec différents ratios d'aspect par point d'arrêt ?

Définissez width et height sur chaque <source>. Chrome et Safari utilisent les dimensions correctes de la source active. Firefox a un bug (1694741) où il utilise toujours les dimensions de secours de <img>. Ajoutez des media queries CSS avec le bon aspect-ratio par point d'arrêt comme solution de contournement.

Le lazy loading cause-t-il un Layout Shift ?

Pas si l'image possède les attributs width et height. Mais le lazy loading d'images au-dessus de la ligne de flottaison retarde le LCP sans aucun bénéfice. N'utilisez jamais loading="lazy" sur les images dans le viewport initial.

Pourquoi Lighthouse affiche-t-il un bon CLS alors que mes données de terrain montrent des Layout Shifts ?

Lighthouse s'exécute sur un navigateur préchauffé avec un réseau rapide. Il ne détecte pas le problème width: auto car il vérifie les attributs HTML, pas les styles CSS calculés. Il ne teste pas non plus les décalages post-chargement causés par les publicités, les intégrations ou le contenu en lazy loading. Vérifiez toujours le CLS avec les données de terrain de CrUX ou d'un outil RUM comme CoreDash.

Comment les images et les médias provoquent un Layout Shift (et comment le corriger)Core Web Vitals Comment les images et les médias provoquent un Layout Shift (et comment le corriger)