CLS
Définition
Cumulative Layout Shift. Mesure des décalages visuels imprévus pendant le chargement de la page. Objectif : sous 0,1. Souvent dégradé par des images sans dimensions ou des polices mal chargées.
Ce que CLS mesure
CLS (Cumulative Layout Shift) mesure les décalages visuels imprévus pendant la durée de vie de la page : un bouton qui se déplace au moment où on allait cliquer, une image qui s'insère et pousse le contenu vers le bas, une bannière de consentement qui surgit, un widget tiers qui apparaît en retard. Tout déplacement non initié par l'utilisateur compte. La métrique additionne ces décalages pondérés par leur ampleur et la surface affectée. Plus la page bouge, plus le score grimpe. Une mise en page stable depuis le premier rendu jusqu'à la fin de la session vise zéro.
Les seuils Google
Sous 0,1, le CLS est considéré comme bon. Entre 0,1 et 0,25, à améliorer. Au-delà de 0,25, mauvais. Comme pour les autres Core Web Vitals, le ranking se base sur le 75e percentile en field data. Un CLS à 0,5 sur mobile est rarement supportable côté expérience : l'utilisateur clique sur le mauvais bouton, abandonne le formulaire, ou désinstalle votre app. Sur les sites e-commerce, un CLS élevé corrèle directement avec une chute du taux d'ajout au panier. Le critère SEO n'est qu'un effet secondaire d'un problème UX réel.
Les coupables habituels
Premier coupable : les images sans attributs width et height, qui forcent le navigateur à recalculer la mise en page une fois l'image téléchargée. Deuxième coupable : les polices web qui changent la métrique du texte au chargement (FOIT, FOUT). Troisième coupable : les contenus injectés au-dessus du fold après le rendu initial (publicités, embeds, widgets). Quatrième coupable : les bannières de consentement RGPD ou cookies qui décalent le contenu au bout de quelques centaines de millisecondes. Cinquième coupable : les animations qui démarrent en modifiant la position d'éléments existants. Identifier le bon coupable est l'étape clé.
Diagnostiquer un mauvais CLS
Chrome DevTools affiche les Layout Shifts dans l'onglet Performance avec une visualisation des zones décalées. Web Vitals Extension donne le CLS en temps réel pendant la navigation. PageSpeed Insights identifie les éléments problématiques sur une URL donnée. Sur le terrain, un RUM segmente le CLS par page, parcours et appareil. Sur un site avec beaucoup de contenu dynamique, mesurer en mobile sur connexion lente révèle des décalages invisibles en local. Le diagnostic en réel précède toujours la correction : on évite de réparer des problèmes qui n'existaient que dans Lighthouse.
Les correctifs efficaces
Sur les images, on impose toujours width et height ou aspect-ratio en CSS. Sur les fonts, on précharge les .woff2 critiques et on utilise font-display swap avec un fallback métrique proche (size-adjust, ascent-override). Sur les contenus dynamiques au-dessus du fold, on pré-réserve l'espace via min-height ou un skeleton placeholder. Sur les bannières de consentement, on les ancre en bas ou en overlay sans pousser le contenu. Sur les animations, on utilise transform et opacity qui ne déclenchent pas de layout, plutôt que top, left ou margin. Ces six réflexes éliminent 90% des CLS.
L'avantage Next.js
next/image impose des dimensions explicites par défaut : impossible d'oublier width et height, ce qui élimine le coupable numéro un. next/font précharge les fonts et applique automatiquement les bons fallbacks métriques, supprimant les décalages liés au FOUT. Le rendu SSR ou SSG livre du HTML complet, donc moins de contenu à insérer après le premier rendu. Combiné à une discipline d'aspect-ratio sur les iframes et embeds, on tient un CLS sous 0,05 sur un site complexe. C'est l'une des raisons pour lesquelles on évite WordPress sur les sites où la performance compte vraiment.
Les pièges peu connus
Les A/B tests asynchrones qui changent le contenu après chargement génèrent un CLS énorme : on les fait côté serveur (Edge Config, Middleware) ou avant le premier rendu. Les iframes sans dimensions (vidéos YouTube, Calendly, etc.) bougent quand leur contenu charge : on impose aspect-ratio sur le conteneur. Les transitions hover sur mobile (où il n'y a pas de hover) peuvent décaler au tap : on réserve via :focus-visible ou des keyframes propres. Le lazy-loading agressif des sections intermédiaires fait sauter le scroll au chargement : on garde le lazy au-dessus du fold uniquement.