Utiliser une typographie avancée avec des polices locales

Découvrez comment l'API Local Font Access vous permet d'accéder aux polices installées localement par l'utilisateur et d'obtenir des informations de bas niveau les concernant.

Thomas Steiner
Thomas Steiner

Polices Web sécurisées

Si vous développez des sites Web depuis suffisamment longtemps, vous vous souvenez peut-être polices Web. Ces polices sont connues pour être disponibles sur presque toutes les instances des systèmes d'exploitation les plus utilisés (à savoir Windows, macOS, les distributions Linux les plus courantes, Android et iOS). Au début des années 2000, Microsoft a même ouvert la voie cette initiative appelées polices de base TrueType pour le Web, qui permettaient de télécharger sans frais ces polices objectif que "chaque fois que vous visitez un site Web qui les spécifie, vous voyez les pages exactement comme le prévu par le concepteur de site. Oui, cela incluait les sites définis dans Comic Sans MS. Voici un une pile de polices standard sécurisée sur le Web (avec la solution de remplacement ultime sans-serif police) peut se présenter comme suit:

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

Polices Web

L'époque où les polices Web étaient vraiment essentielles est révolue depuis longtemps. Aujourd'hui, nous avons polices Web, dont certaines sont et même des polices variables, que nous pouvons ajuster davantage en modifiant les valeurs des différents axes exposés. Vous pouvez utiliser des polices Web en déclarant @font-face au début du CSS, qui spécifie le ou les fichiers de police à télécharger:

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

Vous pouvez ensuite utiliser la police Web personnalisée en spécifiant la font-family, comme d'habitude:

body {
  font-family: 'FlamboyantSansSerif';
}

Polices locales comme vecteur d'empreinte

La plupart des polices Web viennent du Web. Fait intéressant, Propriété src dans @font-face , à l'exception de la déclaration url() accepte également local() . Cela permet (surprise) de charger localement des polices personnalisées. Si l’utilisateur a FlamboyantSansSerif installé sur le système d'exploitation, la copie locale sera utilisée à la place en cours de téléchargement:

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

Cette approche fournit un mécanisme de secours qui permet potentiellement d'économiser de la bande passante. Sur Internet, Malheureusement, nous ne pouvons pas avoir de belles choses. Le problème avec la fonction local() est qu'elle peut être utilisés de manière abusive pour le fingerprinting des navigateurs. Il s'avère que la liste des polices installées par un utilisateur peut être assez identifier. De nombreuses entreprises ont leurs propres polices d'entreprise qui sont installées sur les les ordinateurs portables. Par exemple, Google utilise une police d'entreprise appelée Google Sans.

<ph type="x-smartling-placeholder">
</ph> Application macOS Font Book affichant un aperçu de la police Google Sans. <ph type="x-smartling-placeholder">
</ph> Police Google Sans installée sur l'ordinateur portable d'un employé Google.

Un attaquant peut essayer de déterminer pour quelle entreprise quelqu’un travaille en testant l’existence d’une de nombreuses polices d'entreprise connues, comme Google Sans. L’attaquant tente de rendre du texte dans ces polices sur un canevas et mesurer les glyphes. Si les glyphes correspondent à la forme connue du la police d’entreprise, l’attaquant a un coup. Si les glyphes ne correspondent pas, l’attaquant sait qu’un la police de remplacement par défaut a été utilisée, car la police d'entreprise n'a pas été installée. Pour en savoir plus sur et d'autres attaques par empreinte digitale des navigateurs, lisez le étude rédigée par Laperdix et al.

Les polices de l’entreprise à part, même la seule liste des polices installées peut permettre d’identifier. La situation avec ce vecteur d'attaque est devenu tellement mauvais que récemment l'équipe WebKit décidé "N'incluez [dans la liste des polices disponibles] que les polices Web et les polices fournies avec le système de fichiers, mais pas celles installées localement par l'utilisateur". Voici un article sur l'octroi d'un accès aux polices locales.)

API Local Font Access

Au début de cet article, vous avez peut-être été de mauvaise humeur. Peut-on vraiment ne pas avoir des choses ? Ne vous inquiétez pas. Nous pensons pouvoir, et peut-être, que tout n'est pas sans espoir. Mais d'abord, laissez-moi répondre à une question que vous vous posez peut-être.

Pourquoi avons-nous besoin de l'API Local Font Access quand il existe des polices Web ?

Les outils de conception et de graphisme de qualité professionnelle ont toujours été difficiles à appliquer Web. L'un des obstacles a été l'impossibilité d'accéder à l'ensemble des ressources professionnelles et de les utiliser les polices construites et suggérées que les concepteurs ont installées localement. Les polices Web permettent de publier mais n'autorise pas l'accès programmatique aux formes de glyphes vectoriels et aux tables de polices utilisées par rastériseurs pour afficher les contours des glyphes. De même, il n'existe aucun moyen d'accéder au binaire d'une police Web données.

  • Les outils de conception ont besoin d'accéder aux octets de police pour effectuer leur propre implémentation de mise en page OpenType et permettre des outils de conception à s'associer à des niveaux inférieurs, pour des actions telles que l'exécution de filtres vectoriels ou sur les formes des glyphes.
  • Les développeurs peuvent avoir d'anciennes piles de polices pour leurs applications qu'ils importent sur le Web. Pour utiliser ces piles, elles nécessitent généralement un accès direct aux données de police, ce qui n'est pas le cas des polices Web que vous fournissez.
  • Il est possible que certaines polices ne soient pas concédés sous licence pour une diffusion sur le Web. Par exemple, Linotype dispose d'une licence pour Certaines polices ne peuvent être utilisées que sur ordinateur.

