Carnet · Note 002 · Typographie

Dix langues, trois fichiers de police

Quand tu passes un site en dix langues, le budget des polices lâche souvent en premier. Pas cette fois. Mais le cyrillique et l’arabe ont eu un coût, et nous ne l’avons pas caché.

Serhat Belen

Fondateur, BLN Global · · 6 min de lecture

Réponse courte

Si les trois mêmes polices venaient de Google Fonts, une page en turc téléchargerait 6 fichiers depuis deux sources externes, soit 250 KB. Depuis notre serveur, elle charge 3 fichiers d’une seule source pour 165 KB. Le gros du gain ne vient pas du sous-ensemble, mais du verrouillage des axes inutilisés. Il a fallu choisir une famille distincte pour les caractères cyrilliques et arabes. En arabe, certains symboles viennent donc de la police de secours.

La typo du site reposait sur trois familles: Archivo pour les titres, Instrument Sans pour le texte, Martian Mono pour les chiffres et les libellés. Trois polices variables. Aucun souci en cinq langues. En passant à dix, deux problèmes ont grossi d’un coup: les octets téléchargés et la couverture des alphabets.

Ce qu’on compare, et à quoi

Comparer les fichiers TTF bruts à nos fichiers WOFF2 serait trompeur. L’écart vient surtout de la compression, pas du sous-ensemble. La bonne comparaison se fait avec l’autre option réelle. Quel poids aurait-on téléchargé si les trois mêmes familles venaient de Google Fonts ?

Les neuf fichiers ne se chargent pas tous. Le navigateur unicode-range lit le champ et charge uniquement les sous-ensembles utiles à la page. Pour une page en turc, cela donne latin + latin-ext par famille :

latin 88.0 KB <- latin-ext 83.8 KB <- vietnamese 33.6 KB latin 29.2 KB <- latin-ext 10.8 KB <- latin 23.0 KB <- latin-ext 15.5 KB <- cyrillic 10.3 KB cyrillic-ext 3.1 KB À télécharger pour la page en turc: 250 KB (6 fichiers)
On a récupéré le CSS Google Fonts, puis lu le champ unicode-range de chaque bloc @font-face. Les fichiers ont été pesés un par un. Les lignes avec une flèche sont celles qui se téléchargent sur une page en turc.
250 KB / 6 fichiers / 2 sources externes165 KB / 3 fichiers / une seule source

Poids des polices sur la page turque

Comment on a mesuré À gauche, la mesure ci-dessus. À droite, celle de ce dépôt archivo.woff2 + instrument.woff2 + martian.woff2 taille réelle des fichiers sur disque.

Au-delà des octets, tu gagnes 2 choses : 6 requêtes passent à 3, et les poignées de main DNS + TLS vers 2 origines externes disparaissent. Comment on a supprimé la ressource qui bloquait le premier affichage dans la note sur les 18 derniers points on raconte.

Trois pièges

Un : le sous-ensemble latin-ext n’inclut pas les lettres latines de base

Au premier essai, nous avons téléchargé le fichier latin-ext de Google Fonts pour le réduire. Résultat : 130 glyphes et aucun chiffre. La raison est simple. latin-ext se superpose à latin comme un ajout est un ensemble, pas un alphabet complet à lui seul. La bonne méthode: récupérer la police variable complète dans le dépôt google/fonts, puis extraire toi-même le sous-ensemble.

Deux : sans figer les axes inutilisés, le fichier devient cinq fois plus lourd

Chaque axe d’une police variable alourdit le fichier. Le design n’utilise que graisse et largeur. Si tu ne bloques pas les autres axes sur leurs valeurs par défaut, leurs données restent toutes dans le fichier.

tam = {a.axisTag: a.defaultValue for a in t['fvar'].axes if a.axisTag not in eksen} tam.update(eksen) # Les axes autres que wght/wdth gardent leur valeur par défaut, # sinon le fichier devient cinq fois plus lourd
Figer l’axe avant le sous-ensemble fait gagner plus que le sous-ensemble lui-même.

