Développement Web

Optimiser le CLS : une page qui ne saute plus

12 دقائق للقراءة

Un visiteur de la coopérative Niani s’apprête à toucher le bouton « Voir le panier ». À cet instant précis, la bannière promotionnelle « Livraison offerte » finit de charger en haut de page, pousse tout le contenu vers le bas, et le doigt tombe sur « Supprimer l’article ». Cette frustration porte un nom : le décalage de mise en page, mesuré par le Cumulative Layout Shift. Contrairement au LCP ou à l’INP, le CLS ne parle pas de vitesse mais de stabilité : est-ce que votre page reste sage pendant qu’elle se charge, ou est-ce qu’elle saute sous les yeux de l’utilisateur ? Ce tutoriel vous apprend à la stabiliser, sous le seuil de 0,1.

📍 Guide principal : Core Web Vitals et performance web : le guide — la vue d’ensemble des trois métriques.

🎯 Ce que vous allez apprendre

  • Comprendre comment se calcule le CLS et pourquoi un décalage « inattendu » est pénalisé.
  • Réserver l’espace des images et vidéos avec width, height et aspect-ratio.
  • Stabiliser les contenus injectés tardivement : bannières, encarts, publicités.
  • Empêcher les polices personnalisées de faire sauter votre texte.
  • Repérer l’élément qui décale avec les outils de développement et web-vitals.

🛠️ Ce que vous allez construire

Vous partez de la page d’accueil de Niani qui sursaute trois fois pendant son chargement — la bannière, la grille de produits et le bandeau promotionnel se bousculent — et vous la rendez parfaitement stable. Le contenu apparaît à sa place définitive du premier coup, sans jamais repousser ce que l’utilisateur regarde déjà.

Prérequis

  • Des bases en HTML et CSS (balises d’image, propriétés de mise en page).
  • Savoir ouvrir l’onglet Performance des outils de développement — voir Mesurer la performance web.
  • Accès au code de votre page et de ses styles.
  • Niveau : débutant à intermédiaire. Si vous savez écrire une règle CSS, vous suivrez.
  • ⏱️ Temps estimé : ~40 minutes.

Étape 1 — Comprendre comment se calcule le CLS

Le CLS additionne les scores de tous les décalages inattendus qui surviennent pendant la vie de la page. Le mot « inattendu » est central : un décalage provoqué par l’utilisateur lui-même — il clique sur « Voir plus » et le contenu s’agrandit — n’est pas compté. Seuls les décalages que l’utilisateur n’a pas demandés pénalisent le score.

Chaque décalage reçoit un score qui combine deux facteurs : la fraction d’impact (quelle proportion de l’écran a bougé) et la fraction de distance (de combien elle a bougé). Un gros bloc qui se déplace beaucoup pèse lourd ; un petit élément qui glisse de quelques pixels, presque rien. Ces scores sont regroupés en fenêtres de session, et c’est la pire rafale qui définit le CLS final.

Les seuils, au 75ᵉ centile : le CLS est bon à 0,1 ou moins, à améliorer entre 0,1 et 0,25, médiocre au-delà. Contrairement au LCP en secondes ou à l’INP en millisecondes, le CLS est un nombre sans unité — un indice de turbulence visuelle.

Point d’étape — Vous savez que le CLS additionne les décalages inattendus et vise 0,1. Un décalage déclenché par un clic de l’utilisateur ne compte pas.

Étape 2 — Repérer les éléments qui décalent

Avant de corriger, il faut voir les décalages, car à l’œil nu ils passent souvent inaperçus tant ils sont rapides. Les outils de développement les rendent visibles. Ouvrez l’onglet Performance, enregistrez un chargement, et cherchez la piste Expérience : chaque marqueur Layout Shift indique un décalage, et en le sélectionnant, Chrome surligne l’élément fautif et affiche son score.

Pour vos vrais utilisateurs, la bibliothèque web-vitals en version d’attribution pointe l’élément qui a le plus contribué au CLS.

import { onCLS } from 'https://unpkg.com/web-vitals@5/attribution?module';

onCLS(function (metric) {
  // attribution.largestShiftTarget = le selecteur de l'element fautif
  console.log('CLS', metric.value, metric.attribution.largestShiftTarget);
});

Sur la page Niani, cette inspection révèle trois coupables récurrents : la bannière hero sans dimensions, les images de produits qui s’insèrent sans réserver leur place, et le bandeau promotionnel ajouté en haut après le chargement. Traitons-les un par un.

Point d’étape — Vous avez la liste de vos éléments qui décalent, classés par score. Attaquez le plus gros en premier.

Étape 3 — Réserver l’espace des images

