Usare la tipografia avanzata con i caratteri locali

Scopri come l'API Local Font Access ti consente di accedere ai caratteri installati localmente dall'utente e di ottenere dettagli di basso livello su di essi.

Caratteri sicuri per il web

Se ti occupi di sviluppo web da tempo, forse ricorderai i cosiddetti font sicuri per il web. Questi caratteri sono noti per essere disponibili in quasi tutte le istanze dei sistemi operativi più utilizzati (ovvero Windows, macOS, le distribuzioni Linux più comuni, Android e iOS). Nei primi anni 2000, Microsoft ha persino lanciato un'iniziativa chiamata TrueType core fonts for the Web, che forniva questi caratteri per il download senza costi con l'obiettivo che "ogni volta che visiti un sito web che li specifica, vedrai le pagine esattamente come le ha pensate il progettista del sito". Sì, sono inclusi i siti impostati in Comic Sans MS. Ecco un classico stack di caratteri sicuri per il web (con il fallback finale di qualsiasi carattere sans-serif) potrebbe avere questo aspetto:

body {
  font-family: Helvetica, Arial, sans-serif;
}

Caratteri web

I tempi in cui i caratteri sicuri per il web erano davvero importanti sono finiti da un pezzo. Oggi abbiamo font web, alcuni dei quali sono addirittura font variabili che possiamo modificare ulteriormente cambiando i valori dei vari assi esposti. Puoi utilizzare i caratteri web dichiarando un blocco @font-face all'inizio del CSS, che specifica i file dei caratteri da scaricare:

@font-face {
  font-family: 'FlamboyantSansSerif';
  src: url('flamboyant.woff2');
}

Dopodiché, puoi utilizzare il carattere web personalizzato specificando font-family, come di consueto:

body {
  font-family: 'FlamboyantSansSerif';
}

Caratteri locali come vettore di impronta

La maggior parte dei caratteri web proviene dal web. Un fatto interessante, però, è che la proprietà src nella dichiarazione @font-face, oltre alla funzione url(), accetta anche una funzione local(). Ciò consente di caricare i caratteri personalizzati (sorpresa!) localmente. Se l'utente ha FlamboyantSansSerif installato sul sistema operativo, verrà utilizzata la copia locale anziché il download:

@font-face {
  font-family: 'FlamboyantSansSerif';
  src: local('FlamboyantSansSerif'), url('flamboyant.woff2');
}

Questo approccio fornisce un buon meccanismo di fallback che potenzialmente consente di risparmiare larghezza di banda. Su internet, purtroppo non possiamo avere cose belle. Il problema con la funzione local() è che può essere utilizzata in modo improprio per il fingerprinting del browser. Si è scoperto che l'elenco dei caratteri installati da un utente può essere piuttosto identificativo. Molte aziende hanno i propri caratteri aziendali installati sui laptop dei dipendenti. Ad esempio, Google ha un carattere aziendale chiamato Google Sans.

L'app Font Book di macOS che mostra un'anteprima del carattere Google Sans.
Il carattere Google Sans installato sul laptop di un dipendente Google.

Un malintenzionato può tentare di determinare per quale società lavora una persona verificando l'esistenza di un gran numero di caratteri aziendali noti come Google Sans. L'autore dell'attacco tenterebbe di eseguire il rendering del testo impostato in questi caratteri su un canvas e misurare i glifi. Se i glifi corrispondono alla forma nota del carattere aziendale, l'attaccante ha ottenuto un risultato. Se i glifi non corrispondono, l'autore dell'attacco sa che è stato utilizzato un carattere di sostituzione predefinito perché il carattere aziendale non è stato installato. Per informazioni dettagliate su questo e altri attacchi di fingerprinting del browser, leggi l'articolo di ricerca di Laperdix e altri.

A parte i caratteri aziendali, anche solo l'elenco dei caratteri installati può essere identificativo. La situazione con questo vettore di attacco è diventata così grave che di recente il team di WebKit ha deciso di "includere [nell'elenco dei caratteri disponibili] solo i caratteri web e quelli forniti con il sistema operativo, ma non i caratteri installati localmente dall'utente". (Ed eccomi qui, con un articolo sulla concessione dell'accesso ai caratteri locali.)

API Local Font Access

