Gebruik geavanceerde typografie met lokale lettertypen

Ontdek hoe u met de Local Font Access API toegang krijgt tot de lokaal geïnstalleerde lettertypen van de gebruiker en gedetailleerde informatie over deze lettertypen kunt verkrijgen

Webveilige lettertypen

Als je al lang genoeg bezig bent met webontwikkeling, herinner je je misschien de zogenaamde webveilige lettertypen . Deze lettertypen staan ​​erom bekend dat ze beschikbaar zijn op bijna alle meestgebruikte besturingssystemen (namelijk Windows, macOS, de meest voorkomende Linux-distributies, Android en iOS). Begin jaren 2000 stond Microsoft zelfs aan de wieg van een initiatief genaamd TrueType Core Fonts for the Web , dat deze lettertypen gratis downloadbaar maakte met als doel dat "wanneer je een website bezoekt die deze lettertypen specificeert, je pagina's precies ziet zoals de websiteontwerper het bedoeld heeft" . Ja, dit omvatte ook websites die in Comic Sans MS zijn gemaakt. Hier is een klassieke webveilige lettertypestapel (met als ultieme terugvaloptie elk sans-serif lettertype) die er zo uit zou kunnen zien:

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

Weblettertypen

De tijd dat webveilige lettertypen echt belangrijk waren, is allang voorbij. Tegenwoordig hebben we webfonts , waarvan sommige zelfs variabele lettertypen zijn die we verder kunnen aanpassen door de waarden voor de verschillende zichtbare assen te wijzigen. Je kunt webfonts gebruiken door een @font-face blok aan het begin van de CSS te declareren, dat de te downloaden lettertypebestanden specificeert:

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

Hierna kunt u het aangepaste weblettertype gebruiken door de font-family op de gebruikelijke manier op te geven:

body {
  font-family: 'FlamboyantSansSerif';
}

Lokale lettertypen als vingerafdrukvector

De meeste webfonts komen van, nou ja, het web. Interessant is echter dat de src eigenschap in de @font-face -declaratie, naast de url() functie, ook een local() functie accepteert. Hierdoor kunnen aangepaste lettertypen (verrassing!) lokaal worden geladen. Als de gebruiker toevallig FlamboyantSansSerif op zijn of haar besturingssysteem heeft geïnstalleerd, wordt de lokale kopie gebruikt in plaats van gedownload:

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

Deze aanpak biedt een handig terugvalmechanisme dat mogelijk bandbreedte bespaart. Op internet kunnen we helaas geen leuke dingen hebben. Het probleem met de local() -functie is dat deze misbruikt kan worden voor browser-fingerprinting. Het blijkt dat de lijst met lettertypen die een gebruiker heeft geïnstalleerd, behoorlijk identificerend kan zijn. Veel bedrijven hebben hun eigen bedrijfslettertypen die op de laptops van medewerkers zijn geïnstalleerd. Google heeft bijvoorbeeld een bedrijfslettertype genaamd Google Sans .

De macOS Lettertypeboek-app toont een voorbeeld van het Google Sans-lettertype.
Het Google Sans-lettertype geïnstalleerd op de laptop van een Google-medewerker.

Een aanvaller kan proberen te bepalen voor welk bedrijf iemand werkt door te testen op het bestaan ​​van een groot aantal bekende bedrijfslettertypen, zoals Google Sans . De aanvaller probeert tekst in deze lettertypen op een canvas weer te geven en de tekens te meten. Als de tekens overeenkomen met de bekende vorm van het bedrijfslettertype, heeft de aanvaller succes. Als de tekens niet overeenkomen, weet de aanvaller dat er een standaard vervangend lettertype is gebruikt, aangezien het bedrijfslettertype niet is geïnstalleerd. Lees voor meer informatie over deze en andere browser fingerprinting-aanvallen het onderzoeksrapport van Laperdix et al.

