I font sono una delle risorse più sottovalutate quando si parla di velocità. Un sito può avere immagini ottimizzate e JavaScript ridotto all’osso e continuare a caricare centinaia di kilobyte di caratteri tipografici: pesi e stili multipli, ciascuno con migliaia di glifi per alfabeti che nessun visitatore leggerà mai. Il subsetting, cioè la riduzione di un font ai soli caratteri che servono, è una delle ottimizzazioni con il miglior rapporto tra sforzo e risultato. In questo articolo vediamo perché i font pesano sulle Web Performance, come si crea un sottoinsieme e come caricarlo nel modo giusto.
Perché i font pesano sulle performance
Un web font incide sulle metriche in tre modi. Il primo è il peso: ogni file va scaricato prima di poter essere usato, e su una connessione mobile qualche centinaio di kilobyte di font compete con l’immagine principale e con il CSS per la banda disponibile. Il secondo è la scoperta tardiva: il browser sa quali font servono solo dopo aver scaricato ed elaborato i fogli di stile, e solo allora ne avvia il download. Il terzo è il comportamento durante l’attesa: il testo può restare invisibile finché il font non arriva, oppure comparire con un font di ripiego e cambiare aspetto al momento della sostituzione.
Le conseguenze si leggono direttamente nei Core Web Vitals. Quando l’elemento più grande della pagina è un titolo o un blocco di testo, cosa frequente negli articoli e nelle pagine istituzionali, l’LCP dipende dal font. E quando il font di ripiego ha dimensioni diverse da quello definitivo, il cambio sposta righe e blocchi e peggiora il CLS.
Che cos’è il subsetting
Un font moderno può contenere migliaia di glifi: alfabeti latino esteso, greco, cirillico, simboli matematici, frecce, caratteri per il disegno di riquadri. Un sito in italiano ne usa poche centinaia: lettere di base, accentate, cifre, punteggiatura, virgolette tipografiche, il simbolo dell’euro. Il subsetting crea una copia del font che contiene solo quei caratteri, eliminando tutto il resto.
I numeri, misurati su un font open source completo come DejaVu Sans, rendono l’idea. Il file TTF originale pesa 742 KB; convertito in WOFF2, il formato compresso pensato per il web, scende a 252 KB. Ridotto al sottoinsieme latino, che comprende latino di base, Latino-1, la punteggiatura tipografica e l’euro, pesa 24 KB. Limitato ai soli caratteri dell’italiano, 15 KB. Lo stesso font, per il visitatore, è identico: cambia solo ciò che non avrebbe mai visto.
Anche questo sito segue lo stesso principio: il carattere principale è una versione variabile di IBM Plex Sans, che contiene tutti i pesi dal più sottile al grassetto in un unico file WOFF2 da 45 KB con il solo sottoinsieme latino.
Come si crea un sottoinsieme
Lo strumento di riferimento è pyftsubset, parte della libreria open source fontTools. Si indicano i caratteri da conservare, per intervalli Unicode o come testo, le funzionalità tipografiche da mantenere e il formato di uscita:
# Sottoinsieme latino, con legature e crenatura, in WOFF2
pyftsubset IBMPlexSans-Variable.ttf \
--unicodes="U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+FEFF,U+FFFD" \
--layout-features="*" \
--flavor=woff2 \
--output-file=ibm-plex-sans-latin.woff2
Per scegliere i caratteri ci sono due strade. La più prudente è partire da intervalli standard, come quelli usati da Google Fonts per il sottoinsieme latino, che coprono l’italiano e le principali lingue dell’Europa occidentale. La più aggressiva è analizzare i contenuti del sito e tenere solo i caratteri effettivamente presenti, con strumenti che scandiscono le pagine. È una scelta da fare con cautela: nomi di prodotti, commenti degli utenti o citazioni in altre lingue possono contenere caratteri non previsti, che il browser mostrerebbe con un font diverso.
Quando un sito serve più lingue, la soluzione è creare più file e dichiararli con la proprietà unicode-range: il browser scarica solo i sottoinsiemi che contengono caratteri presenti nella pagina.
@font-face {
font-family: "IBM Plex Sans";
font-weight: 100 700;
font-display: swap;
src: url("/fonts/ibm-plex-sans-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+20AC;
}
@font-face {
font-family: "IBM Plex Sans";
font-weight: 100 700;
font-display: swap;
src: url("/fonts/ibm-plex-sans-cyrillic.woff2") format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1;
}
WOFF2, font variabili e pesi
Il subsetting dà il massimo insieme a due altre scelte. La prima è il formato: WOFF2 è supportato da tutti i browser moderni e comprime molto meglio di TTF e del vecchio WOFF, quindi oggi non c’è motivo di servire altro. La seconda riguarda i pesi: ogni combinazione di peso e stile è un file separato, e un tema che usa regolare, medio, semigrassetto e grassetto, con i relativi corsivi, carica otto font. Un font variabile contiene tutti i pesi in un solo file: è conveniente quando se ne usano diversi, meno quando ne serve uno solo. In ogni caso conviene chiedersi quanti pesi servano davvero, e rinunciare a quelli usati in un solo punto del sito.
Caricarli nel modo giusto
Un font leggero caricato male resta lento. Molti siti usano ancora servizi esterni, che obbligano il browser ad aprire una connessione verso un altro dominio per il foglio di stile dei font e spesso un’altra per i file veri e propri. Da quando i browser separano la cache per sito, il vantaggio di un font “già in cache” perché scaricato su un altro sito non esiste più. Ospitare i font sul proprio dominio, già in sottoinsieme, elimina queste connessioni e permette di annunciarli in anticipo con un preload.
<link rel="preload" href="/fonts/ibm-plex-sans-latin.woff2"
as="font" type="font/woff2" crossorigin>
Il preload va riservato al font usato nella parte visibile della pagina, di solito uno solo: precaricare tutti i pesi e gli stili toglierebbe banda proprio all’immagine principale. L’attributo crossorigin è necessario anche per i font sullo stesso dominio, altrimenti il browser scarica il file due volte.
Che cosa vede l’utente nell’attesa
La proprietà font-display stabilisce che cosa succede finché il font non è arrivato. Con block il testo resta invisibile per un periodo che può arrivare a tre secondi. Con swap compare subito con il font di ripiego e viene sostituito quando arriva quello definitivo. Con optional il browser usa il font del sito solo se è disponibile quasi immediatamente, altrimenti mantiene quello di ripiego per tutta la visita e lo userà dalla successiva, quando sarà in cache.
Per la maggior parte dei siti swap è la scelta giusta, a patto di ridurre lo spostamento al momento del cambio. Si ottiene definendo un font di ripiego locale con metriche corrette, tramite i descrittori size-adjust, ascent-override e descent-override, così che occupi lo stesso spazio del font definitivo:
@font-face {
font-family: "Plex ripiego";
src: local("Arial");
size-adjust: 102%;
ascent-override: 98%;
descent-override: 26%;
}
body {
font-family: "IBM Plex Sans", "Plex ripiego", sans-serif;
}
I valori dipendono dalla coppia di font e vanno calcolati o verificati a vista; esistono strumenti che li ricavano automaticamente dalle metriche dei due caratteri.
Gli errori da evitare
- Togliere caratteri che servono. Virgolette tipografiche, apostrofo curvo, trattini, simbolo dell’euro e lettere accentate maiuscole sono spesso dimenticati: il browser li mostra con un altro font, con un effetto poco professionale.
- Eliminare le funzionalità tipografiche. Crenatura e legature fanno parte della qualità del testo: vanno mantenute esplicitamente, perché alcuni strumenti le rimuovono per impostazione predefinita.
- Dimenticare corsivi e grassetti. Se un peso o uno stile non viene dichiarato, il browser lo simula deformando il font regolare, con un risultato di qualità inferiore.
- Precaricare troppi file. Un preload per ogni variante trasforma un’ottimizzazione in un ostacolo per l’LCP.
- Ignorare la licenza. I font con licenza aperta, come la SIL Open Font License, permettono di modificarli e ospitarli; alcune licenze commerciali vietano subsetting o conversioni. Va verificato prima.
Come verificare il risultato
Nel pannello Network dei DevTools, filtrando per “Font”, si vedono quanti file vengono scaricati, quanto pesano, da quale dominio arrivano e in che momento partono: idealmente uno o due file leggeri, avviati subito dopo il documento. Lighthouse segnala il testo invisibile durante il caricamento dei font e i font non precaricati che bloccano l’LCP. Per l’effetto reale contano, come sempre, i dati degli utenti: LCP e CLS al 75° percentile, prima e dopo l’intervento, sulla finestra di 28 giorni di CrUX.
In sintesi
I font pesano sulle Web Performance per il loro peso, per la scoperta tardiva e per il comportamento durante l’attesa. Il subsetting riduce un font ai soli caratteri necessari e può tagliarne il peso del 90%; WOFF2, pochi pesi o un font variabile, l’hosting sul proprio dominio e un preload mirato completano il lavoro. Con font-display: swap e un font di ripiego dalle metriche allineate, il testo compare subito e non si sposta.
È un intervento che si fa una volta, in fase di sviluppo, e i cui benefici valgono per ogni pagina e ogni visita: meno kilobyte, testo leggibile prima e una pagina più stabile. Poco lavoro, per un risultato che gli utenti vedono subito.