Documentation
Comment fonctionne No More Font Shift, pourquoi il a été créé, et le guide complet de chaque paramètre.
Le problème CLS causé par les polices
Le Cumulative Layout Shift (CLS) est l'une des métriques Core Web Vitals de Google. Elle mesure les décalages visuels inattendus qui se produisent lors du chargement d'une page. Un CLS élevé nuit à l'expérience utilisateur et peut pénaliser le référencement naturel.
L'une des causes les plus courantes et les plus insidieuses de CLS est le chargement des polices web. Voici ce qui se passe :
- Le navigateur affiche d'abord le texte avec une police système de repli (Arial, Georgia, etc.).
- La police web personnalisée (Poppins, Inter, Playfair Display…) se charge.
- Le navigateur remplace la police de repli par la police définitive.
- Comme les deux polices ont des métriques différentes (largeur des caractères, hauteur de ligne, espacement…), le texte se recalcule et la mise en page saute.
Ce saut est mesuré comme du CLS, même si les utilisateurs ne le remarquent pas forcément à l'œil nu. Lighthouse et Google Search Console le détectent.
Le wizard en 6 étapes
Le configurateur est organisé comme un assistant guidé. Vous ne pouvez avancer qu'après avoir validé les pré-requis de chaque étape, mais vous pouvez revenir librement sur une étape déjà franchie.
- Fichier — uploadez votre police (drag-drop ou clic). Le format
.woff2est conseillé. Le nom de la police est auto-détecté via la table OpenTypenamedu fichier (TTF, OTF, WOFF). Pour WOFF2 (compression Brotli), on retombe sur le nom du fichier. - Nom & stack — confirmez le nom auto-détecté et choisissez le stack de repli adapté (Sans ou Serif).
- Fallback 1 — calibrez les 4 métriques pour la première police de repli (Arial ou Times New Roman selon le stack choisi).
- Fallback 2 — même chose pour la police présente sur Android (Roboto ou Noto Serif).
- Test A/B — simulez le chargement réel de la police pour visualiser et mesurer le saut de mise en page (CLS) avec et sans votre fallback ajusté.
- CSS — copiez ou téléchargez le CSS final, et enregistrez-le dans la base si vous êtes connecté.
Pour les visiteurs anonymes consultant une police déjà enregistrée, seules les étapes 3 à 6 sont accessibles (le fichier et le nom sont verrouillés). Les éditeurs et administrateurs ont accès à toutes les étapes.
Guide de l'interface
Stack de repli
Choisissez le groupe de polices système à utiliser comme repli :
- Sans-Serif — Arial + Roboto : pour les polices sans empattement (Inter, Poppins, Open Sans, Nunito…).
- Serif — Times New Roman + Noto Serif : pour les polices avec empattement (Playfair Display, Lora, Merriweather…).
Chaque stack génère deux déclarations @font-face — une par police système — mais elles portent le même nom de famille et n'ajoutent donc qu'une seule entrée dans la stack font-family finale (voir « Une seule famille, deux @font-face » ci-dessous).
Pourquoi Arial et Roboto ?
Arial est disponible sur pratiquement tous les systèmes : Windows depuis 1992, macOS, iOS et la grande majorité des distributions Linux. C'est la police sans-serif la plus universellement présente sur desktop et iOS.
Roboto est la police système par défaut d'Android depuis la version 4.0 (Ice Cream Sandwich, 2011) — Arial n'étant pas disponible sur Android. Attention toutefois : seule la famille sans-serif est servie par Roboto. Sur le stack Serif, Android sert NotoSerif-Regular.ttf ; « Roboto Serif » n'existe pas sur le système, c'est pourquoi le repli serif cible Noto Serif.
Ce choix est directement lié aux Core Web Vitals mesurés par Google via le CrUX (Chrome User Experience Report). CrUX collecte les données de performance réelles des utilisateurs Chrome dans le monde entier. Or, Android représente environ 70 % du trafic mobile mondial. Si votre police de repli n'est pas calibrée pour Roboto, vos scores CLS dans CrUX seront dégradés sur la majorité du trafic mobile — ce qui affecte directement votre référencement Google.
En ciblant à la fois Arial (desktop + iOS) et Roboto (Android), vous couvrez l'essentiel du parc mondial et garantissez de bons scores CLS dans les données réelles de Google.
Une seule famille, deux @font-face
Les deux replis calibrés ne produisent pas deux familles CSS, mais une seule, déclarée par deux règles @font-face distinctes. La stack finale ne contient donc qu'un seul nom de repli.
Pourquoi. Les CMS — WordPress et GeneratePress notamment, mais le cas est général — enregistrent la chaîne font-family elle-même comme valeur d'option. Y ajouter un nom de famille invalide toutes les valeurs déjà enregistrées : la police ne se charge plus du tout. C'est une panne franche, pas une dégradation progressive.
L'ordre est significatif. Quand les deux polices système sont présentes, c'est la dernière face déclarée qui l'emporte. Le repli desktop (Arial / Times New Roman) est donc écrit en dernier : le rendu desktop reste identique, et le repli Android ne sert que là où la police desktop est absente. Si vous réorganisez ce CSS, conservez cet ordre.
Une face en échec ne casse pas les autres. C'est le point qui rend ce montage possible, et il n'est pas évident. Sur Android, local('Arial') ne résout pas — mais cette règle-là est simplement ignorée, et la face précédente reste disponible. La spécification CSS Fonts 4 est explicite : si toutes les alternatives de src échouent, la règle ne fournit aucune face, mais les autres règles définissant la même famille restent valides. Vérifié sur Blink, Gecko et WebKit.
Ne fusionnez jamais les deux règles. Écrire src: local('Arial'), local('Roboto') dans une règle unique donne un seul jeu de métriques pour deux polices différentes : sur Android, vous obtiendriez Roboto rendue avec les métriques d'Arial.
Précision technique : substituts métriques pour Arial et Times New Roman
Arial et Times New Roman sont des fontes propriétaires Microsoft, distribuées sous licence avec Windows et incluses dans macOS et iOS pour des raisons historiques. Nous n'avons pas le droit de les redistribuer dans cet outil. Sur les systèmes Linux sans le paquet msttcorefonts (la majorité), ces deux fontes sont tout simplement absentes.
Pour que l'aperçu et le test A/B fonctionnent correctement sur ces systèmes, nous embarquons leurs équivalents libres (Apache 2.0) conçus par Google pour être métriquement identiques aux originaux :
| Fonte propriétaire | Substitut bundlé |
|---|---|
| Arial | Arimo (/fonts/arimo/Arimo-Regular.woff2) |
| Times New Roman | Tinos (/fonts/tinos/Tinos-Regular.woff2) |
Caractéristiques de l'équivalence métrique :
- Largeur de chaque glyphe : identique au pixel près
- Hauteur de ligne intrinsèque, ascent, descent : identiques
- Retours à la ligne d'un paragraphe : identiques
- Forme des lettres : subtilement différentes (un graphiste verra les variations sur les "a", "e", "g", "R", empattements, terminaisons)
Concrètement, le CSS injecté pour l'aperçu fait par exemple :
src: local('Arial'), url('/fonts/arimo/Arimo-Regular.woff2') format('woff2');
→ Les utilisateurs avec la fonte originale localement (Windows, macOS, iOS) chargent leur vraie fonte. Les utilisateurs sans (Linux desktop, navigateurs avec polices restreintes) chargent silencieusement notre substitut, qui a exactement les mêmes métriques.
Le CSS exporté pour votre site contient uniquement les local() — on n'inclut pas les URLs Arimo/Tinos. Sur les sites de vos visiteurs, l'écrasante majorité a Arial / Times New Roman (Windows, macOS, iOS), et les utilisateurs Android passent par le second repli Roboto (ou Noto Serif). Vous n'avez donc aucun fichier additionnel à embarquer.
Pour la calibration des métriques (objet de cet outil), les paires produisent numériquement les mêmes valeurs de size-adjust, ascent-override, etc. Le résultat de votre tuning est valide indifféremment contre l'original ou le substitut.
Pourquoi il n'y a plus de stack Condensed
Un troisième stack (Impact + Roboto Condensed) a existé, puis a été retiré : aucun de ses deux replis ne résolvait sur Android. Impact en est absent, et depuis Android 12 la variante condensée de Roboto n'est plus un fichier de police mais une instance de fonte variable — donc introuvable par local(), qui n'apparie que sur le nom complet et le nom PostScript des fichiers. Ce stack n'offrait donc aucune protection sur Android.
Pour une police condensée, choisissez le stack Sans-Serif : size-adjust absorbe la différence de chasse. L'objectif est la correspondance métrique, pas la ressemblance visuelle — un repli n'est jamais vu plus de quelques centaines de millisecondes.
Texte de prévisualisation
Sept types de contenus prédéfinis couvrent les cas d'usage les plus courants :
- Paragraphes : texte courant en prose. Représente ~80 % du contenu réel d'un site. C'est le cas le plus important à calibrer en premier.
- Majuscules : révèle les différences de hauteur de capitale entre les polices.
- Gras & italique : le navigateur synthétise le gras à partir du repli Regular, ce qui produit des métriques différentes. Important si votre mise en page contient du texte en gras dans la zone de premier écran.
- Liste à puces : les différences de hauteur de ligne s'accumulent. Une liste de 10 items avec 1 px de différence par ligne = 10 px de décalage total.
- Titres h2/h3 : les titres sont souvent en tête de contenu, chargés en premier. Un h2 de grande taille amplifie visuellement toute différence.
- Tableau : le cas le plus complexe. Chaque cellule est un conteneur indépendant dont la hauteur est calculée séparément.
- Couverture glyphique : chaque caractère répété 30 fois. Permet de repérer des glyphes individuels qui se comportent différemment.
- Personnalisé : saisissez votre propre texte ou HTML pour tester avec votre contenu réel. Sauvegardé en localStorage.
size-adjust 0 % – 200 %, défaut : 100 %
Le paramètre le plus impactant. Il met à l'échelle l'ensemble des glyphes de la police de repli de façon proportionnelle, modifiant ainsi la largeur des caractères et donc les retours à la ligne.
Comment l'utiliser : commencez par ajuster ce curseur jusqu'à ce que les retours à la ligne soient identiques entre les deux calques. Si votre police personnalisée est plus étroite qu'Arial, une valeur inférieure à 100 % réduira les caractères du repli pour s'en rapprocher.
C'est souvent le seul paramètre nécessaire pour les polices proches des standards système. Les autres permettent un ajustement fin de la position verticale du texte.
ascent-override 0 % – 200 %, ou « normal »
Contrôle l'espace alloué au-dessus de la ligne de base (baseline). La valeur « normal » utilise la métrique native de la police de repli.
Quand le modifier : quand, même après avoir ajusté size-adjust, les blocs de texte ne sont pas à la même hauteur verticale entre les deux calques. Typiquement visible quand les titres ou le début du texte ne s'alignent pas.
descent-override 0 % – 100 %, ou « normal »
Contrôle l'espace alloué en dessous de la ligne de base. La valeur « normal » utilise la métrique native.
Quand le modifier : quand le bas des blocs de texte ne s'aligne pas, notamment visible sur la dernière ligne d'un paragraphe ou la hauteur totale d'un bloc.
line-gap-override 0 % – 100 %, ou « normal »
Contrôle l'espace supplémentaire entre les lignes (line gap). Distinct de line-height en CSS : c'est une métrique intrinsèque de la police.
Quand le modifier : quand la hauteur totale d'un bloc de texte diffère encore entre les deux calques après avoir calibré size-adjust, ascent-override et descent-override.
Le piège du line-height
Subtilité importante du spec CSS : line-gap-override (ainsi que ascent-override et descent-override) ne s'applique que lorsque le rendu utilise line-height: normal. Si la page définit un line-height numérique (1.5, 24px, etc.), le navigateur utilise cette valeur et ignore complètement les overrides de métriques.
Comme la quasi-totalité des sites de production définit un line-height explicite, line-gap-override n'a généralement aucun effet visible en production. C'est pour cela qu'on recommande de le laisser à normal dans 99 % des cas.
Le comportement automatique de l'outil
Pour rendre les overrides de métriques pédagogiques, le mode d'aperçu utilise par défaut un line-height numérique de 1.35 (typique d'un site de production). Les calques s'alignent proprement et vous calibrez size-adjust, ascent-override et descent-override dans les conditions réelles.
Dès que vous décochez « normal » sur n'importe quel line-gap-override (Fallback 1 ou 2, n'importe quel stack), l'aperçu bascule automatiquement en line-height: normal pour que votre réglage soit visible. Un avertissement orangé apparaît sous le slider pour rappeler que cet override n'aura probablement pas d'effet en production.
Modes de prévisualisation
Clignoter
Alterne entre la police originale et la police de repli toutes les 500 ms. Quand le texte ne bouge pas pendant le clignotement, le repli est parfaitement calibré. C'est le test décisif.
Lignes
Affiche des lignes de référence typographiques (soulignement + surlignement) sur chaque élément de texte. Permet de comparer visuellement l'alignement des lignes de base entre les deux calques sans dépendre uniquement des couleurs.
Couleurs des calques
En mode clair, les deux calques utilisent mix-blend-mode: multiply sur fond blanc :
- Les zones où les deux calques se superposent parfaitement apparaissent en couleur mélangée (neutre foncé).
- Les zones où il y a un décalage montrent chacun des calques dans sa couleur.
En mode sombre, mix-blend-mode: screen est utilisé avec des couleurs claires, produisant le même effet inverse sur fond sombre.
Cliquez sur l'icône palette à côté du nom de chaque police pour personnaliser sa couleur. Le choix est sauvegardé par thème en localStorage.
Étape Test A/B
Cette étape simule le chargement réel de votre police avec un délai paramétrable, et compare visuellement le résultat dans deux panneaux :
- Sans fallback ajusté — le navigateur n'a que la police générique (sans-serif/serif). Quand la vraie police arrive, ce panneau saute (effet rouge pulsé) — c'est le CLS qu'on cherche à éliminer.
- Avec fallback ajusté — le navigateur utilise vos overrides
@font-face. Si vos métriques sont bien calibrées, ce panneau ne saute pas.
Connexion réseau : choisissez parmi Wi-Fi (300 ms), Fast 3G (1.5 s), Slow 3G (4 s) ou un délai personnalisé via la modale (100 ms à 10 s).
Échantillon de texte : sélectionnez le même type de contenu que dans l'aperçu (paragraphe, titres, liste, tableau…).
Taille de la police : slider 14–36 px, partagé avec l'aperçu des étapes Fallback 1/2 (la valeur est sauvegardée en localStorage).
Le delta en pixels entre l'avant et l'après-swap est mesuré et affiché à droite de chaque panneau quand un saut est détecté.
Utiliser le CSS généré
Une fois les valeurs calibrées, copiez le CSS généré et intégrez-le dans votre feuille de styles avant la déclaration @font-face de votre police principale.
La stack font-family insère une seule famille de repli entre votre police principale et la police générique :
font-family: 'VotrePolice', 'VotrePolice-fallback', sans-serif;
Lorsque la police principale n'est pas encore chargée, le navigateur utilise VotrePolice-fallback — qui désigne selon le système Arial ou Roboto, chacune avec ses propres métriques ajustées.
Dès que la police principale est chargée, elle remplace les polices de repli sans aucun décalage visible.
À propos
No More Font Shift a été conçu et développé par Agence Web Performance, une agence spécialisée en optimisation de la performance web basée en France.
L'outil est né d'un besoin quotidien : lors d'audits de performance et de missions d'optimisation CLS, nous devions trouver manuellement les valeurs @font-face correctes pour chaque police cliente. Ce processus répétitif nous a conduits à créer un outil interne, puis à le rendre public pour en faire bénéficier toute la communauté web.
La base de données publique centralise les configurations déjà établies pour les polices les plus répandues. Si vous utilisez une police déjà enregistrée, vous n'avez qu'à copier le CSS — le travail est déjà fait.
Comment No More Font Shift résout le problème
CSS propose des descripteurs
@font-facequi permettent de modifier les métriques d'une police de repli pour la faire ressembler à votre police personnalisée. L'astuce : ajuster la police de repli, pas la police principale./* Repli Android (Roboto) — déclaré EN PREMIER */ @font-face { font-family: 'Poppins-fallback'; src: local('Roboto Regular'), local('Roboto-Regular'), local('Roboto'); size-adjust: 104.86%; ascent-override: 91.93%; } /* Repli desktop / iOS (Arial) — déclaré EN DERNIER, donc prioritaire */ @font-face { font-family: 'Poppins-fallback'; src: local('Arial'); size-adjust: 103.24%; ascent-override: 94.00%; } body { font-family: 'Poppins', 'Poppins-fallback', sans-serif; }No More Font Shift fournit un éditeur visuel pour trouver ces valeurs : uploadez votre police, comparez les deux calques de texte superposés (police originale en bleu, police de repli en orange), et ajustez les curseurs jusqu'à superposition parfaite.