En une phrase
Les métriques de font fallback sont des super-pouvoirs CSS qui étirent et écrasent artificiellement une police système pour qu'elle occupe exactement le même espace mathématique que votre web font custom, évitant ainsi que le layout de la page ne bouge violemment quand la police personnalisée finit par charger.
Le problème que ça règle
Pour comprendre le problème, il faut d'abord piger la plus vieille guerre typographique du web : qu'est-ce qu'on affiche à l'utilisateur pendant qu'on attend le téléchargement d'une web font de 150 Ko sur une connexion 3G capricieuse ?
Historiquement, les navigateurs adoptaient l'une de ces deux approches, et les deux étaient foireuses. La première, c'était le FOIT (Flash of Invisible Text), où le navigateur planquait tout simplement le texte jusqu'à ce que la font soit téléchargée. Les utilisateurs fixaient un écran vide, en se demandant si votre site était cassé. La seconde, le FOUT (Flash of Unstyled Text) : le navigateur faisait immédiatement le rendu du texte avec une font système locale (comme Arial ou Times New Roman), puis la swappait à l'arrache avec votre magnifique font custom à la milliseconde où elle arrivait.
La communauté du web a fini par se mettre d'accord sur le fait que le FOUT est bien meilleur pour l'accessibilité et les performances perçues. Après tout, lire un texte moche vaut mieux que de ne rien lire du tout. On a officialisé ça avec la règle CSS font-display: swap.
Mais font-display: swap a donné naissance à un nouveau monstre : le Cumulative Layout Shift (CLS).
Chaque font a un squelette unique. Un "x" en Roboto est physiquement plus large qu'un "x" en Arial. La hauteur des majuscules varie. Les espacements codés en dur dans les fichiers de font sont complètement différents. Quand le navigateur swap Arial pour Roboto, le texte prend soudainement une place horizontale et verticale différente. Les paragraphes subissent un reflow. Le texte passe à la ligne différemment.
Si ça arrive pendant que l'utilisateur lit déjà ou s'apprête à cliquer sur un bouton, toute la page saute comme si un tremblement de terre venait de frapper le DOM. Les boutons se dérobent sous le curseur. Les images sont repoussées vers le bas de la page. Google a introduit les métriques Core Web Vitals pour mesurer précisément cette frustration, pénalisant violemment le SEO des sites avec un gros CLS. Il nous fallait un moyen pour que la vilaine font système temporaire imite parfaitement l'empreinte physique de notre belle font custom.
Comment ça marche sous le capot
Pour stopper le layout shift, on ne touche pas à la web font custom. On va plutôt créer une version "Frankenstein" d'une font système locale en utilisant la règle @font-face. On utilise des descripteurs CSS spécialisés pour overrider la géométrie interne de la font système.
L'anatomie d'une Font Box
Pour manipuler une font, il faut piger comment un navigateur calcule la boîte autour d'une ligne de texte (la bounding box). Ce n'est pas qu'une question de font-size. Ça repose sur trois métriques internes cuites directement dans le fichier de la font elle-même :
- Ascent : La distance entre la baseline invisible (la ligne de base où reposent les lettres) et le sommet des caractères les plus hauts (comme le haut d'un 'h' ou d'un 'T').
- Descent : La distance entre la baseline et le bas des caractères qui pendent le plus bas (comme la queue d'un 'y', 'g' ou 'p').
- Line Gap : L'espace vide recommandé entre le descent d'une ligne et le ascent de la ligne suivante (souvent appelé "interligne" ou leading).
En CSS, la hauteur totale d'une ligne de texte est grosso modo ascent + descent + line gap. Si votre font custom et votre font système ont des valeurs différentes pour ces trois métriques, votre layout va sauter verticalement. Si les lettres n'ont pas la même largeur, votre layout va sauter horizontalement.
Place aux Overrides
Le CSS Fonts Module Level 4 a introduit quatre descripteurs magiques qu'on peut caler à l'intérieur d'un bloc @font-face. Ces descripteurs interceptent la lecture par le navigateur des métriques internes du fichier de la font et les écrasent à la volée.
size-adjust: Il agit comme un multiplicateur pour toute la font. Si votre font custom est globalement plus large qu'Arial, vous pouvez mettre unsize-adjust: 110%sur Arial pour l'étirer horizontalement.ascent-override: Écrase la métrique interne ascent de la font.descent-override: Écrase la métrique interne descent de la font.line-gap-override: Écrase la métrique interne line gap de la font.
Faire le calcul
Le piège, c'est que size-adjust redimensionne tout — y compris les largeurs horizontales, le ascent et le descent. Donc, si vous scalez une font système de 110% pour que la largeur de ses lignes matche celle de votre web font, vous venez, sans faire exprès, de rendre la hauteur verticale de la font système 110% plus grande, ce qui provoque un layout shift vertical !
Pour corriger le tir, les overrides (ascent-override, descent-override, line-gap-override) sont calculés en tant que pourcentages de la valeur de size-adjust, et non de la font size d'origine. Vous utilisez size-adjust pour faire matcher parfaitement la largeur horizontale, puis vous utilisez les métriques d'override pour, en gros, ratatiner la hauteur verticale (ou l'étirer) afin de coller à la bounding box exacte de votre font custom.
Voici à quoi ressemble le code final. Remarquez comment on crée une toute nouvelle font-family imaginaire appelée Roboto-Fallback qui englobe la font locale Arial avec des overrides mathématiquement ultra-précis :
/* 1. Load your actual web font */
@font-face {
font-family: 'Roboto';
src: url('/fonts/roboto.woff2') format('woff2');
font-display: swap;
}
/* 2. Create the Frankenstein fallback */
@font-face {
font-family: 'Roboto-Fallback';
src: local('Arial');
/* Stretch Arial horizontally to match Roboto */
size-adjust: 104.5%;
/* Squish Arial's vertical metrics to match Roboto */
ascent-override: 89.92%;
descent-override: 23.44%;
line-gap-override: 0%;
}
/* 3. Use them together in your CSS */
body {
font-family: 'Roboto', 'Roboto-Fallback', sans-serif;
}
Au chargement de la page, le navigateur fait le rendu de Roboto-Fallback instantanément. Ce n'est rien d'autre que de l'Arial local, mais étiré horizontalement et écrasé verticalement pour correspondre à l'empreinte mathématique exacte de Roboto. Quand le vrai fichier Roboto finit de télécharger, le swap s'opère, le design des lettres change, mais le layout ne bouge pas d'un seul pixel.
Histoires du terrain
Le piège du bouton "Annuler"
Une grosse plateforme e-commerce galérait avec des abandons de panier et des tickets de support client furieux. Les utilisateurs se plaignaient de vider leur panier par accident. L'équipe technique a enregistré des sessions utilisateurs et a trouvé le coupable. Le site chargeait une font de marque bien lourde. Un utilisateur voyait le bouton "Commander" juste à côté du bouton "Vider le panier". Pile au moment où il cliquait sur "Commander", la font custom finissait de charger. Cette font était beaucoup plus large que la police par défaut du système. Le texte faisait un reflow, poussant le bouton "Commander" vers la droite, et positionnant le bouton "Vider le panier" exactement sous le clic de souris descendant de l'utilisateur. L'implémentation de size-adjust et des metric overrides a verrouillé la position des boutons pendant le swap de font, faisant instantanément chuter le taux d'annulations accidentelles.
Le séisme de l'article de presse
Un célèbre blog tech a fait une refonte massive, incluant une magnifique font serif moderne pour les longs articles. Pour prioriser la vitesse, ils ont utilisé font-display: swap. Sauf que les lecteurs avec une petite connexion ont subi un phénomène super frustrant : ils chargeaient un article, scrollaient de trois paragraphes, et commençaient à lire. Deux secondes plus tard, la font serif popait. Parce que cette font avait un ascent et un descent plus grands que le défaut du système, absolument chaque ligne de texte grandissait d'une fraction de millimètre. Sur l'espace de trois paragraphes, ça se cumulait pour créer un énorme shift vertical, éjectant carrément de l'écran la phrase que l'utilisateur était en train de lire. En ajoutant un ascent-override et un descent-override à une fallback font locale, le texte a swappé parfaitement sur place, gardant l'œil du lecteur exactement au bon endroit.
La désillusion du score Lighthouse
Un dev front a passé trois semaines à optimiser une web app pour les Core Web Vitals de Google. Il a compressé les images en WebP, mis un defer sur le JavaScript non-critique, et minifié le CSS. Il a lancé Google Lighthouse, confiant de taper le sacro-saint score de 100. Au lieu de ça, il s'est pris un 75. Le rapport a pointé une énorme pénalité de Cumulative Layout Shift. Tout le shift venait d'un seul titre <H1> qui passait d'une ligne à deux au moment du chargement de la web font custom. Au lieu de refaire le design du header ou de se rabattre sur du texte invisible, le dev a généré les fallback metrics exactes pour la font du titre. Le layout shift est tombé à zéro, le score Lighthouse a atteint 100, et le développeur a enfin pu aller dormir.
Erreurs courantes et pièges
- Deviner les pourcentages au pif : Vous ne pouvez pas trouver ces nombres à l'œil. Les calculs nécessitent d'extraire exactement les données UPM (Units Per Em), ascent, descent et line gap directement depuis les tables binaires intégrées aux fichiers de la web font et de la font système, et de faire des produits en croix. Utilisez toujours un générateur programmatique pour ne pas vous rater sur les maths.
- Appliquer les overrides sur la web font : Un piège classique est de coller
size-adjustdirectement dans la déclaration@font-facede la web font custom. Ça ne sert strictement à rien. Les overrides doivent être appliqués à une déclaration@font-facecomplètement séparée qui charge une font systèmelocal(), que vous placez ensuite en deuxième position dans votre stackfont-family. - Choisir des fallbacks structurellement opposées : Les métriques de font ne font pas non plus des miracles. Si votre font custom est une sans-serif ultra-condensée, et que vous utilisez une font serif bien large comme base de fallback locale, les maths du
size-adjustrendront la font serif complètement déformée et illisible en attendant le swap. Choisissez toujours une font système locale dont la structure osseuse ressemble vaguement à celle de votre web font. - Oublier le
line-gap-override: Les devs se focalisent souvent à 100% sur la largeur et la hauteur en pensant que laisser le line gap ennormalou l'omettre fera l'affaire. Si le navigateur décide d'ajouter un leading par défaut à la font fallback qui ne matche pas parfaitement le leading interne de la web font, votre rythme vertical va sauter. Définissez-le toujours explicitement.
Pourquoi ça doit être sur votre radar
Vous devriez penser aux métriques de font fallback dès l'instant où vous décidez d'utiliser une web font custom sur un projet où l'expérience utilisateur et le SEO ont de l'importance.
Historiquement, la typographie sur le web était un compromis entre l'esthétique (utiliser de belles fonts) et les performances (éviter les layouts qui sautent). Avec l'arrivée des font metrics en CSS, ce compromis est mort. Dès que vous auditez les Core Web Vitals d'un site, que vous vous battez avec un gros score CLS, ou que vous construisez des composants UI réutilisables qui ne peuvent pas se permettre de trembler à l'écran, les font fallback overrides sont la solution d'ingénierie définitive. Ça transforme les web fonts : d'un point faible au chargement, elles deviennent une transition fluide et totalement imperceptible.
Pour aller plus loin
- MDN Web Docs: size-adjust - La doc officielle de Mozilla qui explique comment le descripteur size-adjust met à l'échelle le tracé des glyphes et les métriques.
- MDN Web Docs: ascent-override - Plongée en profondeur sur la façon d'overrider la métrique ascent de la font.
- web.dev: Improved font fallbacks - L'excellent guide de Google sur l'utilisation de ces fameux descripteurs CSS pour régler le Cumulative Layout Shift.
- W3C CSS Fonts Module Level 4 - La spécification officielle qui détaille la formule mathématique exacte et les règles de rendu des navigateurs pour les overrides de font metrics.