Trois : gvar se charge en différé

avec fontTools, après avoir figé l’axe, si tu tentes un sous-ensemble direct KeyError: space Ça se récupère. La cause: les données de glyphes variables (gvar) se chargent à la demande. Après figage, l’objet paraît cohérent en mémoire, mais le subsetter ne peut pas le lire. La solution fait un détour, en une ligne: enregistre le fichier en TTF temporaire, rouvre-le, puis génère le sous-ensemble.

Cyrillique et arabe : le prix à payer

Archivo n’a pas de cyrillique, Instrument Sans non plus. Aucun des deux n’a d’arabe. Pour ces deux langues, il fallait choisir une autre famille. On ne l’a pas fait au hasard.

  • Russe : Roboto Flex. Un seul point commun dans la structure : un axe de largeur. Donc tous les font-variation-settings fonctionnent sans toucher aux valeurs. Un seul fichier couvre les titres et le corps. La page russe reste plus légère que la page latine.
  • Arabe : Noto Sans Arabic. Le seul candidat avec un axe de largeur. Un fichier de 144 KB couvre les trois rôles, donc la page arabe télécharge moins que la page latine.

Le coût est là : Noto Sans Arabic et n’a pas ces symboles. Sur la page en arabe, ces deux signes viennent de la police de secours et diffèrent légèrement des caractères voisins. On l’a expliqué dans un commentaire CSS au lieu de le cacher. Sinon, la prochaine personne aurait pris cette différence pour un bug.

La mise en page de droite à gauche demande un travail à part. Les flèches ont changé de sens et les propriétés de position ont cédé la place à leurs équivalents logiques (margin-inline-start, inset-inline-start), comme ça le même CSS marche dans les deux sens.

Un petit réglage : pourquoi Martian Mono utilise optional

Deux familles sur trois font-display:swap utilise. Martian Mono optional. La cause a été mesurée: avec swap, Martian arrive tard, force le bouton de menu à se remesurer et crée un décalage de 0,015. Comme il est préchargé, il arrive presque toujours à temps. Et dans le seul cas où il n’y arrive pas, la page ne bouge pas, elle garde la police de secours.

Le dossier de polices pour dix langues pèse 404 KB. Personne ne télécharge tout. Chaque page charge uniquement les fichiers de sa langue.

FAQ

Dois-tu héberger les polices au lieu d’utiliser Google Fonts ?

Pas toujours en octets, mais souvent en connexions, oui. Google Fonts se branche sur deux origines, et chaque nouvelle origine ajoute une résolution DNS et une poignée de main TLS. Chez nous, on est passé de 250 KB / 6 fichiers / 2 origines à 165 KB / 3 fichiers / une seule origine.

Qui gagne le plus : sous-ensemble ou axe figé ?

Bloque l’axe. Chaque axe inutilisé d’une police variable prend de la place dans le fichier. Si tu ne le bloques pas, le fichier peut grossir plusieurs fois. Le sous-ensemble vient après.

Le sous-ensemble latin-ext suffit-il pour le turc ?

Non, il ne suffit à aucune langue lorsqu’il est utilisé seul. latin-ext complète latin. Il ne contient ni les lettres de base ni les chiffres. Télécharge la police variable complète, puis crée toi-même le sous-ensemble.

swap ou optional pour font-display ?

Si le texte forme le corps de la page et que la police est préchargée, optional protège mieux : si elle arrive trop tard, la page ne bouge pas, elle garde la police de secours. Chez nous, swap créait un décalage de mise en page de 0,287 sur les pages arabes. optional l'a ramené à zéro.

Quelle police as-tu choisie pour l’arabe et le russe, et pourquoi ?

Pour le russe: Roboto Flex. Pour l’arabe: Noto Sans Arabic. Le choix ne tenait pas au style, mais à la structure: les deux ont un axe de largeur, donc l’existant dans le CSS font-variation-settings tourne sans toucher aux valeurs.

Sources

Projets liés