Prérequis
- Niveau : bases HTML/CSS.
- Outils : VS Code, navigateur (DevTools onglet Network filtre Font).
- Temps estimé : 45 min.
Pourquoi cet article ?
Les polices web mal intégrées sont une cause majeure de mauvais score Lighthouse : chargement bloquant, FOIT/FOUT, CLS. Bien faites, elles ne coûtent presque rien tout en transformant l’identité visuelle d’un site.
Pourquoi le choix de vos polices impacte directement votre site
La typographie représente plus de 90% du contenu visuel d’un site web. Une police mal choisie ou mal chargée ralentit votre site, nuit à la lisibilité et dégrade l’expérience utilisateur. Ce guide vous montre comment intégrer des polices web proprement, optimiser leur chargement, et éviter le flash de texte invisible (FOIT) qui fait fuir les visiteurs.
Google Fonts : intégration en 2 méthodes
Méthode 1 : le lien HTML (la plus simple)
Allez sur fonts.google.com, choisissez vos polices, et copiez le code dans votre <head> :
<!-- Charger Inter (texte) et Playfair Display (titres) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&family=Playfair+Display:wght@700&display=swap" rel="stylesheet">
Points importants :
- Les deux
preconnectaccélèrent la connexion au serveur de Google Fonts display=swapaffiche d’abord une police système puis la remplace → le texte est lisible immédiatement- Ne chargez que les graisses dont vous avez besoin (400, 500, 700 ici, pas toute la famille)
Méthode 2 : @import dans le CSS
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');
body {
font-family: 'Inter', sans-serif;
}
À éviter en production. Le @import bloque le rendu du CSS tant que la police n’est pas téléchargée. Utilisez toujours la méthode <link> en production.
Méthode 3 : auto-héberger les polices (la plus performante)
Téléchargez les fichiers de police et servez-les depuis votre propre serveur. Aucune requête vers Google, chargement plus rapide, et conformité RGPD (pas de données envoyées à Google).
Utilisez google-webfonts-helper pour télécharger les fichiers et générer le CSS automatiquement :
/* Placer les fichiers dans /fonts/ */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/inter-v13-latin-regular.woff2') format('woff2');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts/inter-v13-latin-700.woff2') format('woff2');
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
Pourquoi WOFF2 suffit : le format WOFF2 est supporté par 97%+ des navigateurs en 2026 (informations vérifiées en avril 2026, susceptibles d’évoluer). Inutile d’ajouter TTF, EOT ou WOFF1 sauf si vous ciblez Internet Explorer (ce que vous ne devriez pas faire).
Les 5 règles d’or de la typographie web
1. Maximum 2 polices par site
Une police pour les titres, une pour le texte courant. Chaque police supplémentaire ajoute 50-150 Ko de téléchargement. Deux polices bien choisies sont plus élégantes que cinq qui se battent.
2. Toujours déclarer une pile de polices de secours
/* Bon : pile complète avec fallback */
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
/* Mauvais : pas de fallback */
font-family: 'Inter';
Si Inter ne charge pas, le navigateur utilise la police système la plus proche. L’utilisateur voit du texte lisible immédiatement au lieu d’un trou vide.
3. Utiliser font-display: swap
Cette propriété CSS dit au navigateur : « affiche le texte avec une police de secours immédiatement, puis remplace par la web font quand elle est prête ». Sans swap, le texte est invisible pendant le chargement (FOIT — Flash of Invisible Text).
4. Limiter les graisses chargées
Chaque graisse (400, 500, 600, 700) est un fichier séparé de 15-40 Ko. Ne chargez que ce que vous utilisez réellement :
- 400 (Regular) : texte courant
- 700 (Bold) : titres et emphase
- 500 (Medium) : sous-titres (optionnel)
5. Précharger la police critique
<link rel="preload" href="/fonts/inter-v13-latin-regular.woff2" as="font" type="font/woff2" crossorigin>
Le preload demande au navigateur de télécharger cette police en priorité, avant même d’analyser le CSS. À utiliser uniquement pour la police du texte principal (pas les titres qui apparaissent plus bas).
Tailles et espacement : les valeurs qui marchent
body {
font-size: 16px; /* Minimum absolu pour la lisibilité */
line-height: 1.6; /* Espacement entre les lignes */
letter-spacing: -0.01em; /* Légère compression pour Inter */
}
h1 { font-size: clamp(2rem, 5vw, 3.5rem); } /* Responsive automatique */
h2 { font-size: clamp(1.5rem, 3vw, 2.5rem); }
h3 { font-size: clamp(1.2rem, 2.5vw, 1.8rem); }
p {
max-width: 65ch; /* 65 caractères par ligne = confort de lecture optimal */
margin-bottom: 1.5em;
}
La fonction clamp() définit un minimum, une taille fluide et un maximum. Le titre s’adapte automatiquement entre mobile et desktop sans media query.
Combinaisons de polices recommandées
| Usage | Titres | Texte | Style |
|---|---|---|---|
| Corporate / pro | Playfair Display | Inter | Élégant et moderne |
| Tech / startup | Space Grotesk | DM Sans | Géométrique et clean |
| Blog / éditorial | Merriweather | Source Sans Pro | Lisible et sérieux |
| Créatif / portfolio | Syne | Work Sans | Original et moderne |
| Minimaliste | Inter Bold | Inter Regular | Une seule police = chargement rapide |
Tester vos performances de chargement de police
- Ouvrez Chrome DevTools → onglet Network
- Filtrez par Font
- Rechargez la page (Ctrl+Shift+R)
- Vérifiez le nombre de fichiers de police chargés et leur taille totale
- Objectif : moins de 100 Ko total pour toutes les polices
Erreurs fréquentes
Charger toute la famille de polices
Cause : on coche toutes les graisses dans Google Fonts.
Solution : 2 ou 3 graisses suffisent (400, 700 + éventuellement 500). Chaque graisse = un fichier WOFF2 supplémentaire.
Oubli de font-display: swap
Cause : par défaut, le navigateur attend la police → texte invisible (FOIT) jusqu’à 3 secondes.
Solution : display=swap dans l’URL Google Fonts, ou font-display: swap dans @font-face.
Pas de fallback dans font-family
Cause : on écrit juste font-family: 'Inter';.
Solution : empilez toujours 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif.
Données envoyées à Google (RGPD)
Cause : le simple chargement depuis Google Fonts envoie l’IP de l’utilisateur à Google.
Solution : auto-hébergez les polices (google-webfonts-helper) — gain RGPD + perf.
Exercice pratique
Créez une page HTML qui utilise Playfair Display pour le titre et Inter pour le texte :
- Intégrez les polices avec la méthode
<link>etdisplay=swap - Déclarez une pile de polices de secours complète
- Utilisez
clamp()pour des tailles responsive - Limitez la largeur du texte à 65 caractères
- Mesurez le temps de chargement des polices dans DevTools
- Bonus : passez à l’auto-hébergement et comparez la vitesse
Pour creuser ce sujet
- Optimiser les performances
- Mode sombre
- Référence : web.dev — Font best practices
- Auto-hébergement : google-webfonts-helper
- Variable fonts : v-fonts.com (1 fichier = toutes les graisses)
Étape 1 — Choisir une famille de polices adaptée au web africain
En Afrique de l’Ouest, beaucoup d’utilisateurs accèdent au web via 4G plafonnée ou 3G dégradée (zones périurbaines de Dakar, Abidjan, Bamako). Le choix typographique doit rester sobre : une famille pour les titres, une famille pour le corps de texte, deux graisses maximum (regular + bold). Au-delà, chaque variante ajoute 30 à 50 ko à charger.
BUDGET POLICES :
- Titres : Inter Bold (~25 ko WOFF2)
- Corps : Inter Regular (~22 ko WOFF2)
- TOTAL CIBLE : < 60 ko
ECRITURE LATIN-EXT (français + accents wolof / bambara) : OK
Le test concluant : votre maquette tient avec 2 fichiers WOFF2 et reste lisible sur un Tecno Spark à 320 px de large.
Étape 2 — Auto-héberger plutôt que charger Google Fonts en direct
Depuis l’arrêt de la CJUE du 20 janvier 2022 et les décisions allemandes qui ont suivi, embarquer Google Fonts en direct (fonts.googleapis.com) transmet l’IP visiteur à Google sans consentement. Pour un site servant l’Europe ou l’Afrique de l’Ouest francophone, l’auto-hébergement est désormais la voie sûre côté RGPD.
# télécharger les fichiers WOFF2 depuis google-webfonts-helper
# https://gwfh.mranftl.com/fonts
# choisir Inter, charset latin + latin-ext, formats WOFF2
# extraire dans /assets/fonts/inter/
ls assets/fonts/inter/
# inter-v18-latin-ext-regular.woff2
# inter-v18-latin-ext-700.woff2
Vous devriez obtenir : deux fichiers WOFF2 dans votre dépôt, prêts à être servis depuis votre propre domaine. Aucun appel sortant vers fonts.gstatic.com au chargement de la page.
Étape 3 — Déclarer @font-face avec font-display swap
La déclaration @font-face doit utiliser font-display: swap pour afficher immédiatement la police système, puis remplacer par la police personnalisée dès qu’elle est disponible. Sans cette directive, l’utilisateur voit du texte invisible (FOIT) pendant 1 à 3 secondes sur 4G dégradée.
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/assets/fonts/inter/inter-v18-latin-ext-regular.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0100-024F, U+1E00-1EFF;
}
@font-face {
font-family: 'Inter';
font-weight: 700;
font-display: swap;
src: url('/assets/fonts/inter/inter-v18-latin-ext-700.woff2') format('woff2');
}
Sortie attendue : Lighthouse ne signale plus l’avertissement « Ensure text remains visible during webfont load ». Mesurez le LCP avant et après, vous gagnez typiquement 200 à 500 ms sur connexion 3G.
Étape 4 — Précharger les polices critiques
Pour les polices utilisées au-dessus de la ligne de flottaison (titre H1, navigation), ajoutez un preload dans le head. Cette directive force le navigateur à télécharger le fichier dès le parsing du HTML, sans attendre l’analyse du CSS.
<link rel="preload" as="font" type="font/woff2"
href="/assets/fonts/inter/inter-v18-latin-ext-regular.woff2"
crossorigin>
<link rel="preload" as="font" type="font/woff2"
href="/assets/fonts/inter/inter-v18-latin-ext-700.woff2"
crossorigin>
Résultat attendu : dans l’onglet Network du DevTools, les fichiers WOFF2 partent au tout début du waterfall, en parallèle du CSS. Attention : ne préchargez QUE les polices visibles immédiatement. Précharger 6 fichiers retarde le LCP.
Étape 5 — Activer la compression et le cache long
Les fichiers WOFF2 sont déjà compressés (Brotli interne). Inutile de les regzip côté serveur. En revanche, configurez un cache HTTP très long (1 an) avec un nom de fichier versionné, puisque le contenu d’une police ne change jamais.
# Nginx
location ~* \.(woff2)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Access-Control-Allow-Origin "*";
}
Sortie de référence : la deuxième visite ne re-télécharge plus les polices (statut 200 from disk cache ou 304). En mode incognito, observez le « 200 OK » initial puis le cache hit au refresh.
Étape 6 — Limiter le sous-ensemble (subsetting) au strict utile
Une police latine complète pèse 60 à 90 ko. En limitant aux glyphes effectivement utilisés (latin de base + latin extended pour les accents français, wolof, bambara), vous descendez à 18-25 ko. Pour les sites en français pur sans contenu utilisateur multilingue, le sous-ensemble latin-ext suffit.
# sous-ensemble manuel avec glyphhanger + pyftsubset
npm install -g glyphhanger
pip install fonttools brotli
glyphhanger --LATIN https://votresite.com --subset=Inter*.woff2 --formats=woff2
Sortie de référence : un fichier Inter-subset.woff2 de 18 à 25 ko qui couvre 100 % du français + caractères des langues nationales sénégalaises et ivoiriennes. Vérifiez visuellement les pages avec accents (é, è, à, ê, ç) et caractères wolof (ŋ).
Étape 7 — Vérifier l’impact CLS avec Lighthouse
Le swap de police peut provoquer un Cumulative Layout Shift (CLS) si la police de remplacement a des métriques très différentes de la police finale. CSS dispose depuis 2024 des descripteurs size-adjust, ascent-override, descent-override pour aligner les métriques.
@font-face {
font-family: 'Inter Fallback';
src: local('Arial');
size-adjust: 107%;
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
}
body { font-family: 'Inter', 'Inter Fallback', sans-serif; }
Sortie attendue : Lighthouse CLS < 0,1. Le contenu ne saute plus quand la police personnalisée prend le relais. Testez sur l’émulation Slow 4G et Fast 3G.
Étape 8 — Auditer la consommation de bande passante côté visiteur
Une polices auto-hébergée mal calibrée peut quand même peser 250 ko cumulés sur la première visite. Auditez votre site avec WebPageTest depuis un serveur Frankfurt ou London (latence proche de Dakar via les câbles ACE et SAT-3) et vérifiez le poids total des polices dans le breakdown.
Pour approfondir sur la performance perçue, voir notre tutoriel optimisation temps de chargement Afrique de l’Ouest et notre guide Core Web Vitals 2026.
Étape 9 — Gérer les variantes italiques et graisses intermédiaires
Beaucoup de sites WordPress ou Shopify embarquent par défaut 6 à 12 variantes (regular, italic, light, medium, semibold, bold, extrabold). Sur la cible francophone ouest-africaine, 80 % du trafic n’utilise que regular et bold. Auditez votre CSS avec l’onglet Coverage de Chrome DevTools pour repérer les graisses jamais appliquées.
# Chrome DevTools
# Cmd/Ctrl+Shift+P → "Show Coverage"
# Recharger la page
# Filtrer par CSS, trier par "Unused Bytes"
# Repérer les @font-face inutilisés et les supprimer
Résultat attendu : la liste des variantes effectivement utilisées au-dessus de la ligne de flottaison. Toutes les autres peuvent partir, ou passer en chargement différé via media="print" onload.
Étape 10 — Variable fonts : gain ou piège
Les polices variables (un seul fichier qui contient toutes les graisses via un axe wght) peuvent peser moins lourd qu’une seule variante statique au-delà de 3 graisses utilisées. En dessous de 3 graisses, la version statique reste plus légère. Comparez avant de choisir.
STATIQUE 2 graisses : 22 + 25 = 47 ko
VARIABLE Inter[wght] : 78 ko
→ STATIQUE GAGNE
STATIQUE 5 graisses : 22+24+25+27+30 = 128 ko
VARIABLE Inter[wght] : 78 ko
→ VARIABLE GAGNE
Ce que vous devez voir : un choix documenté dans le README front-end avec le poids final mesuré. Ne suivez pas un conseil générique « les variable fonts sont toujours mieux » sans le vérifier sur votre cas.