L'inizio di questo articolo potrebbe averti messo di cattivo umore. Non possiamo davvero avere cose belle? Non preoccuparti. Pensiamo di sì e forse non tutto è perduto. Ma prima, rispondo a una domanda che potresti farti.

Perché abbiamo bisogno dell'API Local Font Access quando esistono i caratteri web?

Gli strumenti di progettazione e grafica di qualità professionale sono sempre stati difficili da fornire sul web. Un ostacolo è stato l'impossibilità di accedere e utilizzare l'intera gamma di caratteri creati e suggeriti a livello professionale che i designer hanno installato localmente. I caratteri web consentono alcuni casi d'uso di pubblicazione, ma non consentono l'accesso programmatico alle forme dei glifi vettoriali e alle tabelle dei caratteri utilizzate dai rasterizzatori per eseguire il rendering dei contorni dei glifi. Allo stesso modo, non è possibile accedere ai dati binari di un carattere web.

  • Gli strumenti di progettazione devono accedere ai byte dei caratteri per eseguire la propria implementazione del layout OpenType e consentire agli strumenti di progettazione di agganciarsi a livelli inferiori, per azioni come l'esecuzione di filtri vettoriali o trasformazioni sulle forme dei glifi.
  • Gli sviluppatori potrebbero avere stack di caratteri legacy per le loro applicazioni che stanno portando sul web. Per utilizzare questi stack, in genere è necessario l'accesso diretto ai dati dei caratteri, cosa che i web font non forniscono.
  • Alcuni caratteri potrebbero non essere concessi in licenza per la distribuzione sul web. Ad esempio, Linotype ha una licenza per alcuni caratteri che include solo l'utilizzo desktop.

L'API Local Font Access è un tentativo di risolvere queste sfide. È composto da due parti:

  • Un'API di enumerazione dei caratteri, che consente agli utenti di concedere l'accesso all'intero set di caratteri di sistema disponibili.
  • Da ogni risultato di enumerazione, la possibilità di richiedere l'accesso al contenitore SFNT di basso livello (orientato ai byte) che include i dati completi del carattere.

Supporto browser

Browser Support

  • Chrome: 103.
  • Edge: 103.
  • Firefox: not supported.
  • Safari: not supported.

Source

Come utilizzare l'API Local Font Access

Rilevamento delle funzionalità

Per verificare se l'API Local Font Access è supportata, utilizza:

if ('queryLocalFonts' in window) {
  // The Local Font Access API is supported
}

Enumerazione dei caratteri locali

Per ottenere un elenco dei caratteri installati localmente, devi chiamare window.queryLocalFonts(). La prima volta, verrà visualizzata una richiesta di autorizzazione che l'utente può approvare o negare. Se l'utente approva l'interrogazione dei caratteri locali, il browser restituirà un array con i dati dei caratteri su cui puoi eseguire un ciclo. Ogni carattere è rappresentato come un oggetto FontData con le proprietà family (ad esempio, "Comic Sans MS"), fullName (ad esempio, "Comic Sans MS"), postscriptName (ad esempio, "ComicSansMS") e style (ad esempio, "Regular").

// Query for all available fonts and log metadata.
try {
  const availableFonts = await window.queryLocalFonts();
  for (const fontData of availableFonts) {
    console.log(fontData.postscriptName);
    console.log(fontData.fullName);
    console.log(fontData.family);
    console.log(fontData.style);
  }
} catch (err) {
  console.error(err.name, err.message);
}

Se ti interessa solo un sottoinsieme di caratteri, puoi anche filtrarli in base ai nomi PostScript aggiungendo un parametro postscriptNames.

const availableFonts = await window.queryLocalFonts({
  postscriptNames: ['Verdana', 'Verdana-Bold', 'Verdana-Italic'],
});

Accesso ai dati SFNT

L'accesso completo a SFNT è disponibile tramite il metodo blob() dell'oggetto FontData. SFNT è un formato di file dei caratteri che può contenere altri caratteri, come PostScript, TrueType, OpenType, Web Open Font Format (WOFF) e altri.

try {
  const availableFonts = await window.queryLocalFonts({
    postscriptNames: ['ComicSansMS'],
  });
  for (const fontData of availableFonts) {
    // `blob()` returns a Blob containing valid and complete
    // SFNT-wrapped font data.
    const sfnt = await fontData.blob();
    // Slice out only the bytes we need: the first 4 bytes are the SFNT
    // version info.
    // Spec: https://docs.microsoft.com/en-us/typography/opentype/spec/otff#organization-of-an-opentype-font
    const sfntVersion = await sfnt.slice(0, 4).text();

    let outlineFormat = 'UNKNOWN';
    switch (sfntVersion) {
      case '\x00\x01\x00\x00':
      case 'true':
      case 'typ1':
        outlineFormat = 'truetype';
        break;
      case 'OTTO':
        outlineFormat = 'cff';
        break;
    }
    console.log('Outline format:', outlineFormat);
  }
} catch (err) {
  console.error(err.name, err.message);
}

Demo

Puoi vedere l'API Local Font Access in azione nella demo. Assicurati di controllare anche il codice sorgente. La demo mostra un elemento personalizzato chiamato <font-select> che implementa un selettore di caratteri locali.

Considerazioni sulla privacy

L'autorizzazione "local-fonts" sembra fornire una superficie altamente identificabile. Tuttavia, i browser sono liberi di restituire qualsiasi cosa. Ad esempio, i browser incentrati sull'anonimato potrebbero scegliere di fornire solo un insieme di caratteri predefiniti integrati nel browser. Analogamente, i browser non sono tenuti a fornire i dati delle tabelle esattamente come appaiono sul disco.

Ove possibile, l'API Local Font Access è progettata per esporre solo le informazioni necessarie per attivare i casi d'uso menzionati. Le API di sistema potrebbero produrre un elenco di caratteri installati non in un ordine casuale o ordinato, ma nell'ordine di installazione dei caratteri. Restituire esattamente l'elenco dei caratteri installati fornito da un'API di sistema di questo tipo può esporre dati aggiuntivi che possono essere utilizzati per l'impronta digitale e i casi d'uso che vogliamo attivare non sono supportati dal mantenimento di questo ordine. Di conseguenza, questa API richiede che i dati restituiti vengano ordinati prima di essere restituiti.

Sicurezza e autorizzazioni

Il team di Chrome ha progettato e implementato l'API Local Font Access utilizzando i principi fondamentali definiti in Controlling Access to Powerful Web Platform Features, tra cui controllo utente, trasparenza ed ergonomia.

Controllo utente

L'accesso ai caratteri di un utente è completamente sotto il suo controllo e non sarà consentito a meno che non venga concessa l'autorizzazione "local-fonts", come elencato nel registro delle autorizzazioni.

Trasparenza

Se a un sito è stato concesso l'accesso ai caratteri locali dell'utente, sarà visibile nella scheda delle informazioni del sito.

Persistenza delle autorizzazioni

L'autorizzazione "local-fonts" verrà mantenuta tra i ricaricamenti della pagina. Può essere revocato tramite il foglio Informazioni sito.

Feedback

Il team di Chrome vuole conoscere le tue esperienze con l'API Local Font Access.

Descrivi la progettazione dell'API

C'è qualcosa nell'API che non funziona come previsto? Oppure mancano metodi o proprietà che ti servono per implementare la tua idea? Hai una domanda o un commento sul modello di sicurezza? Segnala un problema relativo alle specifiche nel repository GitHub corrispondente o aggiungi i tuoi commenti a un problema esistente.

Segnalare un problema relativo all'implementazione

Hai trovato un bug nell'implementazione di Chrome? L'implementazione è diversa dalla specifica? Segnala un bug all'indirizzo new.crbug.com. Assicurati di includere il maggior numero possibile di dettagli, istruzioni semplici per la riproduzione e inserisci Blink>Storage>FontAccess nella casella Componenti.

Mostra il tuo sostegno all'API

Intendi utilizzare l'API Local Font Access? Il tuo supporto pubblico aiuta il team di Chrome a dare la priorità alle funzionalità e mostra ad altri fornitori di browser quanto sia fondamentale supportarle.

Invia un tweet a @ChromiumDev utilizzando l'hashtag #LocalFontAccess e facci sapere dove e come lo utilizzi.

Ringraziamenti

La specifica dell'API Local Font Access è stata modificata da Emil A. Eklund, Alex Russell, Joshua Bell e Olivier Yiptong. Questo articolo è stato rivisto da Joe Medley, Dominik Röttsches e Olivier Yiptong. Immagine promozionale di Brett Jordan su Unsplash.