Los van bedrijfslettertypen kan zelfs de lijst met geïnstalleerde lettertypen al identificerend zijn. De situatie met deze aanvalsmethode is zo ernstig geworden dat het WebKit-team onlangs heeft besloten om "[in de lijst met beschikbare lettertypen] alleen webfonts en lettertypen op te nemen die bij het besturingssysteem horen, maar geen lokaal door de gebruiker geïnstalleerde lettertypen" . (En hier ben ik dan, met een artikel over het verlenen van toegang tot lokale lettertypen.)

De lokale lettertypetoegangs-API

Het begin van dit artikel heeft je misschien in een negatieve stemming gebracht. Kunnen we echt geen leuke dingen hebben? Maak je geen zorgen. We denken van wel, en misschien is niet alles hopeloos . Maar laat me eerst een vraag beantwoorden die je jezelf misschien stelt.

Waarom hebben we de Local Font Access API nodig als er webfonts bestaan?

Professionele ontwerp- en grafische tools zijn historisch gezien moeilijk te leveren op het web. Een struikelblok is de onmogelijkheid om toegang te krijgen tot en gebruik te maken van de volledige variëteit aan professioneel ontworpen en gehint lettertypen die ontwerpers lokaal hebben geïnstalleerd. Webfonts maken sommige toepassingen voor publicatie mogelijk, maar bieden geen programmatische toegang tot de vectortekenvormen en lettertypetabellen die rasterizers gebruiken om de tekencontouren weer te geven. Er is ook geen manier om toegang te krijgen tot de binaire gegevens van een webfont.

  • Ontwerpgereedschappen hebben toegang nodig tot lettertypebytes om hun eigen OpenType-layoutimplementatie uit te voeren. Daarnaast moeten ontwerpgereedschappen op lagere niveaus kunnen inhaken voor acties zoals het uitvoeren van vectorfilters of transformaties op de tekenvormen.
  • Ontwikkelaars kunnen legacy font stacks hebben voor hun applicaties die ze online zetten. Om deze stacks te gebruiken, hebben ze meestal directe toegang tot lettertypegegevens nodig, iets wat webfonts niet bieden.
  • Voor sommige lettertypen is mogelijk geen licentie beschikbaar voor levering via internet. Linotype heeft bijvoorbeeld voor sommige lettertypen een licentie die alleen voor desktopgebruik geldt.

De Local Font Access API is een poging om deze uitdagingen op te lossen. Deze bestaat uit twee delen:

  • Een API voor het opsommen van lettertypen , waarmee gebruikers toegang kunnen verlenen tot de volledige set beschikbare systeemlettertypen.
  • Vanuit elk opsommingsresultaat is het mogelijk om toegang op laag niveau (byte-georiënteerd) tot de SFNT-container aan te vragen, inclusief de volledige lettertypegegevens.

Browserondersteuning

Browser Support

  • Chroom: 103.
  • Rand: 103.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

Source

Hoe de Local Font Access API te gebruiken

Functiedetectie

Om te controleren of de Local Font Access API wordt ondersteund, gebruikt u:

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

Lokale lettertypen opsommen

Om een ​​lijst met lokaal geïnstalleerde lettertypen te verkrijgen, moet u window.queryLocalFonts() aanroepen. De eerste keer dat dit gebeurt, wordt een toestemmingsprompt geactiveerd, die de gebruiker kan goedkeuren of weigeren. Als de gebruiker de query van zijn of haar lokale lettertypen goedkeurt, retourneert de browser een array met lettertypegegevens die u kunt doorlopen. Elk lettertype wordt weergegeven als een FontData object met de eigenschappen family (bijvoorbeeld "Comic Sans MS" ), fullName (bijvoorbeeld "Comic Sans MS" ), postscriptName (bijvoorbeeld "ComicSansMS" ) en style (bijvoorbeeld "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);
}

Als u alleen geïnteresseerd bent in een subset van lettertypen, kunt u deze ook filteren op basis van de PostScript-namen door de parameter postscriptNames toe te voegen.

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

Toegang tot SFNT-gegevens

