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 bekanntermaßen auf fast allen Instanzen der am häufigsten verwendeten Betriebssysteme verfügbar (insbesondere Windows, macOS, die gängigsten Linux-Distributionen sowie 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;
}

Web-Schriftarten

Die Zeiten, in denen websichere Schriftarten so wichtig waren, sind längst vorbei. Heute gibt es Webschriftarten. Einige davon sind sogar variable Schriftarten, die wir weiter optimieren können, indem wir die Werte für die verschiedenen Achsen ändern. Sie können Webschriften 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. Interessanterweise akzeptiert das Attribut src in der Deklaration @font-face neben der Funktion url() auch eine local()-Funktion. 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. Beispiel: Google hat eine Unternehmensschriftart namens Google Sans.

Die macOS Font Book App 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 Umfragepapier von Laperdix et al.

Unternehmensschriftarten auseinanderzuhalten, kann sogar schon eine Liste der installierten Schriftarten eindeutig identifiziert werden. 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.)

Die Local Font Access API

Der Anfang dieses Artikels hat Sie vielleicht in eine negative Stimmung versetzt. Können wir wirklich nichts Schönes 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 Stolperstein war die Unmöglichkeit, auf die gesamte Vielfalt der professionell erstellten und gehinterten Schriftarten zuzugreifen, die Designer lokal installiert haben. Webschriftarten ermöglichen einige Anwendungsfälle für die Veröffentlichung, ermöglichen jedoch keinen programmatischen Zugriff auf die Vektorglyphenformen und Schrifttabellen, die von Rastern zum Rendern der Glyphenumrisse 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 alte Schriftartstacks für ihre Anwendungen, die sie ins Web holen. 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ähigkeit, aus jedem Aufzählungsergebnis einen (byteorientierten) SFNT-Containerzugriff auf unterer Ebene anzufordern, der die vollständigen Schriftartdaten 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, die Sie als Schleife wiedergeben können. Jede Schriftart 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.

Überlegungen zum Datenschutz

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 mit Fokus auf Anonymität nur eine Reihe von Standardschriftarten bereitstellen, die in den 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.

Berechtigungstreue

Die Berechtigung "local-fonts" bleibt zwischen Seitenaktualisierungen erhalten. Er kann über das Tabellenblatt mit den Websiteinformationen widerrufen werden.

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 Umsetzung 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