La cause numéro un de CLS est l’image sans dimensions. Quand le navigateur rencontre une balise <img> sans largeur ni hauteur, il ne sait pas combien de place lui réserver : il affiche d’abord le texte, puis, quand l’image arrive, il l’insère et repousse tout ce qui suit. D’où le saut.

La solution est de toujours fournir les attributs width et height. Le navigateur en déduit le rapport d’aspect et réserve la place exacte avant même de télécharger l’image. Côté CSS, on laisse l’image rester responsive avec height: auto.

<img src="/img/panier.avif" alt="Panier tressé"
     width="400" height="300">
/* L'image reste fluide tout en gardant le rapport reserve */
img {
  max-width: 100%;
  height: auto;
}

Pour les contenus dont on ne connaît pas la taille exacte à l’avance — une vidéo intégrée, une carte, un cadre externe — on réserve la place avec la propriété CSS aspect-ratio, qui fige le rapport hauteur/largeur du conteneur.

.video-integree {
  aspect-ratio: 16 / 9;
  width: 100%;
}

Après ce changement, rechargez et observez : le texte n’est plus repoussé quand les images arrivent, car leur emplacement était déjà réservé. Sur une grille de produits, l’effet est spectaculaire.

Point d’étape — Toutes vos images et vidéos ont des dimensions réservées. Le marqueur de décalage lié aux images doit disparaître de la trace.

Étape 4 — Stabiliser les contenus injectés tardivement

Le deuxième grand coupable est le contenu ajouté après coup : un bandeau promotionnel, un encart de consentement aux cookies, une notification. S’il s’insère au-dessus d’un contenu déjà visible, il pousse tout vers le bas — exactement le scénario du doigt qui rate son bouton.

Deux principes règlent le problème. Le premier : réserver l’espace à l’avance. Si vous savez qu’un bandeau de 60 pixels de haut va apparaître, réservez ce bloc dès le départ avec une hauteur minimale, quitte à le laisser vide un instant.

/* L'emplacement du bandeau est reserve des le depart */
.bandeau-promo {
  min-height: 60px;
}

Le second principe : superposer plutôt qu’insérer. Un encart de consentement ou une notification gagne à flotter au-dessus de la page (en position fixe ou absolue) plutôt qu’à s’intercaler dans le flux. Il recouvre alors le contenu sans le déplacer, et le CLS reste nul. La règle générale tient en une phrase : ne jamais insérer de contenu au-dessus d’un contenu existant, sauf en réponse à une action de l’utilisateur.

Point d’étape — Vos bannières et encarts ont leur espace réservé ou flottent au-dessus de la page. Plus de saut à leur apparition.

Étape 5 — Empêcher les polices de faire sauter le texte

Une cause plus subtile de CLS vient des polices personnalisées. Le navigateur affiche d’abord le texte avec une police de secours, puis le remplace par votre police une fois chargée. Si les deux polices n’ont pas les mêmes proportions, le texte se réorganise — les lignes se décalent, et le score grimpe.

La parade tient en deux gestes. D’abord, précharger la police critique pour qu’elle arrive tôt. Ensuite, ajuster les métriques de la police de secours pour qu’elle occupe le même espace que la police finale, grâce à size-adjust et aux propriétés d’override dans la déclaration @font-face. Le remplacement devient alors invisible : aucun décalage.

@font-face {
  font-family: 'Secours ajustee';
  src: local('Arial');
  size-adjust: 105%;
  ascent-override: 95%;
}

Le réglage fin du chargement des polices — formats, préchargement, font-display — fait l’objet du tutoriel Optimiser les images et les polices. Pour le CLS, retenez le principe : faire en sorte que la police de secours et la police finale occupent exactement la même place.

Point d’étape — Le remplacement de votre police ne provoque plus de réorganisation du texte. Le décalage lié à la police a disparu de la trace.

Étape 6 — Animer sans décaler

Dernier réflexe, souvent oublié : certaines animations provoquent elles-mêmes du CLS. Animer la position d’un élément en modifiant top, left, width ou height déclenche un recalcul de mise en page à chaque image — et peut décaler les voisins. La bonne pratique est d’animer avec transform, qui déplace l’élément sur une couche séparée sans toucher au flux.

/* A eviter : anime la mise en page, peut decaler */
.carte:hover { margin-top: -8px; }

/* A preferer : anime sans toucher au flux */
.carte:hover { transform: translateY(-8px); }

Le second exemple soulève la carte au survol sans déplacer quoi que ce soit autour d’elle. C’est la même logique que pour l’INP : transform s’exécute hors du fil de mise en page, donc il est à la fois plus fluide et plus stable.

Point d’étape — Vos animations utilisent transform et n’engendrent plus de décalage. Le CLS de la page devrait viser le vert.

Étape 7 — Vérification finale