Volledige SFNT- toegang is beschikbaar via de blob() -methode van het FontData object. SFNT is een lettertypebestandsindeling die andere lettertypen kan bevatten, zoals PostScript, TrueType, OpenType, Web Open Font Format (WOFF) en andere.

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);
}

Demonstratie

U kunt de Local Font Access API in actie zien in de onderstaande demo . Bekijk ook de broncode . De demo toont een aangepast element genaamd <font-select> dat een lokale lettertypekiezer implementeert.

Privacyoverwegingen

De toestemming "local-fonts" lijkt een zeer vingerafdrukgevoelig oppervlak te bieden. Browsers zijn echter vrij om te retourneren wat ze willen. Zo kunnen browsers die op anonimiteit zijn gericht ervoor kiezen om alleen een set standaardlettertypen te gebruiken die in de browser zijn ingebouwd. Evenmin zijn browsers verplicht om tabelgegevens exact te leveren zoals ze op schijf verschijnen.

Waar mogelijk is de Local Font Access API ontworpen om alleen exact de informatie te tonen die nodig is om de genoemde use cases mogelijk te maken. Systeem-API's kunnen een lijst met geïnstalleerde lettertypen niet in willekeurige of gesorteerde volgorde genereren, maar in de volgorde waarin het lettertype is geïnstalleerd. Het retourneren van exact de lijst met geïnstalleerde lettertypen die door een dergelijke systeem-API wordt gegeven, kan extra gegevens blootleggen die kunnen worden gebruikt voor vingerafdrukken. De use cases die we mogelijk willen maken, worden niet ondersteund door het behouden van deze volgorde. Daarom vereist deze API dat de geretourneerde gegevens worden gesorteerd voordat ze worden geretourneerd.

Beveiliging en machtigingen

Het Chrome-team heeft de Local Font Access API ontworpen en geïmplementeerd op basis van de kernprincipes die zijn gedefinieerd in Controlling Access to Powerful Web Platform Features , waaronder gebruikerscontrole, transparantie en ergonomie.

Gebruikerscontrole

De toegang tot de lettertypen van een gebruiker valt volledig onder diens controle en wordt niet verleend tenzij de machtiging "local-fonts" is verleend, zoals vermeld in het machtigingsregister .

Transparantie

Of een site toegang heeft gekregen tot de lokale lettertypen van de gebruiker, is zichtbaar in het informatieblad van de site .

Permissiepersistentie

De toestemming "local-fonts" blijft behouden tussen paginaherladingen. Deze kan worden ingetrokken via het informatieblad van de site .

Feedback

Het Chrome-team wil graag uw ervaringen met de Local Font Access API horen.

Vertel ons over het API-ontwerp

Werkt er iets aan de API dat niet werkt zoals je had verwacht? Of ontbreken er methoden of eigenschappen die je nodig hebt om je idee te implementeren? Heb je een vraag of opmerking over het beveiligingsmodel? Dien een spec-issue in op de betreffende GitHub-repository of voeg je mening toe aan een bestaand issue.

Meld een probleem met de implementatie

Heb je een bug gevonden in de implementatie van Chrome? Of wijkt de implementatie af van de specificatie? Meld een bug op new.crbug.com . Zorg ervoor dat je zoveel mogelijk details geeft, eenvoudige instructies voor het reproduceren en Blink>Storage>FontAccess invoert in het vak Componenten .

Toon ondersteuning voor de API

Bent u van plan de Local Font Access API te gebruiken? Uw publieke steun helpt het Chrome-team om functies te prioriteren en laat andere browserleveranciers zien hoe belangrijk het is om deze te ondersteunen.

Stuur een tweet naar @ChromiumDev met de hashtag #LocalFontAccess en laat ons weten waar en hoe je het gebruikt.

Dankbetuigingen

De Local Font Access API-specificatie is bewerkt door Emil A. Eklund , Alex Russell , Joshua Bell en Olivier Yiptong . Dit artikel is beoordeeld door Joe Medley , Dominik Röttsches en Olivier Yiptong . Hoofdafbeelding door Brett Jordan op Unsplash .