Ridurre le dimensioni dei caratteri web

La tipografia è fondamentale per un buon design, il branding, la leggibilità e l'accessibilità. I caratteri web consentono tutto quanto sopra e altro ancora: il testo è selezionabile, ricercabile, ingrandibile e compatibile con DPI elevati, fornendo un rendering del testo nitido e coerente indipendentemente dalle dimensioni e dalla risoluzione dello schermo. I caratteri web sono fondamentali per un buon design, una buona UX e un buon rendimento.

L'ottimizzazione dei caratteri web è un elemento fondamentale della strategia di rendimento complessiva. Ogni carattere è una risorsa aggiuntiva e alcuni caratteri potrebbero bloccare il rendering del testo, ma il fatto che la pagina utilizzi caratteri web non significa che il rendering debba essere più lento. Al contrario, i caratteri ottimizzati, combinati con una strategia oculata per il caricamento e l'applicazione nella pagina, possono contribuire a ridurre le dimensioni totali della pagina e a migliorare i tempi di rendering.

Anatomia di un carattere web

Un carattere web è una raccolta di glifi e ogni glifo è una forma vettoriale che descrive una lettera o un simbolo. Di conseguenza, due semplici variabili determinano le dimensioni di un determinato file di caratteri: la complessità dei percorsi vettoriali di ogni glifo e il numero di glifi in un determinato carattere. Ad esempio, Open Sans, uno dei caratteri web più diffusi, contiene 897 glifi, tra cui caratteri latini, greci e cirillici.

Tabella dei glifi dei caratteri

Quando scegli un carattere, è importante considerare quali set di caratteri sono supportati. Se devi localizzare i contenuti della pagina in più lingue, devi utilizzare un carattere che possa offrire un aspetto e un'esperienza coerenti per i tuoi utenti. Ad esempio, la famiglia di caratteri Noto di Google mira a supportare tutte le lingue del mondo. Tieni presente, tuttavia, che le dimensioni totali di Noto, con tutte le lingue incluse, comportano un download ZIP di oltre 1,1 GB.

In questo post scoprirai come ridurre le dimensioni del file dei caratteri web pubblicati.

Formati dei caratteri web

Oggi sul web sono in uso due formati di container di caratteri consigliati:

WOFF e WOFF 2.0 sono ampiamente supportati e sono supportati da tutti i browser moderni.

  • Pubblica la variante WOFF 2.0 nei browser moderni.
  • Se è assolutamente necessario, ad esempio se devi ancora supportare Internet Explorer 11, pubblica WOFF come fallback.
  • In alternativa, valuta la possibilità di non utilizzare i caratteri web per i browser meno recenti e di utilizzare i caratteri di sistema. Questo potrebbe essere più efficiente anche per i dispositivi meno recenti e più limitati.
  • Poiché WOFF e WOFF 2.0 coprono tutte le basi per i browser moderni e meno recenti ancora in uso, l'utilizzo di EOT e TTF non è più necessario e può comportare tempi di download più lunghi dei caratteri web.

Caratteri web e compressione

Sia WOFF sia WOFF 2.0 hanno una compressione integrata. La compressione interna di WOFF 2.0 utilizza Brotli e offre una compressione fino al 30% migliore rispetto a WOFF. Per saperne di più, consulta il report di valutazione di WOFF 2.0.

Infine, è importante notare che alcuni formati di caratteri contengono metadati aggiuntivi, come informazioni sull'hinting dei caratteri e sul kerning, che potrebbero non essere necessari su alcune piattaforme, il che consente un'ulteriore ottimizzazione delle dimensioni dei file. Ad esempio, Google Fonts gestisce più di 30 varianti ottimizzate per ogni carattere e rileva e pubblica automaticamente la variante ottimale per ogni piattaforma e browser.

Definire una famiglia di caratteri con @font-face

La regola CSS @font-face consente di definire la posizione di una determinata risorsa di caratteri, le relative caratteristiche di stile e i punti di codice Unicode per cui deve essere utilizzata. È possibile utilizzare una combinazione di queste dichiarazioni @font-face per creare una "famiglia di caratteri", che il browser utilizzerà per valutare quali risorse di caratteri devono essere scaricate e applicate alla pagina corrente.

Valuta la possibilità di utilizzare un carattere variabile

