Subsetting dei font e miglioramento delle Web Performance

Ridurre un font ai soli caratteri che servono può tagliarne il peso del 90%: che cos’è il subsetting, come si fa con pyftsubset, come caricare i font e come evitare testo invisibile e spostamenti.

La griglia dei 6.253 glifi di un font completo in WOFF2 da 252 KB, di cui solo un piccolo gruppo evidenziato in verde, e accanto il sottoinsieme latino con le lettere Aa, le vocali accentate, le virgolette e l’euro in 24 KB, il 90% in meno

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 blocchi di caratteri di un font completo, DejaVu Sans con 6.253 glifi: si tengono latino di base, Latino-1, punteggiatura e simboli di valuta, si eliminano latino esteso, greco, cirillico, armeno, ebraico, georgiano, lao, frecce, simboli matematici, riquadri e braille; il file passa da 742 KB in TTF e 252 KB in WOFF2 a 24 KB con il sottoinsieme latino e 15 KB con i soli caratteri dell’italiano
Misure reali su DejaVu Sans: dal WOFF2 completo al sottoinsieme latino il file perde il 90% del peso.

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.

Due waterfall a confronto: con un servizio esterno il browser scarica l’HTML, apre una connessione per il CSS dei font, scarica il CSS, apre una seconda connessione e solo allora il file del font, così il testo compare con il font del sito dopo circa 1,25 secondi; con il font sottoinsieme sullo stesso dominio e precaricato, il file parte insieme al CSS del sito e il testo compare dopo circa 0,55 secondi
Meno connessioni e un file più piccolo annunciato subito: il testo definitivo arriva molto prima.
<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.

Tre righe temporali per un font che arriva dopo 1,2 secondi: con font-display block il testo è invisibile fino a quel momento, con swap compare subito con il font di ripiego e poi cambia con possibile spostamento, con optional resta il font di ripiego per tutta la visita e il font del sito verrà usato dalla visita successiva
block nasconde il testo, swap lo mostra subito ma può spostarlo, optional non lo cambia mai durante la visita.

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.

IL PROSSIMO PASSO

Partiamo
dal tuo sito.

Raccontaci il progetto, i problemi che riscontri e i tuoi obiettivi. Definiremo insieme un intervento su misura.

Richiedi un’analisi

Ti porta al modulo della pagina Contatti.

MANAGED SERVER S.R.L.info@corewebvitals.it +39 02 5656 9681

Lunedì – venerdì · 09:30 – 19:30

Preferisci un modulo online?
Contattaci su managedserver.it ↗