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.

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
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.
Link utili
- Explainer
- Spec draft
- Bug di Chromium per l'enumerazione dei caratteri
- Bug di Chromium per l'accesso alla tabella dei caratteri
- Voce di ChromeStatus
- Repository GitHub
- Revisione del TAG
- Posizione di Mozilla sugli standard
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.