I caratteri variabili possono ridurre significativamente le dimensioni dei file dei caratteri nei casi in cui sono necessarie più varianti di un carattere. Anziché dover caricare gli stili normale e grassetto, oltre alle relative versioni in corsivo, puoi caricare un singolo file contenente tutte le informazioni. Tuttavia, le dimensioni dei file dei caratteri variabili saranno maggiori di quelle di una singola variante di carattere, ma inferiori alla combinazione di molte varianti. Anziché un unico carattere variabile di grandi dimensioni, potrebbe essere preferibile pubblicare prima le varianti di caratteri critiche e scaricare le altre in un secondo momento.

I caratteri variabili sono ora supportati da tutti i browser moderni. Per saperne di più, consulta l'articolo Introduzione ai caratteri variabili sul web.

Selezionare il formato corretto

Ogni dichiarazione @font-face fornisce il nome della famiglia di caratteri, che funge da gruppo logico di più dichiarazioni, le proprietà dei caratteri come stile, spessore e allungamento e il descrittore src, che specifica un elenco prioritario di posizioni per la risorsa di caratteri.

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: local('Awesome Font'),
       url('/fonts/awesome.woff2') format('woff2'),
       /* Only serve WOFF if necessary. Otherwise,
          WOFF 2.0 is fine by itself. */
       url('/fonts/awesome.woff') format('woff');
}

@font-face {
  font-family: 'Awesome Font';
  font-style: italic;
  font-weight: 400;
  src: local('Awesome Font Italic'),
       url('/fonts/awesome-i.woff2') format('woff2'),
       url('/fonts/awesome-i.woff') format('woff');
}

Innanzitutto, tieni presente che gli esempi precedenti definiscono una singola famiglia Awesome Font con due stili (normale e corsivo), ognuno dei quali rimanda a un insieme diverso di risorse di caratteri. A sua volta, ogni descrittore src contiene un elenco prioritario di varianti di risorse separate da virgole:

  • La direttiva local() consente di fare riferimento, caricare e utilizzare i caratteri installati localmente. Se l'utente ha già installato il carattere sul proprio sistema, la rete viene completamente ignorata ed è la soluzione più veloce.
  • La direttiva url() consente di caricare caratteri esterni e può contenere un hint format() facoltativo che indica il formato del carattere a cui fa riferimento l'URL fornito.

Quando il browser determina che il carattere è necessario, scorre l'elenco delle risorse fornite nell'ordine specificato e tenta di caricare la risorsa appropriata. Ad esempio, seguendo l'esempio precedente:

  1. Il browser esegue il layout della pagina e determina quali varianti di caratteri sono necessarie per eseguire il rendering del testo specificato nella pagina. I caratteri che non fanno parte del modello a oggetti CSS (CSSOM) della pagina non vengono scaricati dal browser, perché non sono necessari.
  2. Per ogni carattere richiesto, il browser verifica se il carattere è disponibile localmente.
  3. Se il carattere non è disponibile localmente, il browser scorre le definizioni esterne:
    • Se è presente un hint di formato, il browser verifica se lo supporta prima di avviare il download. Se il browser non supporta l'hint, passa al successivo.
    • Se non è presente alcun hint di formato, il browser scarica la risorsa.

La combinazione di direttive locali ed esterne con hint di formato appropriati consente di specificare tutti i formati di caratteri disponibili e lasciare che il browser gestisca il resto. Il browser determina quali risorse sono necessarie e seleziona il formato ottimale.

Suddivisione in sottoinsiemi di intervalli Unicode

Oltre alle proprietà dei caratteri come stile, spessore e allungamento, la regola @font-face consente di definire un insieme di punti di codice Unicode supportati da ogni risorsa. In questo modo, puoi suddividere un carattere Unicode di grandi dimensioni in sottoinsiemi più piccoli (ad esempio, sottoinsiemi latini, cirillici e greci) e scaricare solo i glifi necessari per eseguire il rendering del testo in una determinata pagina.

Il descrittore unicode-range consente di specificare un elenco di valori di intervallo separati da virgole, ognuno dei quali può essere in una delle tre forme seguenti:

  • Punto di codice singolo (ad esempio, U+416)
  • Intervallo (ad esempio, U+400-4ff): indica i punti di codice di inizio e fine di un intervallo
  • Intervallo con caratteri jolly (ad esempio, U+4??): i caratteri ? indicano qualsiasi cifra esadecimale

