Diagnostiquer un CLS élevé causé par une police web

Un score CLS (Cumulative Layout Shift) supérieur à 0,1 dégrade le classement SEO et l'expérience utilisateur. Dans une stack Next.js déployée sur Vercel, les polices web sont une cause fréquente de ce problème, souvent invisible en développement local mais flagrante en production sous charge réseau réelle.

Comprendre le mécanisme du décalage

Le CLS lié aux polices survient dans deux scénarios distincts :

FOUT (Flash of Unstyled Text) : le navigateur affiche d'abord une police système, puis la remplace par la police web une fois chargée. Si les métriques de fallback (line-height, largeur des glyphes) diffèrent de la police finale, le texte se redimensionne et déplace les éléments environnants.

FOIT (Flash of Invisible Text) : le texte reste invisible jusqu'au chargement complet de la police, puis apparaît brutalement. Sans décalage visuel direct, mais souvent combiné à un layout shift si la police occupe un espace différent une fois rendue.

Le calcul du CLS pénalise tout déplacement d'éléments visibles entre deux frames rendus. Une police avec un x-height ou une largeur moyenne de caractère différente de son fallback peut décaler un bloc de texte de plusieurs dizaines de pixels, surtout sur des titres ou des paragraphes longs.

Isoler la police responsable avec les DevTools

Ouvrez l'onglet Performance de Chrome DevTools et enregistrez un chargement de page en simulant une connexion "Fast 3G" (Network throttling). Repérez les entrées Layout Shift dans la timeline. Chaque entrée expose :

  • value : le score de décalage
  • sources : les nœuds DOM affectés avec leurs rectangles avant/après

Cliquez sur une source pour identifier l'élément précis. Si l'élément contient du texte et que le décalage coïncide temporellement avec une requête réseau vers un fichier .woff2, la police est la cause probable.

Confirmez avec l'API PerformanceObserver directement en console :

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('CLS entry:', entry.value, entry.sources);
  }
}).observe({ type: 'layout-shift', buffered: true });

Croisez ensuite avec l'onglet Network : filtrez par type Font et vérifiez le timing de la requête par rapport aux entrées de layout shift relevées. Un décalage temporel de quelques centaines de millisecondes entre la fin du téléchargement de la police et l'entrée layout-shift confirme la corrélation.

Vérifier la stratégie font-display et les métriques de fallback

Inspectez le CSS généré (@font-face) dans l'onglet Elements > Computed ou directement dans le fichier source. L'absence de font-display: swap ou optional force souvent un FOIT prolongé, mais ce n'est pas la cause du CLS en soi — le vrai problème est l'écart de métriques entre la police web et son fallback.

Comparez les valeurs suivantes entre la police cible et la police de secours (Arial, system-ui) :

  • ascent-override
  • descent-override
  • line-gap-override
  • size-adjust

Ces descripteurs, supportés nativement dans les navigateurs modernes, permettent d'ajuster les métriques du fallback pour qu'il occupe exactement le même espace que la police finale. Sans eux, un fallback avec un x-height plus petit affichera un texte plus compact, puis le layout "sautera" à l'arrivée de la police définitive.

Corriger avec next/font

Sur Next.js, la solution native passe par next/font, qui génère automatiquement les métriques de fallback et auto-héberge les polices pour éliminer la latence réseau externe :

import { Inter } from 'next/font/google';

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  fallback: ['system-ui', 'arial'],
  adjustFontFallback: true,
});

adjustFontFallback: true (activé par défaut) calcule automatiquement ascent-override, descent-override et size-adjust pour aligner le fallback sur la police cible. Vérifiez le résultat dans le CSS généré par le build — Next.js injecte une police @font-face locale nommée avec un suffixe Fallback.

Pour les polices auto-hébergées hors Google Fonts, utilisez next/font/local avec les mêmes options.

Valider en production avec le monitoring réel

Le comportement en local (cache navigateur chaud, réseau rapide) masque souvent le problème. Déployez sur un environnement preview Vercel et activez **V

Le Template Puppeteer B2B, gratuit

Un script d'automatisation prêt à l'emploi pour vos scrapers et générateurs de PDF B2B. Envoyé par e-mail, sans spam.

Partenaire

Hébergez vos APIs sur une infrastructure rapide

Hostinger propose un hébergement cloud et VPS haute performance avec NVMe, CDN intégré et déploiement Git — idéal pour vos back-ends et APIs JSON.