Usa la tipografía avanzada con fuentes locales

Aprender cómo la API de Local Font Access te permite acceder a las fuentes instaladas localmente por el usuario y obtener detalles de bajo nivel sobre ellas

Fuentes seguras para la Web

Si llevas suficiente tiempo haciendo desarrollo web, quizás recuerdes los llamados fuentes seguras para la Web. Se sabe que estas fuentes están disponibles en casi todas las instancias de los sistemas operativos más usados. (es decir, Windows, macOS, las distribuciones más comunes de Linux, iOS y Android). A principios de los 2000, Microsoft incluso encabezó una iniciativa llamadas fuentes principales TrueType para la Web, que ofrecían la descarga gratuita de estas fuentes con el objetivo de que "cada vez que visites un sitio web que las especifique, verás páginas exactamente como las del diseñador del sitio". Sí, esto incluyó sitios configurados en Comic Sans MS. Este es un la pila de fuentes seguras clásicas para la Web (con el resguardo definitivo de lo que sea sans-serif fuente) podría verse así:

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

Fuentes web

Los días en que las fuentes seguras para la Web eran realmente importantes han quedado en el pasado. Hoy tenemos fuentes web, algunas de las cuales son incluso fuentes variables que podemos modificar aún más cambiando los valores de la varios ejes expuestos. Puedes usar fuentes web si declaras un el bloque @font-face al comienzo del CSS que especifica los archivos de fuente que se descargarán:

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

Luego, puedes usar la fuente web personalizada especificando la font-family, como de costumbre:

body {
  font-family: 'FlamboyantSansSerif';
}

Fuentes locales como vector de huellas digitales

La mayoría de las fuentes web provienen, bueno, de la Web. Sin embargo, un hecho interesante es que la Propiedad src en @font-face de la declaración de clientes, además del url() esta función también acepta un local() . Esto permite que las fuentes personalizadas se carguen (sorpresa) de forma local. Si el usuario tiene FlamboyantSansSerif instalado en su sistema operativo, se usará la copia local en lugar de que se descarga:

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

Este enfoque proporciona un buen mecanismo de resguardo que potencialmente ahorra ancho de banda. En Internet, lamentablemente, no podemos tener cosas buenas. El problema con la función local() es que puede las huellas digitales del navegador. Resulta que la lista de fuentes que instaló un usuario la identificación. Muchas empresas tienen sus propias fuentes corporativas que se instalan en las computadoras de los empleados. laptops. Por ejemplo, Google tiene una fuente corporativa llamada Google Sans.

La app de Font Book para macOS que muestra una vista previa de la fuente Google Sans.
La fuente Google Sans instalada en la laptop de un empleado de Google

Un atacante puede intentar determinar para qué empresa trabaja alguien probando la existencia de una una gran cantidad de fuentes corporativas conocidas, como Google Sans. El atacante intentaría renderizar texto colocar estas fuentes en un lienzo y medir los glifos. Si los glifos coinciden con la forma conocida de la fuente corporativa, el atacante tiene un golpe. Si los glifos no coinciden, el atacante sabrá que hay se usó la fuente de reemplazo predeterminada porque la fuente corporativa no estaba instalada. Para obtener todos los detalles este y otros ataques de huella digital del navegador, lee el informe de encuesta de Laperdix et al.

Se pueden separar fuentes empresariales, incluso solo la lista de fuentes instaladas. La situación con este vector de ataque se volvió tan malo que recientemente el equipo de WebKit decidido para "incluir solo [en la lista de fuentes disponibles] las fuentes web y las fuentes que vienen con el sistema del sistema, pero no de las fuentes instaladas por el usuario de forma local. (Y aquí estoy, con un artículo sobre cómo otorgar acceso a fuentes locales).

La API de Local Font Access

Es posible que el comienzo de este artículo te haya puesto de ánimo. ¿Es posible realmente no tener cosas? No te preocupes. Creemos que sí podemos, y quizás no todo es desesperado. Pero primero, permítanme responder una pregunta que podrían estar haciendo.

¿Por qué necesitamos la API de Local Font Access cuando hay fuentes web?

Las herramientas gráficas y de diseño de calidad profesional siempre han sido difíciles de entregar web. Un obstáculo fue la imposibilidad de acceder y utilizar toda la variedad de herramientas fuentes construidas y optimizadas que los diseñadores instalaron de forma local. Las fuentes web permiten algunas publicaciones casos de uso, pero que no permita el acceso programático a las tablas de fuentes y formas de glifos vectoriales que utiliza rasterizadores para renderizar los contornos del glifo. Tampoco hay forma de acceder al objeto binario de una fuente web de datos no estructurados.

  • Las herramientas de diseño necesitan acceso a bytes de fuente para realizar su propia implementación de diseño de OpenType y permitir herramientas de diseño para conectarse en los niveles inferiores, para acciones como realizar filtros vectoriales o se transforman en las formas del glifo.
  • Es posible que los desarrolladores tengan pilas de fuentes heredadas para sus aplicaciones que llevan a la Web. Para usar estas pilas, suelen requerir acceso directo a los datos de fuente, algo que las fuentes web no necesitan proporcionan.
  • Es posible que algunas fuentes no tengan una licencia para su entrega a través de la Web. Por ejemplo, Linotype tiene una licencia para algunas fuentes que solo incluyen uso de escritorio