Ad esempio, puoi suddividere la famiglia Awesome Font in sottoinsiemi latini e giapponesi, ognuno dei quali viene scaricato dal browser in base alle esigenze:

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: local('Awesome Font'),
       url('/fonts/awesome-l.woff2') format('woff2');
  /* Latin glyphs */
  unicode-range: U+000-5FF;
}

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: local('Awesome Font'),
       url('/fonts/awesome-jp.woff2') format('woff2');
  /* Japanese glyphs */
  unicode-range: U+3000-9FFF, U+ff??;
}

L'utilizzo di sottoinsiemi di intervalli Unicode e di file separati per ogni variante stilistica del carattere consente di definire una famiglia di caratteri composita più veloce ed efficiente da scaricare. I visitatori scaricano solo le varianti e i sottoinsiemi di cui hanno bisogno e non sono costretti a scaricare sottoinsiemi che potrebbero non vedere o utilizzare mai nella pagina.

Quasi tutti i browser supportano unicode-range. Per la compatibilità con i browser meno recenti, potrebbe essere necessario utilizzare la "suddivisione in sottoinsiemi manuale". In questo caso, devi fornire una singola risorsa di caratteri che contenga tutti i sottoinsiemi necessari e nascondere il resto al browser. Ad esempio, se la pagina utilizza solo caratteri latini, puoi rimuovere altri glifi e pubblicare quel particolare sottoinsieme come risorsa autonoma.

  1. Determina quali sottoinsiemi sono necessari:
    • Se il browser supporta la suddivisione in sottoinsiemi di intervalli Unicode, selezionerà automaticamente il sottoinsieme corretto. La pagina deve solo fornire i file dei sottoinsiemi e specificare gli intervalli Unicode appropriati nelle regole @font-face.
    • Se il browser non supporta la suddivisione in sottoinsiemi di intervalli Unicode, la pagina deve nascondere tutti i sottoinsiemi non necessari, ovvero lo sviluppatore deve specificare i sottoinsiemi richiesti.
  2. Genera sottoinsiemi di caratteri:
    • Utilizza lo strumento open source pyftsubset per suddividere in sottoinsiemi e ottimizzare i caratteri.
    • Alcuni server di caratteri, come Google Fonts, eseguono automaticamente la suddivisione in sottoinsiemi per impostazione predefinita.
    • Alcuni servizi di caratteri consentono la suddivisione in sottoinsiemi manuale tramite parametri di query personalizzati, che puoi utilizzare per specificare manualmente il sottoinsieme richiesto per la tua pagina. Consulta la documentazione del tuo fornitore di caratteri.

Selezione e sintesi dei caratteri

Ogni famiglia di caratteri può essere composta da più varianti stilistiche (normale, grassetto, corsivo) e più spessori per ogni stile. Ognuna delle quali, a sua volta, può contenere forme di glifi molto diverse, ad esempio spaziatura, dimensioni o una forma completamente diversa.

Spessori dei caratteri

Il diagramma precedente illustra una famiglia di caratteri che offre tre diversi spessori in grassetto:

  • 400 (normale).
  • 700 (grassetto).
  • 900 (grassetto extra).

Tutte le altre varianti intermedie (indicate in grigio) vengono mappate automaticamente alla variante più vicina dal browser.

Quando viene specificato uno spessore per cui non esiste alcun carattere, viene utilizzato un carattere con uno spessore simile. In generale, gli spessori in grassetto vengono mappati ai caratteri con spessori maggiori e gli spessori leggeri vengono mappati ai caratteri con spessori minori.

CSS font matching algorithm

Una logica simile si applica alle varianti corsive. Il progettista del carattere controlla quali varianti produrrà e tu controlli quali varianti utilizzerai nella pagina. Poiché ogni variante è un download separato, è consigliabile mantenere basso il numero di varianti. Ad esempio, puoi definire due varianti in grassetto per la famiglia Awesome Font:

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: local('Awesome Font'),
       url('/fonts/awesome-l.woff2') format('woff2');
  /* Latin glyphs */
  unicode-range: U+000-5FF;
}

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 700;
  src: local('Awesome Font'),
       url('/fonts/awesome-l-700.woff2') format('woff2');
  /* Latin glyphs */
  unicode-range: U+000-5FF;
}

