Erweiterte Typografie mit lokalen Schriftarten verwenden

Informationen dazu, wie Sie mit der Local Fonts Access API auf die lokal installierten Schriftarten des Nutzers zugreifen und Details dazu abrufen können

Websichere Schriftarten

Wenn Sie schon länger in der Webentwicklung tätig sind, erinnern Sie sich vielleicht an die sogenannten websicheren Schriftarten. Diese Schriftarten sind auf fast allen Instanzen der gängigsten Betriebssysteme verfügbar (Windows, macOS, die gängigsten Linux-Distributionen, Android und iOS). Anfang der 2000er Jahre hat Microsoft sogar eine Initiative namens TrueType-Kernschriften für das Web ins Leben gerufen, über die diese Schriftarten kostenlos heruntergeladen werden konnten. Ziel war es, dass Nutzer, die eine Website mit diesen Schriftarten besuchen, die Seiten genau so sehen, wie der Designer sie vorgesehen hat. Ja, dazu gehörten auch Websites, die in Comic Sans MS erstellt wurden. Hier ist ein klassischer Web-Safe-Schriftstapel (mit dem ultimativen Fallback auf die Schriftart sans-serif) als Beispiel:

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

Webschriften

Die Zeiten, in denen websichere Schriftarten wirklich wichtig waren, sind längst vorbei. Heute haben wir Webschriften, von denen einige sogar variable Schriftarten sind, die wir durch Ändern der Werte für die verschiedenen sichtbaren Achsen weiter anpassen können. Sie können Web-Schriftarten verwenden, indem Sie am Anfang des CSS-Codes einen Block @font-face deklarieren, in dem die herunterzuladenden Schriftdateien angegeben werden:

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

Anschließend können Sie die benutzerdefinierte Webschriftart verwenden, indem Sie wie gewohnt font-family angeben:

body {
  font-family: 'FlamboyantSansSerif';
}

Lokale Schriftarten als Fingerabdruckvektor

Die meisten Webschriften stammen aus dem Web. Interessant ist jedoch, dass die Property src in der @font-face-Deklaration neben der Funktion url() auch eine Funktion vom Typ local() akzeptiert. So können benutzerdefinierte Schriftarten lokal geladen werden. Wenn der Nutzer FlamboyantSansSerif auf seinem Betriebssystem installiert hat, wird die lokale Kopie verwendet, anstatt sie herunterzuladen:

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

Dieser Ansatz bietet einen praktischen Fallback-Mechanismus, der potenziell Bandbreite spart. Leider ist das im Internet nicht möglich. Das Problem mit der Funktion local() ist, dass sie für Browser-Fingerprinting missbraucht werden kann. Die Liste der von einem Nutzer installierten Schriftarten kann ziemlich eindeutig sein. Viele Unternehmen haben eigene Unternehmensschriften, die auf den Laptops der Mitarbeiter installiert sind. Google hat beispielsweise die Unternehmensschriftart Google Sans.

Die macOS-App „Font Book“ mit einer Vorschau der Schriftart „Google Sans“
Die Schriftart „Google Sans“, die auf dem Laptop eines Google-Mitarbeiters installiert ist.

Ein Angreifer kann versuchen, herauszufinden, für welches Unternehmen eine Person arbeitet, indem er nach einer großen Anzahl bekannter Unternehmensschriften wie Google Sans sucht. Der Angreifer würde versuchen, Text, der in diesen Schriftarten gesetzt ist, auf einem Canvas zu rendern und die Schriftzeichen zu messen. Wenn die Schriftzeichen der bekannten Form der Unternehmensschrift entsprechen, hat der Angreifer einen Treffer erzielt. Wenn die Schriftzeichen nicht übereinstimmen, weiß der Angreifer, dass eine Standard-Ersatzschrift verwendet wurde, da die Unternehmensschrift nicht installiert war. Ausführliche Informationen zu diesem und anderen Browser-Fingerprinting-Angriffen finden Sie im Umfrageartikel von Laperdix et al.

Abgesehen von den Schriftarten eines Unternehmens kann auch die Liste der installierten Schriftarten eine Identifizierung ermöglichen. Die Situation mit diesem Angriffsvektor hat sich so verschlimmert, dass das WebKit-Team vor Kurzem beschlossen hat, „nur Web-Schriftarten und Schriftarten, die mit dem Betriebssystem geliefert werden, aber keine lokal vom Nutzer installierten Schriftarten [in die Liste der verfügbaren Schriftarten] aufzunehmen“. (Und hier bin ich mit einem Artikel zum Gewähren von Zugriff auf lokale Schriftarten.)

Local Font Access API

Der Anfang dieses Artikels hat Sie vielleicht in eine negative Stimmung versetzt. Können wir wirklich keine schönen Dinge haben? Keine Sorge. Wir glauben, dass wir das können, und vielleicht ist nicht alles verloren. Aber zuerst möchte ich eine Frage beantworten, die Sie sich vielleicht stellen.

Warum benötigen wir die Local Fonts Access API, wenn es Webschriften gibt?

Design- und Grafiktools in professioneller Qualität waren bisher nur schwer im Web verfügbar. Ein Hindernis war die Unmöglichkeit, auf die gesamte Vielfalt der professionell erstellten und gehinterten Schriftarten zuzugreifen, die Designer lokal installiert haben. Webschriften ermöglichen einige Anwendungsfälle für die Veröffentlichung, aber keinen programmatischen Zugriff auf die Vektorglyphformen und Schrifttabellen, die von Rasterizern zum Rendern der Glyphenkonturen verwendet werden. Es gibt auch keine Möglichkeit, auf die Binärdaten eines Web-Fonts zuzugreifen.

  • Designtools benötigen Zugriff auf Schrift-Bytes, um ihre eigene OpenType-Layoutimplementierung auszuführen und sich auf niedrigeren Ebenen anzubinden, z. B. für Aktionen wie das Anwenden von Vektorfiltern oder ‑transformationen auf die Schriftzeichenformen.
  • Entwickler haben möglicherweise ältere Schriftschnitt-Stacks für ihre Anwendungen, die sie ins Web bringen. Für die Verwendung dieser Stapel ist in der Regel ein direkter Zugriff auf Schriftartdaten erforderlich, was Webschriften nicht bieten.
  • Einige Schriftarten sind möglicherweise nicht für die Bereitstellung über das Web lizenziert. Linotype hat beispielsweise eine Lizenz für einige Schriftarten, die nur die Nutzung auf dem Computer umfasst.

Die Local Font Access API ist ein Versuch, diese Herausforderungen zu lösen. Sie besteht aus zwei Teilen:

  • Eine Schriftarten-Aufzählungs-API, mit der Nutzer Zugriff auf alle verfügbaren Systemschriften gewähren können.
  • Für jedes Enumerationsergebnis die Möglichkeit, einen Low-Level-Zugriff (byteorientiert) auf den SFNT-Container anzufordern, der die vollständigen Schriftdaten enthält.

Unterstützte Browser

Unterstützte Browser

  • Chrome: 103.
  • Edge: 103.
  • Firefox: Nicht unterstützt.
  • Safari: Nicht unterstützt.

Quelle

Local Font Access API verwenden

Funktionserkennung

So prüfen Sie, ob die Local Font Access API unterstützt wird:

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

Lokale Schriftarten auflisten

Wenn Sie eine Liste der lokal installierten Schriftarten abrufen möchten, müssen Sie window.queryLocalFonts() aufrufen. Beim ersten Mal wird eine Berechtigungsanfrage angezeigt, die der Nutzer genehmigen oder ablehnen kann. Wenn der Nutzer zustimmt, dass seine lokalen Schriftarten abgefragt werden, gibt der Browser ein Array mit Schriftartendaten zurück, über das Sie eine Schleife erstellen können. Jede Schrift wird als FontData-Objekt mit den Eigenschaften family (z. B. "Comic Sans MS"), fullName (z. B. "Comic Sans MS"), postscriptName (z. B. "ComicSansMS") und style (z. B. "Regular") dargestellt.

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

Wenn Sie nur an einer Teilmenge der Schriftarten interessiert sind, können Sie sie auch anhand der PostScript-Namen filtern, indem Sie einen postscriptNames-Parameter hinzufügen.

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

Auf SFNT-Daten zugreifen

Vollständiger SFNT-Zugriff ist über die Methode blob() des FontData-Objekts verfügbar. SFNT ist ein Schriftdateiformat, das andere Schriftarten wie PostScript, TrueType, OpenType und WOFF (Web Open Font Format) enthalten kann.

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

In der Demo unten sehen Sie die Local Font Access API in Aktion. Sehen Sie sich auch den Quellcode an. In der Demo wird ein benutzerdefiniertes Element namens <font-select> gezeigt, das eine lokale Schriftauswahl implementiert.