La API de Local Font Access sirve para resolver estos desafíos. Está compuesto por dos partes:

  • Una API de enumeración de fuentes, que permite a los usuarios otorgar acceso al conjunto completo de sistemas disponibles fuentes.
  • A partir de cada resultado de enumeración, la capacidad de solicitar un contenedor SFNT de bajo nivel (orientado a bytes) de las fuentes que incluya todos los datos de la fuente.

Navegadores compatibles

Navegadores compatibles

  • Chrome: 103
  • Edge: 103.
  • Firefox: No es compatible.
  • Safari: no es compatible.

Origen

Cómo utilizar la API de Local Font Access

Detección de funciones

Para comprobar si la API de Local Font Access es compatible, utiliza lo siguiente:

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

Enumera las fuentes locales

Para obtener una lista de las fuentes instaladas de forma local, debes llamar a window.queryLocalFonts(). El primera vez, se activará una solicitud de permiso que el usuario puede aprobar o rechazar. Si el usuario aprueba las fuentes locales que se consultarán, el navegador devolverá una matriz con los datos de las fuentes. que puedes usar en bucle. Cada fuente se representa como un objeto FontData con las propiedades family. (por ejemplo, "Comic Sans MS"), fullName (por ejemplo, "Comic Sans MS"), postscriptName (por ejemplo, por ejemplo, "ComicSansMS") y style (por ejemplo, "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 solo te interesa un subconjunto de fuentes, también puedes filtrarlas en función del PostScript nombres mediante la adición de un parámetro postscriptNames.

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

Acceso a datos de SFNT

El acceso completo a SFNT está disponible a través del método blob() de la FontData. SFNT es un formato de archivo de fuente que puede contener otras fuentes, como PostScript, Fuentes: TrueType, OpenType, Web Open Font Format (WOFF), etcétera

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

Demostración

Puedes ver la API de Local Font Access en acción en la demo a continuación. Asegúrate de consultar también código fuente. La demostración muestra un elemento personalizado llamado <font-select> que implementa un selector de fuentes local.

Consideraciones de privacidad

El permiso "local-fonts" parece proporcionar una superficie en la que se pueden extraer las huellas digitales. Sin embargo, los navegadores tienen la libertad de mostrar lo que quieran. Por ejemplo, los navegadores centrados en el anonimato pueden elegir para proporcionar solo un conjunto de fuentes predeterminadas integradas en el navegador. Del mismo modo, los navegadores no son obligatorios para proporcionar los datos de la tabla exactamente como aparecen en el disco.

Siempre que sea posible, la API de Local Font Access se diseñó para mostrar solo la información con exactitud. necesarios para habilitar los casos de uso mencionados. Las APIs del sistema pueden generar una lista de fuentes instaladas que no están en una aleatorio o en un orden ordenado, pero en el orden de instalación de la fuente. Mostrar exactamente la lista de Las fuentes instaladas que brinda una API del sistema pueden exponer datos adicionales que pueden usarse para la creación de huellas digitales y los casos de uso que queremos habilitar no cuentan con la asistencia de retener este orden. Como como resultado, esta API requiere que los datos devueltos se ordenen antes de mostrarse.

Seguridad y permisos

El equipo de Chrome diseñó e implementó la API de Local Font Access con los principios fundamentales. se definen en Controla el acceso a las funciones potentes de la plataforma web, incluida la información la transparencia y la ergonomía.

Control de usuarios

El acceso a las fuentes de un usuario está completamente bajo su control y no se permitirá a menos que "local-fonts", como se indica en la permiso de registro.

Transparencia

Si un sitio tiene acceso a las fuentes locales del usuario, aparecerá en la sección hoja de información del sitio.

Persistencia de permisos

Se conservará el permiso "local-fonts" entre las recargas de páginas. Se puede revocar mediante información del sitio.

Comentarios

El equipo de Chrome quiere conocer tu experiencia con la API de Local Font Access.

Cuéntanos sobre el diseño de la API

¿Algo en la API no funciona como esperabas? ¿O faltan métodos o propiedades que necesitas para implementar tu idea? Haz una pregunta o comentario sobre la seguridad modelo? Informa un problema de especificaciones en el repositorio de GitHub correspondiente o agrega lo que piensas a un problema existente.

Informar un problema con la implementación

¿Encontraste un error en la implementación de Chrome? ¿O la implementación es diferente de la especificación? Informa un error en new.crbug.com. Asegúrate de incluir tantos detalles como puedas instrucciones simples de reproducción y, luego, ingresa Blink>Storage>FontAccess en el cuadro Componentes. Glitch funciona muy bien para compartir repros rápidos y fáciles.

Demuestra compatibilidad con la API

¿Piensas utilizar la API de Local Font Access? Tu asistencia pública ayuda al equipo de Chrome a prioriza funciones y muestra a otros proveedores de navegadores la importancia de admitirlas.

Envía un tweet a @ChromiumDev con el hashtag #LocalFontAccess y deja para saber dónde y cómo lo utilizas.

Agradecimientos

La especificación de la API de Local Font Access fue editada por Emil A. Eklund, Alex Russell Joshua Bell y Olivier Yiptong. Este artículo fue revisado por Joe Medley: Dominik Röttsches y Olivier Yiptong. Hero image de Brett Jordan en Retiro: