Conlaccento

A web making blog by Antonio Trifirò

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:

  1. Titoli: utilizziamo il font personalizzato (Web Font); essendo testi brevi e grandi, l’impatto sul peso è contenuto e l’effetto visivo è garantito
  2. 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! ✌️