Rechargez la page plusieurs fois en mode Mobile, onglet Performance ouvert : la piste Expérience ne doit plus afficher de décalage significatif, et le CLS de laboratoire doit tomber sous 0,1. Pensez à tester aussi en faisant défiler immédiatement, car certains décalages ne surviennent qu’après le premier rendu. Si vous avez du trafic, surveillez le 75ᵉ centile du CLS sur le terrain via PageSpeed Insights.

La page d’accueil de Niani est désormais stable : la bannière, la grille et le bandeau apparaissent chacun à leur place réservée, sans bousculer le reste. Plus de doigt qui rate son bouton, plus de lecture interrompue par un saut. Vous avez complété les trois métriques — vitesse d’affichage, réactivité, stabilité — et il vous reste à attaquer les deux grandes sources de poids : les images et polices, puis le JavaScript.

🐞 Pièges fréquents

Symptôme Cause probable Correctif
Le texte saute quand les images arrivent Images sans width ni height Ajouter les dimensions sur chaque image et height: auto en CSS
Toute la page descend après une seconde Bandeau ou encart injecté au-dessus du contenu Réserver l’espace avec min-height ou faire flotter l’élément au-dessus
Les titres se réorganisent au chargement Police personnalisée aux proportions différentes de la secours Précharger la police et ajuster la secours avec size-adjust
CLS bon au chargement, mauvais ensuite Décalage déclenché au défilement (image différée, contenu paresseux) Réserver aussi l’espace des contenus chargés plus bas

🌍 Réalités du terrain

Sur les connexions lentes fréquentes en Afrique de l’Ouest, le CLS est paradoxalement plus visible que sur la fibre : comme les ressources arrivent en ordre dispersé et avec du retard, chaque image ou police tardive provoque son petit saut, bien après que l’utilisateur a commencé à lire. Une page qui semble stable sur votre connexion rapide peut sauter trois fois sur une 3G à Kankan ou Parakou.

Le bon réflexe est de tester avec le bridage « Slow 4G » activé : les décalages se déploient au ralenti, et vous les voyez tous. Réserver l’espace des images et des bannières ne coûte presque rien à mettre en place et reste l’une des optimisations au meilleur rapport effort/résultat de toute la performance web — d’autant qu’elle protège directement vos utilisateurs des clics malheureux sur un catalogue marchand.

✅ Récapitulatif

Vous savez maintenant stabiliser une page : comprendre que le CLS additionne les décalages inattendus, les repérer dans les outils, puis les éliminer — réserver l’espace des images et vidéos, gérer les contenus injectés sans pousser le reste, neutraliser le saut des polices, et animer avec transform. La stabilité visuelle est souvent la métrique la plus simple à corriger une fois qu’on en connaît les quatre causes.

🧾 Aide-mémoire

Élément Rôle
width + height sur les images Réserver la place avant le téléchargement
aspect-ratio Réserver la place des cadres et vidéos
min-height sur les bandeaux Anticiper l’espace d’un contenu injecté
Superposer plutôt qu’insérer Afficher encarts et notifications sans pousser le contenu
size-adjust / ascent-override Éviter le saut au remplacement de police
transform pour les animations Bouger sans décaler le flux
Cible CLS ≤ 0,1 au 75ᵉ centile

💪 À vous de jouer

Retirez les attributs width et height d’une image de votre page, rechargez avec le bridage « Slow 4G », et observez le décalage dans l’onglet Performance. Puis remettez les dimensions et constatez la différence de score.

Voir une piste de solution

Sans dimensions, une seule grande image peut à elle seule faire passer le CLS de 0 à 0,2 ou plus, car elle repousse tout le contenu situé en dessous au moment où elle se charge. En rétablissant width et height, le navigateur réserve la place et le décalage tombe à zéro pour cette image. Multipliez par le nombre d’images d’une grille de produits, et vous comprenez pourquoi c’est la première correction à faire.

Dans la même série

Pour aller plus loin

FAQ

Un menu qui s’ouvre au clic dégrade-t-il mon CLS ?
Non. Les décalages provoqués par une action de l’utilisateur dans la demi-seconde qui suit ne sont pas comptés. Le CLS ne pénalise que les mouvements inattendus, ceux que l’utilisateur n’a pas déclenchés.

Dois-je mettre des dimensions même si mon image est responsive ?
Oui, et c’est compatible. Indiquez width et height dans le HTML (le navigateur en déduit le rapport d’aspect) et laissez height: auto en CSS pour la fluidité. L’image s’adapte tout en réservant sa place.

Pourquoi mon CLS est-il pire sur mobile ?
Souvent à cause des bannières et de la réorganisation du texte sur un écran étroit, où le moindre élément injecté pousse plus de contenu. Testez toujours en mode Mobile avec bridage réseau pour voir le CLS tel que vos visiteurs le subissent.

مشاركة