L'esempio precedente dichiara la famiglia Awesome Font composta da due risorse che coprono lo stesso insieme di glifi latini (U+000-5FF) ma offrono due "spessori" diversi: normale (400) e grassetto (700). Tuttavia, cosa succede se una delle tue regole CSS specifica uno spessore del carattere diverso o imposta la proprietà font-style su italic?

  • Se non è disponibile una corrispondenza esatta del carattere, il browser sostituisce la corrispondenza più vicina.
  • Se non viene trovata alcuna corrispondenza stilistica (ad esempio, nell'esempio precedente non sono state dichiarate varianti in corsivo), il browser sintetizza la propria variante di carattere.
Sintesi dei caratteri

L'esempio precedente illustra la differenza tra i risultati dei caratteri effettivi e sintetizzati per Open Sans. Tutte le varianti sintetizzate vengono generate da un singolo carattere con spessore 400. Come puoi vedere, c'è una differenza notevole nei risultati. I dettagli su come generare le varianti in grassetto e in obliquo non sono specificati. Pertanto, i risultati variano da browser a browser e dipendono molto dal carattere.

Elenco di controllo per l'ottimizzazione delle dimensioni dei caratteri web

  • Controlla e monitora l'utilizzo dei caratteri: non utilizzare troppi caratteri nelle pagine e, per ogni carattere, riduci al minimo il numero di varianti utilizzate. In questo modo, l'esperienza degli utenti sarà più coerente e veloce.
  • Se possibile, evita i formati meno recenti: i formati EOT, TTF e WOFF sono più grandi di WOFF 2.0. I formati EOT e TTF sono strettamente inutili, mentre WOFF potrebbe essere accettabile se devi supportare Internet Explorer 11. Se hai come target solo i browser moderni, l'utilizzo solo di WOFF 2.0 è l'opzione più semplice ed efficiente.
  • Suddividi in sottoinsiemi le risorse dei caratteri: molti caratteri possono essere suddivisi in sottoinsiemi o suddivisi in più intervalli Unicode per pubblicare solo i glifi richiesti da una determinata pagina. In questo modo si riducono le dimensioni del file e si migliora la velocità di download della risorsa. Tuttavia, quando definisci i sottoinsiemi, fai attenzione a ottimizzare il riutilizzo dei caratteri. Ad esempio, non scaricare un insieme di caratteri diverso ma sovrapposto su ogni pagina. Una buona pratica è la suddivisione in sottoinsiemi in base allo script, ad esempio latino e cirillico.
  • Dai la precedenza a local() nell'elenco src: se elenchi local('Font Name') per primo nell'elenco src, ti assicuri che non vengano effettuate richieste HTTP per i caratteri già installati.
  • Utilizza Lighthouse per verificare la compressione del testo.

Effetti su Largest Contentful Paint (LCP) e Cumulative Layout Shift (CLS)

A seconda dei contenuti della pagina, i nodi di testo possono essere considerati candidati per Largest Contentful Paint (LCP). È quindi fondamentale assicurarsi che i caratteri web siano il più piccoli possibile seguendo i consigli riportati in questo articolo, in modo che gli utenti vedano il testo della pagina il prima possibile.

Se temi che, nonostante i tuoi sforzi di ottimizzazione, il testo della pagina possa impiegare troppo tempo a essere visualizzato a causa delle dimensioni elevate della risorsa di caratteri web, la proprietà font-display ha una serie di impostazioni che possono aiutarti a evitare il testo invisibile durante il download di un carattere. Tuttavia, l'utilizzo del valore swap potrebbe causare spostamenti di layout significativi che influiscono su Cumulative Layout Shift (CLS) del tuo sito. Se possibile, valuta la possibilità di utilizzare i valori optional o fallback.

Se i caratteri web sono fondamentali per il tuo branding e, di conseguenza, per l'esperienza utente, valuta la possibilità di precaricare i caratteri in modo che il browser abbia un vantaggio nella richiesta. In questo modo, puoi ridurre sia il periodo di scambio se utilizzi font-display: swap sia il periodo di blocco se non utilizzi font-display.