Comment diviser par 10 le poids de vos polices grâce au subsetting

La majorité des sites web utilisent des polices personnalisées que l'on retrouve souvent sur Google Fonts. Comme vous le savez probablement, vous devez télécharger autant de fichiers que de graisses. En effet, si vous avez besoin de 4 graisses et leur version italique, vous aurez besoin de 8 fichiers (8 requêtes HTTP, 8 fichiers de 150ko en TTF, etc).

Nous allons voir comment réduire de plus de 90% le poids (et améliorer votre CLS (Cumulative Layout Shift)) de vos polices variables en embarquant la totalité des graisses au passage.

On va prendre Roboto comme exemple et pour comparer les performances, nous allons convertir les TTF en WOFF2 pour avoir une référence avec des fontes statiques optimisées.

Fonte statique TTF (source) WOFF2 (conversion)
Roboto-Regular 156 Ko 68 Ko
Roboto-Bold 157 Ko 70 Ko
Roboto-Light 156 Ko 68 Ko
Roboto-Black 157 Ko 69 Ko
Roboto-Italic 162 Ko 74 Ko
Roboto-BoldItalic 163 Ko 76 Ko
Roboto-LightItalic 162 Ko 74 Ko
Roboto-BlackItalic 163 Ko 75 Ko
TOTAL 1,276 Mo 0,574 Mo

On peut voir que le poids des polices d'un site est comparable aux chargements d'une dizaine d'images.

La conversion de TTF à WOFF2 apporte un gain de 55% mais ce n'est pas suffisant.

Voyons ce que cela peut donner si nous utilisons les polices variables à la place.

Ce qu'est vraiment une fonte variable

Une fonte variable est un fichier unique qui encode plusieurs variations typographiques sur un ou plusieurs axes continus. L'axe wght (graisse) est le plus courant : il permet d'aller de Thin (100) à Black (900) sans avoir à télécharger neuf fichiers distincts.

D'autres axes existent : ital (italique), wdth (chasse), opsz (taille optique), ou des axes propriétaires. Une fonte comme Roboto Flex en combine une douzaine.

Concrètement, un fichier variable TTF contient :

Un seul fichier pour toutes les graisses (et bien plus) mais à quel prix ?

Fonte variable TTF (source) WOFF2 (conversion)
Roboto-VariableFont_wdth,wght 477 Ko 216 Ko
roboto-italic-variablefont-wdth,wght 518 Ko 249 Ko
TOTAL 0,995 Mo 0,465 Mo

La version variable nous permet de réduire légèrement le poids des fontes dans un cas où l'on utilise 4 graisses ou plus. Dans les autres cas, c'est l'inverse, le coût de la fonte variable n'est pas intéressant.

Le vrai problème : les glyphes inutiles

Une fonte Google Fonts couvre souvent des centaines de systèmes d'écriture. Roboto, par exemple, inclut le latin de base, le latin étendu, le cyrillique, le vietnamien, le grec... Autant de glyphes dont un site français n'a absolument pas besoin.

Le subsetting consiste à extraire uniquement les glyphes correspondant aux caractères réellement utilisés. Pour un site en français ou en anglais, les plages Unicode suivantes couvrent 99,9 % des besoins :

Tout le reste ? Supprimé. Le gain est immédiat et drastique.

Fonte variable TTF (source) WOFF2 WOFF2 Latin
Roboto-VariableFont_wdth,wght 477 Ko 216 Ko 77 Ko
roboto-italic-variablefont-wdth,wght 518 Ko 249 Ko 89 Ko
TOTAL 0,995 Mo 0,465 Mo 0,166 Mo

Comparaison avec des Google Fonts populaires

Comparons maintenant ce que ça donne sur un échantillon de 5 Google Fonts variables populaires.