L'API Local Font Access tente de résoudre ces problèmes. Il se compose de deux parties :

  • Une API d'énumération des polices, qui permet aux utilisateurs d'accorder l'accès à l'ensemble des systèmes disponibles et les polices de caractères.
  • À partir de chaque résultat d'énumération, la possibilité de demander un conteneur SFNT de bas niveau (orienté octet) l'accès, qui inclut les données de police complètes.

Prise en charge des navigateurs

Navigateurs pris en charge

  • Chrome: 103. <ph type="x-smartling-placeholder">
  • Edge: 103. <ph type="x-smartling-placeholder">
  • Firefox: non compatible. <ph type="x-smartling-placeholder">
  • Safari: non compatible. <ph type="x-smartling-placeholder">

Source

Utiliser l'API Local Font Access

Détection de caractéristiques

Pour vérifier si l'API Local Font Access est compatible, utilisez:

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

Énumérer les polices locales

Pour obtenir la liste des polices installées localement, vous devez appeler window.queryLocalFonts(). La première fois, une invite d'autorisation s'affiche, que l'utilisateur peut approuver ou refuser. Si l'utilisateur approuve l'interrogation de ses polices locales, le navigateur renvoie un tableau contenant les données de police. que vous pouvez lire en boucle. Chaque police est représentée par un objet FontData avec les propriétés family. (par exemple, "Comic Sans MS"), fullName (par exemple, "Comic Sans MS"), postscriptName (par par exemple, "ComicSansMS") et style (par exemple, "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);
}

Si vous n'êtes intéressé que par un sous-ensemble de polices, vous pouvez également les filtrer en fonction du PostScript. en ajoutant un paramètre postscriptNames.

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

Accéder aux données SFNT

L'accès complet au SFNT est disponible via la méthode blob() du FontData. SFNT est un format de fichier de police qui peut contenir d’autres polices, telles que PostScript, Polices TrueType, OpenType, Web Open Font Format (WOFF), etc.

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

Démo

Vous pouvez voir l'API Local Font Access en action dans le fichier demo ci-dessous. N'oubliez pas de consulter également les code source. La version de démonstration présente un élément personnalisé appelé <font-select> qui et implémente un sélecteur de police local.

Considérations liées à la confidentialité

L'autorisation "local-fonts" semble fournir une surface hautement exploitable par empreinte digitale. Toutefois, les navigateurs sont libres de renvoyer ce qu’ils veulent. Par exemple, les navigateurs axés sur l'anonymat peuvent choisir pour ne fournir qu'un ensemble de polices par défaut intégrées au navigateur. De même, les navigateurs ne sont pas obligatoires pour fournir les données de table exactement telles qu'elles apparaissent sur le disque.

Dans la mesure du possible, l'API Local Font Access est conçue pour n'exposer que les informations exactes nécessaires pour activer les cas d'utilisation mentionnés. Les API système peuvent générer une liste de polices installées qui ne sont pas dans un aléatoire ou dans un ordre trié, mais dans l’ordre d’installation des polices. Renvoyer exactement la liste de les polices installées fournies par une telle API système peuvent exposer des données supplémentaires pouvant être utilisées pour le fingerprinting et les cas d'utilisation que nous souhaitons activer ne sont pas facilités par le maintien de cet ordre. En tant que résultat, cette API exige que les données renvoyées soient triées avant d'être renvoyées.

Sécurité et autorisations

L'équipe Chrome a conçu et mis en œuvre l'API Local Font Access selon les principes fondamentaux définies dans la section Contrôler l'accès à des fonctionnalités puissantes de plate-forme Web, y compris les règles le contrôle, la transparence et l'ergonomie.

Contrôle des utilisateurs

L'accès aux polices d'un utilisateur est entièrement sous son contrôle et ne lui sera pas autorisé à moins que Autorisation "local-fonts", comme indiqué dans registre d'autorisations est accordée.

Transparence

Si un site a été autorisé à accéder aux polices locales de l'utilisateur est visible dans le fiche d'information du site.

Persistance des autorisations

L'autorisation "local-fonts" sera conservée entre les actualisations de la page. Elle peut être révoquée via la informations sur le site.

Commentaires

L'équipe Chrome aimerait connaître votre avis sur l'API Local Font Access.

Présentez-nous la conception de l'API

Y a-t-il un aspect de l'API qui ne fonctionne pas comme prévu ? Ou manque-t-il des méthodes ou les propriétés dont vous avez besoin pour mettre en œuvre votre idée ? Vous avez une question ou un commentaire sur la sécurité ? Signalez un problème de spécification dans le dépôt GitHub correspondant ou ajoutez vos commentaires à un problème existant.

Signaler un problème d'implémentation

Avez-vous détecté un bug dans l'implémentation de Chrome ? Ou l'implémentation est-elle différente des spécifications ? Signalez un bug sur new.crbug.com. Veillez à inclure autant de détails que possible, des instructions simples pour le reproduire et saisissez Blink>Storage>FontAccess dans la zone Composants. Glitch est idéal pour partager des répétitions rapidement et facilement.

Apportez votre soutien à l'API

Prévoyez-vous d'utiliser l'API Local Font Access ? Votre assistance publique aide l'équipe Chrome à hiérarchisent les fonctionnalités et montre aux autres fournisseurs de navigateurs à quel point il est essentiel de les prendre en charge.

Envoyez un tweet à @ChromiumDev en utilisant le hashtag. #LocalFontAccess et laissez où et comment vous l'utilisez.

Remerciements

La spécification de l'API Local Font Access a été modifiée par Emil A. Eklund Alex Russell, Joshua Bell et Olivier Yiptong. Cet article a été examiné par Joe Medley, Dominik Röttsches Olivier Yiptong. Image héros de Brett Jordan sur Unsplash.