System Font: quando le performance incontrano l'accessibilità
Spesso, quando iniziamo a immaginare il design di un nuovo progetto web, la prima cosa che facciamo è perderci nelle infinite librerie di font. Cerchiamo quel carattere unico, particolare, capace di dare “personalità” al brand. È una fase creativa bellissima, non lo nego. Tuttavia l’attenzione che dobbiamo alle performance ci porta a una domanda scomoda: quanto ci costa, in termini di velocità e usabilità, questa scelta estetica?
Oggi vorrei parlarti di un ritorno alle origini che sta diventando sempre più una scelta consapevole e tecnicamente avanzata: l’uso dei Font di Sistema.
Che cosa sono i Font di Sistema (e perché mi piacciono)
I font di sistema sono quelli già preinstallati nel dispositivo che stai usando per leggere questo articolo, sia esso un Mac, un PC Windows, Linux, un iPhone o un Android. Non devono essere scaricati dal web: sono già lì, pronti all’uso.
Recentemente ho approfondito una risorsa preziosissima che si chiama Modern Font Stack. Questo sito ha fatto un lavoro di categorizzazione eccellente, organizzando i font di sistema non per nome, ma per stile tipografico, fornendo delle stringhe CSS, dei font stack, pronti da copiare.
Ecco un esempio di come appare uno stack Neo-Grotesque (ottimo per un look pulito e moderno):
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
È uno strumento fantastico, ma va usato cum grano salis. Tra gli stack proposti, infatti, ce ne sono alcuni come l’Handwritten (simil-scrittura a mano) che, per quanto tecnicamente “di sistema”, presentano enormi problemi di leggibilità. E sappiamo bene che se un testo non è leggibile, non è accessibile. La leggibilità deve venire sempre prima dello stile.
I numeri della velocità: Google Fonts vs System Fonts
Per capire l’impatto reale di questa scelta, dobbiamo guardare i numeri. Le performance non sono un’opinione.
Quando colleghiamo un font esterno, ad esempio da Google Fonts, il browser deve compiere una serie di azioni bloccanti: risolvere il DNS, stabilire una connessione TCP, eseguire l’handshake TLS e infine scaricare il file.
Parliamo di dati concreti:
- Font esterno: Può aggiungere dai 100ms ai 500ms al tempo di caricamento (FCP), a seconda della latenza della rete. Inoltre, un singolo stile di un font (es. Regular o Italic) può pesare tra i 20kb e i 50kb. Se carichi Regular, Bold e Italic, arrivi facilmente a 150kb di dati extra.
- Font di sistema: Tempo di caricamento 0ms. Peso 0kb. Nessuna richiesta al server.
Questi millisecondi di attesa si traducono in due comportamenti che l’utente percepisce direttamente. Il primo è il FOIT (Flash of Invisible Text): il browser nasconde il testo finché il font non è pronto, lasciando la pagina apparentemente vuota. Il secondo è il FOUT (Flash of Unstyled Text): il testo appare subito con un font di sistema e poi “salta” visivamente quando il font personalizzato viene caricato. Capire questa distinzione è fondamentale per scegliere la strategia giusta.
La performance è la prima forma di accessibilità
Qui arriviamo al punto cruciale. Spesso pensiamo all’accessibilità solo come contrasto colori o supporto agli screen reader. Ma esiste una forma di accessibilità legata alle infrastrutture.
Alleggerire il sito eliminando il peso dei font esterni significa renderlo fruibile anche a chi naviga con connessioni lente (pensa a un 3G in treno), dispositivi datati o piani dati limitati. Un sito che si carica istantaneamente è un sito democratico, che rispetta il tempo e le risorse dell’utente. Ne volete di più? Grande aiuto per i Core Web Vitals, in particolare per il First Contentful Paint (FCP) e il Largest Contentful Paint (LCP).
La strategia ibrida: il compromesso intelligente
Naturalmente, capisco le esigenze di branding. A volte un font specifico è necessario per veicolare l’identità visiva del progetto. In questi casi, la soluzione non è rinunciare a tutto, ma adottare una strategia ibrida:
- Titoli: utilizziamo il font personalizzato (Web Font); essendo testi brevi e grandi, l’impatto sul peso è contenuto e l’effetto visivo è garantito
- Corpo del testo: utilizziamo uno stack di sistema, garantendo che la gran parte del testo sia leggibile immediatamente
Ottimizzare i Web Vitals nella strategia ibrida
Se decidiamo di caricare font esterni per i titoli, dobbiamo farlo proteggendo i Core Web Vitals, come già accennato, in particolare il Cumulative Layout Shift (CLS).
Ecco la mia checklist per un’implementazione robusta:
1. Scegli font-display con criterio
font-display: swap dice al browser di mostrare subito il testo con un font di sistema (evitando il FOIT) e di sostituirlo con quello personalizzato appena è pronto. È un buon punto di partenza, ma non è sempre la scelta migliore.
Se la connessione è lenta e il font arriva tardi, lo swap genera un layout shift visibile che penalizza il CLS. In produzione vale la pena valutare font-display: optional: il browser tenta di caricare il font solo se già presente in cache, altrimenti usa direttamente il fallback — zero layout shift garantito, a costo di non mostrare il font al primo accesso.
/* Buono per UX fluida, può causare CLS su connessioni lente */
font-display: swap;
/* Ottimo per CLS, il font custom appare solo se già in cache */
font-display: optional;
La scelta dipende dalla priorità: se il font è parte integrante del brand, usa swap; se la stabilità del layout viene prima, usa optional.
2. Formato WOFF2 e Self-Hosting
Ospita i font sul tuo server (niente CDN esterne per risparmiare il tempo di lookup DNS) e usa esclusivamente il formato WOFF2, che offre una compressione superiore del 30% rispetto ai vecchi formati.
3. Evita il CLS con size-adjust
Il problema del swap è che se il font di sistema e quello personalizzato hanno dimensioni diverse, la pagina “salta” quando avviene il cambio. Possiamo mitigare questo effetto usando la proprietà size-adjust nel descrittore @font-face per calibrare il font fallback affinché occupi lo stesso spazio di quello finale.
size-adjust accetta una percentuale che scala il font fallback per farlo coincidere visivamente con quello custom. Il valore si trova empiricamente — strumenti come Fallback Font Generator lo calcolano in automatico — oppure a mano, confrontando le due versioni in sovrimpressione nel browser.
@font-face {
font-family: 'MioFontBrand-Fallback';
src: local('Arial');
size-adjust: 94%;
ascent-override: 90%;
descent-override: 22%;
}
h1, h2, h3 {
font-family: 'MioFontBrand', 'MioFontBrand-Fallback', Arial, sans-serif;
}
In questo modo, anche durante il periodo di caricamento, il testo occupa esattamente lo stesso spazio — il layout non si muove di un pixel.
4. Precarica i font con rel=“preload”
Questo punto è stato aggiunto dopo la pubblicazione originale, grazie a un commento di un lettore attento e fortissimo developer, Giovanni Invernizzi: grazie mille Giovanni!
Per default, il browser scopre un font solo quando ha finito di analizzare il CSS che lo referenzia — il che lo rende l’ultima risorsa nella catena di caricamento. Con l’attributo rel="preload" nel <head> puoi anticiparne il download e rimuoverlo dal percorso critico.
<link
rel="preload"
href="/fonts/mio-font-bold.woff2"
as="font"
type="font/woff2"
crossorigin
/>
Due dettagli che fanno la differenza: l’attributo crossorigin è obbligatorio anche per i font self-hosted, altrimenti il browser ignora il preload e scarica il font una seconda volta. Inoltre, ha senso precaricare solo i font usati above the fold, tipicamente il peso Regular e Bold del font dei titoli. Precaricare tutto il set di varianti annulla il vantaggio e genera richieste inutili che penalizzano le performance invece di migliorarle.
Scegliere i font di sistema, o usarli strategicamente, non significa rinunciare al design, ma abbracciare un’estetica funzionale che mette l’utente al centro. E credo che questa sia la vera essenza di un buon lavoro di sviluppo.
Peace&Love! ✌️