Fonte TTF variable (source) WOFF2 complet WOFF2 Latin Gain
Roboto 477 Ko 217 Ko 77 Ko -84 %
Open Sans 518 Ko 274 Ko 83 Ko -84 %
Inter 855 Ko 341 Ko 85 Ko -90 %
Montserrat 673 Ko 202 Ko 51 Ko -92 %
Roboto Flex 1646 Ko 730 Ko 288 Ko -82 %

Télécharger les fontes optimisées

Comme je suis cool, je vous donne les quelques fontes que j'ai déjà allégées pour que vous puissiez les télécharger et les utiliser sur vos propres sites :

Ces versions ultra-optimisées vont vous permettre d'accélérer le chargement de votre site et optimiser votre CLS (Cumulative Layout Shift).

Créez vos subsets de fontes

L'outil de référence est fontTools, la bibliothèque Python maintenue par Google et utilisée en interne pour produire les fontes Google Fonts elles-mêmes.

Installation :

sudo apt install python3-fonttools python3-brotli

ou alors

pip3 install fonttools brotli

La commande de subset, telle qu'utilisée sur ce projet :

python3 -m fontTools.subset "resources/fonts/Lexend-VariableFont_wght.ttf" \
    --unicodes="U+0020-007F,U+00A0-00FF,U+0152-0153" \
    --flavor=woff2 \
    --output-file="public/fonts/lexend-variablefont-wght.woff2" \
    --layout-features="*" \
    --name-IDs="*"

Ce que fait chaque option :

Automatisé dans un makefile, ça donne une cible font-subset qu'on appelle au build. Un seul appel pour traiter toutes les fontes du dossier resources/fonts/ :

font-subset: ## Génère un subset woff2 pour chaque fonte de resources/fonts/ vers public/fonts/
    @for font in resources/fonts/*; do \
        name=$$(basename "$$font" | sed 's/\.[^.]*$$//' | sed 's/_/-/g' | tr '[:upper:]' '[:lower:]'); \
        output="public/fonts/$$name.woff2"; \
        python3 -m fontTools.subset "$$font" \
            --unicodes="U+0020-007F,U+00A0-00FF" \
            --flavor=woff2 \
            --output-file="$$output" \
            --layout-features="*" \
            --name-IDs="*"; \
    done

Optimisez votre déclaration @font-face

Maintenant que nous avons optimisé le fichier, nous pouvons aussi optimiser son chargement dans la déclaration @font-face pour améliorer la performance perçue.

<!-- Preload : le navigateur télécharge la fonte dès le parsing du <head> -->
<link rel="preload" href="/fonts/lexend-variablefont-wght.woff2" as="font" type="font/woff2" crossorigin>

<style>
    @font-face {
        font-family: 'Lexend';
        src: url('/fonts/lexend-variablefont-wght.woff2') format('woff2');
        font-weight: 100 900; /* toutes les graisses disponibles sur l'axe wght */
        font-style: normal;
        font-display: optional; /* chargement lazy */
    }

    /* Fallback calibré pour zéro layout shift */
    @font-face {
        font-family: 'Lexend Fallback';
        src: local('Arial'); /* on affiche un arial ajusté en attendant Lexend */
        ascent-override: 90%;
        descent-override: 22%;
        line-gap-override: 0%;
        size-adjust: 107%;
    }
</style>

A vous de faire le ménage dans vos fontes !

La recette est simple :

  1. Une fonte variable TTF dans resources/fonts/
  2. Un make font-subset au build avec fontTools → fichier WOFF2 subseté dans public/fonts/
  3. Un @font-face correctement déclaré avec font-weight: 100 900 et font-display: optional
  4. Un fallback calibré avec ascent-override, descent-override et size-adjust

Le résultat sur uxcode : Lexend à 28 KB, chargée en une seule requête, avec toutes les graisses disponibles de 100 à 900, sans flash typographique, sans layout shift.

Le résultat ? Une typographie riche, une requête unique de moins de 30 Ko, et une bonne pratique de plus pour un score Lighthouse qui vise les 100%.

C'est l'approche standard pour tout projet web sérieux en 2026.