Diario · Nota 002 · Tipografia

Dieci lingue, tre file di font

Quando porti un sito in dieci lingue, il budget dei font è il primo a saltare. Qui ha retto. I caratteri cirillici e arabi hanno imposto un altro costo, che abbiamo mostrato senza nasconderlo.

Serhat Belen

Fondatore, BLN Global · · 6 min di lettura

Risposta breve

Con gli stessi tre font serviti da Google Fonts, una pagina turca scaricherebbe 6 file per 250 KB da due origini esterne. Dal nostro server ne scarica 3 per 165 KB, da un'unica origine. Il risparmio nasce soprattutto dal blocco degli assi inutilizzati, non dai sottoinsiemi. Per i caratteri cirillici e arabi abbiamo dovuto scegliere famiglie separate. In arabo, alcuni simboli arrivano dal font di riserva.

La tipografia del sito usava tre famiglie: Archivo per i titoli, Instrument Sans per il testo, Martian Mono per numeri ed etichette. Tutti e tre sono font variabili. Con cinque lingue filava tutto. Passando a dieci, sono cresciuti insieme due problemi: byte scaricati e copertura degli alfabeti.

Cosa confrontiamo con cosa

Confrontare i file TTF grezzi con i WOFF2 pubblicati sarebbe scorretto. Gran parte della differenza dipende dalla compressione, non dal sottoinsieme. Il confronto utile è con l’alternativa reale: quanti dati avresti scaricato usando le stesse tre famiglie da Google Fonts.

Non scarica tutti e nove i file. Il browser unicode-range controlla il campo e carica solo i sottoinsiemi necessari. Per una pagina in turco significa latin + latin-ext per ogni famiglia:

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 La pagina in turco scarica: 250 KB (6 file)
Abbiamo scaricato il CSS di Google Fonts, letto il campo unicode-range di ogni blocco @font-face e misurato i file uno per uno. Quelli con la freccia sono i file che una pagina in turco scarica davvero.
250 KB / 6 file / 2 origini esterne165 KB / 3 file / una sola origine

Il peso dei font nella pagina turca

Come abbiamo misurato A sinistra, la misura qui sopra. A destra, quella di questo repository archivo.woff2 + instrument.woff2 + martian.woff2 la dimensione reale dei file su disco.

Oltre ai byte, sono arrivati altri due vantaggi: sei richieste sono diventate tre e sono spariti del tutto gli handshake DNS + TLS verso due origini esterne. Come abbiamo chiuso il problema delle risorse che bloccavano il primo paint nella nota sugli ultimi 18 punti lo spieghiamo.

Tre trappole

Uno: nel subset latin-ext mancano le lettere latine di base

Al primo tentativo abbiamo scaricato il file latin-ext di Google Fonts e ne abbiamo creato un sottoinsieme. Il risultato conteneva 130 glifi, ma nessuna cifra. Il motivo è semplice: latin-ext non contiene tutto latin. extra è un subset, non un alfabeto completo. La strada giusta è scaricare il font variabile completo dal repository google/fonts ed estrarre tu il subset.

Due: se non fissi gli assi inutilizzati, il file diventa cinque volte più grande

Ogni asse di un font variabile pesa sul file. Nel design usiamo solo peso e larghezza. Se non blocchi gli altri assi ai valori predefiniti, i loro dati restano nel file.

completo = {a.axisTag: a.defaultValue for a in t['fvar'].axes if a.axisTag not in assi} completo.update(assi) # Gli assi diversi da wght/wdth restano sul valore predefinito, # altrimenti il file pesa cinque volte tanto
Bloccare l’asse prima del subset fa risparmiare più spazio del subset stesso.

Tre: gvar si carica in lazy

dopo aver bloccato l’asse con fontTools, se provi a fare subito il subset KeyError: space si estrae. Il motivo è il lazy loading dei dati dei glifi variabili (gvar): dopo il pinning, l’oggetto in memoria sembra coerente, ma il subsetter non riesce a leggerlo. La soluzione fa un giro largo, ma sta in una riga: salva il file come TTF temporaneo, riaprilo, poi estrai il subset.

Cirillico e arabo: il prezzo pagato

Archivo non contiene cirillico. Nemmeno Instrument Sans. L'arabo manca in entrambi. Per queste due lingue serviva una famiglia diversa, e la scelta non è stata casuale.

  • Russo: Roboto Flex. Era l’unico match strutturale: ha l’asse della larghezza. Nel CSS tutti i font-variation-settings i valori funzionano senza modifiche. Un solo file gestisce titoli e testo. La pagina russa resta più leggera di quella latina.
  • Arabo: Noto Sans Arabic. L'unico candidato con asse della larghezza. Un solo file da 144 KB copre tre ruoli, così la pagina araba scarica meno della pagina latina.

Il costo sta qui: in Noto Sans Arabic e non contiene i glifi. Nella pagina araba, questi due segni arrivano dal font di riserva e appaiono leggermente diversi dai caratteri vicini. Invece di nasconderlo, lo abbiamo spiegato in un commento nel CSS. Altrimenti chi verrà dopo potrebbe scambiare la differenza per un errore.

Il layout da destra a sinistra ha richiesto un lavoro a parte: abbiamo invertito le frecce e sostituito le proprietà di posizione con gli equivalenti logici (margin-inline-start, inset-inline-start), così lo stesso CSS funziona bene in entrambe le direzioni.

Una piccola modifica: perché Martian Mono usa optional

Due famiglie su tre font-display:swap usa. Martian Mono optional. Il motivo lo abbiamo misurato: con swap, Martian arrivava tardi, faceva ricalcolare il pulsante del menu e causava uno spostamento di layout di 0,015. Siccome è precaricato, in pratica arriva in tempo. Nell’unico caso in cui non ce la fa, la pagina non si sposta e resta con il font di fallback.

La cartella dei font pesa 404 KB per dieci lingue. Nessuno la scarica tutta. Ogni pagina carica solo i file della propria lingua.

Domande frequenti

Meglio ospitare i font sul mio server invece di usare Google Fonts?

In byte non sempre, nelle connessioni di solito sì. Google Fonts apre due origini diverse, e ogni origine nuova chiede DNS e handshake TLS. Nei nostri test: 165 KB / 3 file / un’unica origine invece di 250 KB / 6 file / 2 origini.

Fa risparmiare di più il subset o il blocco dell’asse?

Blocca gli assi. Ogni asse che non usi in un font variabile occupa spazio nel file. Se non lo fissi, il file cresce di parecchie volte. Il subset arriva dopo.

Il subset latin-ext basta per il turco?

No, da solo non basta per nessuna lingua. latin-ext è un insieme aggiuntivo che si sovrappone a latin e non include lettere di base né cifre. Scarica il font variabile completo e crea tu il sottoinsieme.

swap o optional per font-display?

Se il testo è il corpo della pagina e il font è in preload, optional è più sicuro: se arriva tardi, la pagina non si sposta e resta sul font di riserva. Da noi swap sulle pagine arabe causava un CLS di 0,287. optional lo ha portato a zero.

Quale font hai scelto per arabo e russo, e perché?

Roboto Flex per il russo, Noto Sans Arabic per l'arabo. La scelta non era estetica, era strutturale: entrambi hanno l'asse della larghezza, cioè l'attuale in CSS font-variation-settings funziona senza cambiare i valori.

Fonti

Lavori collegati