Datenschutzaspekte

Die Berechtigung "local-fonts" bietet offenbar eine Oberfläche, die sich sehr gut für die Erstellung von Fingerabdrücken eignet. Browser können jedoch alles zurückgeben, was sie möchten. Beispielsweise können Browser, die auf Anonymität ausgerichtet sind, nur eine Reihe von Standardschriften bereitstellen, die im Browser integriert sind. Ebenso sind Browser nicht verpflichtet, Tabellendaten genau so bereitzustellen, wie sie auf dem Laufwerk angezeigt werden.

Die Local Fonts Access API ist so konzipiert, dass nach Möglichkeit nur genau die Informationen freigegeben werden, die für die genannten Anwendungsfälle erforderlich sind. System-APIs geben möglicherweise eine Liste der installierten Schriftarten nicht in einer zufälligen oder sortierten Reihenfolge, sondern in der Reihenfolge der Installation der Schriftarten aus. Wenn genau die Liste der installierten Schriftarten zurückgegeben wird, die von einer solchen System-API bereitgestellt wird, können zusätzliche Daten freigelegt werden, die für das Fingerprinting verwendet werden können. Die Beibehaltung dieser Reihenfolge trägt nicht dazu bei, die von uns gewünschten Anwendungsfälle zu ermöglichen. Daher müssen die zurückgegebenen Daten vor der Rückgabe in dieser API sortiert werden.

Sicherheit und Berechtigungen

Das Chrome-Team hat die Local Font Access API anhand der in Controlling Access to Powerful Web Platform Features (Zugriff auf leistungsstarke Funktionen der Webplattform steuern) definierten Grundprinzipien entwickelt und implementiert, einschließlich Nutzersteuerung, Transparenz und Ergonomie.

Nutzersteuerung

Der Zugriff auf die Schriftarten eines Nutzers liegt vollständig in seiner Kontrolle und ist nur zulässig, wenn die Berechtigung "local-fonts", wie in der Berechtigungsregistrierung aufgeführt, gewährt wurde.

Transparenz

Ob einer Website Zugriff auf die lokalen Schriftarten des Nutzers gewährt wurde, ist im Informationsblatt zur Website zu sehen.

Berechtigungsspeicherung

Die Berechtigung "local-fonts" bleibt zwischen Seitenaktualisierungen erhalten. Sie können die Einwilligung über das Tabellenblatt Websiteinformationen widerrufen.

Feedback

Das Chrome-Team möchte von Ihnen wissen, wie Sie die Local Font Access API bisher erlebt haben.

Informationen zum API-Design

Funktioniert die API nicht wie erwartet? Oder fehlen Methoden oder Eigenschaften, die Sie zur Implementierung Ihrer Idee benötigen? Haben Sie Fragen oder Kommentare zum Sicherheitsmodell? Reichen Sie ein Problem mit der Spezifikation im entsprechenden GitHub-Repository ein oder fügen Sie Ihre Gedanken zu einem vorhandenen Problem hinzu.

Problem mit der Implementierung melden

Haben Sie einen Fehler in der Chrome-Implementierung gefunden? Oder unterscheidet sich die Implementierung von der Spezifikation? Melden Sie den Fehler unter new.crbug.com. Geben Sie dabei so viele Details wie möglich an, eine einfache Anleitung zur Reproduktion und geben Sie Blink>Storage>FontAccess in das Feld Components ein. Glitch eignet sich hervorragend, um schnell und einfach Reproduktionen zu teilen.

Unterstützung für die API anzeigen

Beabsichtigen Sie, die Local Fonts Access API zu verwenden? Ihre öffentliche Unterstützung hilft dem Chrome-Team, Funktionen zu priorisieren, und zeigt anderen Browseranbietern, wie wichtig es ist, sie zu unterstützen.

Senden Sie einen Tweet an @ChromiumDev mit dem Hashtag #LocalFontAccess und teilen Sie uns mit, wo und wie Sie ihn verwenden.

Danksagungen

Die Spezifikation der Local Font Access API wurde von Emil A. Eklund, Alex Russell, Joshua Bell und Olivier Yiptong. Dieser Artikel wurde von Joe Medley, Dominik Röttsches und Olivier Yiptong überprüft. Hero-Image von Brett Jordan auf Unsplash