enumerar todas las fuentes que puede mostrar el navegador de un usuario

105

¿Hay alguna forma en JavaScript para obtener los nombres de todas las fuentes (o familias de fuentes) que el navegador puede mostrar? (Quiero darle al usuario un menú desplegable con una lista de todas las fuentes disponibles y permitir que el usuario elija una). Preferiría no tener que codificar esta lista antes de tiempo o enviarla desde el servidor. (Intuitivamente, parece que el navegador debería saber qué fuentes tiene y esto debería estar expuesto a javascript de alguna manera).

mattsh
fuente

Respuestas:

38

La versión de JavaScript es un poco inestable. Obtiene fuentes iterando a través de fuentes conocidas y probando.

La forma más precisa (aunque tenga que usar un complemento de propiedad) es usar Flash . Aquí puede obtener la lista de fuentes sin tener que probarlas individualmente usando dimensiones.

Tendrá que decidir si tiene una lista exacta a expensas de no funcionar en algunos dispositivos (iDevices, navegadores sin plugin Flash, etc.), o una lista parcial con mejor soporte solo a través de JavaScript .

alex
fuente
30
@Jared ¿Por mencionar a Flash? No dije que fuera la única solución, mencioné que es la forma más precisa de detectar fuentes.
alex
4
@alex Sí. Puede dar una impresión equivocada a los desarrolladores, especialmente a los nuevos. Sugiero editar su respuesta para explicar mejor los pros y los contras de usar Flash, tal vez simplemente "No se recomienda, pero ..." o algo así.
Jared
19
@Jared ¿Tengo que escribir todas mis respuestas para proporcionar información desde cero a los lectores en caso de que sean nuevos en el oficio? Expliqué que Flash requiere un complemento de propiedad, pero también mencioné que actualmente es la única forma de obtener todas las fuentes disponibles (el método JavaScript solo detecta un subconjunto de fuentes, lo que probablemente sea lo suficientemente bueno para la mayoría de los casos de uso). Tampoco estoy contento de tener que usar Flash, pero es todo lo que tenemos ahora para esta tarea.
alex
7
@Jared ¿Ves ese último párrafo? Es posible que desee volver a leerlo.
Alex
10
@Jared Ese párrafo siempre existió.
alex
73

¡Sí hay! Estoy muy contento de que hayas hecho esta pregunta porque ahora quiero usar esto también.

+1 para la pregunta, y aquí está tu respuesta :)

http://www.lalit.org/lab/javascript-css-font-detect

Código de http://www.lalit.org/wordpress/wp-content/uploads/2008/05/fontdetect.js?ver=0.3

/**
 * JavaScript code to detect available availability of a
 * particular font in a browser using JavaScript and CSS.
 *
 * Author : Lalit Patel
 * Website: http://www.lalit.org/lab/javascript-css-font-detect/
 * License: Apache Software License 2.0
 *          http://www.apache.org/licenses/LICENSE-2.0
 * Version: 0.15 (21 Sep 2009)
 *          Changed comparision font to default from sans-default-default,
 *          as in FF3.0 font of child element didn't fallback
 *          to parent element if the font is missing.
 * Version: 0.2 (04 Mar 2012)
 *          Comparing font against all the 3 generic font families ie,
 *          'monospace', 'sans-serif' and 'sans'. If it doesn't match all 3
 *          then that font is 100% not available in the system
 * Version: 0.3 (24 Mar 2012)
 *          Replaced sans with serif in the list of baseFonts
 */

/**
 * Usage: d = new Detector();
 *        d.detect('font name');
 */
var Detector = function() {
    // a font will be compared against all the three default fonts.
    // and if it doesn't match all 3 then that font is not available.
    var baseFonts = ['monospace', 'sans-serif', 'serif'];

    //we use m or w because these two characters take up the maximum width.
    // And we use a LLi so that the same matching fonts can get separated
    var testString = "mmmmmmmmmmlli";

    //we test using 72px font size, we may use any size. I guess larger the better.
    var testSize = '72px';

    var h = document.getElementsByTagName("body")[0];

    // create a SPAN in the document to get the width of the text we use to test
    var s = document.createElement("span");
    s.style.fontSize = testSize;
    s.innerHTML = testString;
    var defaultWidth = {};
    var defaultHeight = {};
    for (var index in baseFonts) {
        //get the default width for the three base fonts
        s.style.fontFamily = baseFonts[index];
        h.appendChild(s);
        defaultWidth[baseFonts[index]] = s.offsetWidth; //width for the default font
        defaultHeight[baseFonts[index]] = s.offsetHeight; //height for the defualt font
        h.removeChild(s);
    }

    function detect(font) {
        var detected = false;
        for (var index in baseFonts) {
            s.style.fontFamily = font + ',' + baseFonts[index]; // name of the font along with the base font for fallback.
            h.appendChild(s);
            var matched = (s.offsetWidth != defaultWidth[baseFonts[index]] || s.offsetHeight != defaultHeight[baseFonts[index]]);
            h.removeChild(s);
            detected = detected || matched;
        }
        return detected;
    }

    this.detect = detect;
};

Resumen

¿Como funciona?

Este código funciona con el principio simple de que cada carácter aparece de manera diferente en diferentes fuentes. Entonces, diferentes fuentes tomarán diferentes anchos y altos para la misma cadena de caracteres del mismo tamaño de fuente.

Marko
fuente
2
Muy tortuoso. Esto es asombroso.
recursivo
4
Gracias, sí, esto es útil una vez que tengo una lista de fuentes para probar lo que está instalado, pero el problema es cómo generar una lista de nombres de fuentes en primer lugar.
mattsh
43
Esto solo dará un sí / no para si una fuente está instalada.
rektide
2
Primero pensé que era genial, pero luego encontré algunos problemas. El principal problema es que cada navegador arroja resultados diferentes. Definitivamente no es confiable.
Błażej Klisz
11
Interesante y útil pero no responde a la pregunta. Esto no recupera los nombres de las fuentes disponibles en el navegador. Dando un -1 reacio.
BenjaminGolder
11

Hay una forma de hacer esto usando document.fonts

El valor devuelto es la interfaz FontFaceSet del documento. La interfaz FontFaceSet es útil para cargar nuevas fuentes, verificar el estado de las fuentes cargadas previamente, etc.

  • Los valores devueltos son detallados con peso, estilo, etc.
function listFonts() {
  let { fonts } = document;
  const it = fonts.entries();

  let arr = [];
  let done = false;

  while (!done) {
    const font = it.next();
    if (!font.done) {
      arr.push(font.value[0]);
    } else {
      done = font.done;
    }
  }

  return arr;
}
  • Devuelve solo la familia de fuentes
function listFonts() {
  let { fonts } = document;
  const it = fonts.entries();

  let arr = [];
  let done = false;

  while (!done) {
    const font = it.next();
    if (!font.done) {
      arr.push(font.value[0].family);
    } else {
      done = font.done;
    }
  }

  // converted to set then arr to filter repetitive values
  return [...new Set(arr)];
}

Lo probé sin vincular ninguna fuente en el HTML, luego vinculé la fuente Roboto, lo probé nuevamente y se agregó al resultado.

Youssef AbouEgla
fuente
este fragmento de código funcionó perfectamente gracias! `` `listFonts () {let fonts = document ['fonts']; const it = fonts.entries (); deje arr = []; dejar hecho = falso; while (! hecho) {fuente constante = it.next (); if (! font.done) {arr.push (font.value [0] .family); } else {hecho = font.done; }} // convertido a set y luego arr para filtrar valores repetitivos return [... new Set (arr)]; } `` `
rufreakde
5
<SCRIPT>
    function getFonts()
    {
        var nFontLen = dlgHelper.fonts.count;
        var rgFonts = new Array();
        for ( var i = 1; i < nFontLen + 1; i++ )
            rgFonts[i] = dlgHelper.fonts(i); 

        rgFonts.sort();
        for ( var j = 0; j < nFontLen; j++ )
            document.write( rgFonts[j] + "<BR>" );
    }
</SCRIPT>

<BODY onload="getFonts()">
<OBJECT id=dlgHelper CLASSID="clsid:3050f819-98b5-11cf-bb82-00aa00bdce0b" width="0px" height="0px">
</OBJECT>
MPC
fuente
2
@Robert Sköld, sí, parece ser solo para IE. Todavía es útil para muchos propósitos, aunque cuando se usa en serio, debe tener alguna detección de funciones para que las personas que usan otros navegadores lo entiendan; ver, por ejemplo, cs.tut.fi/~jkorpela/listfonts1.html
Jukka K. Korpela
¿No funcionará en IE11 para Windows Phone? ¿Hay algo más que deba agregar para Windows Phone?
jats
4

Solución FontFaceSet.check ()

  • La detección de todas las fuentes disponibles es una técnica común de huellas dactilares del navegador , por lo que es poco probable que se agregue alguna API JS que devuelva directamente una lista.
  • El soporte de FontFaceSet.check () es lo suficientemente bueno como para ser utilizado, pero necesitará un respaldo, por ejemplo, esta respuesta para navegadores más antiguos.
  • Verificar la siguiente lista de fuentes toma más de 150 ms, por lo que deberá ejecutarse solo cuando sea necesario y el resultado almacenado en caché.

Lista de fuentes de Windows 10

'Arial',
'Arial Black',
'Bahnschrift',
'Calibri',
'Cambria',
'Cambria Math',
'Candara',
'Comic Sans MS',
'Consolas',
'Constantia',
'Corbel',
'Courier New',
'Ebrima',
'Franklin Gothic Medium',
'Gabriola',
'Gadugi',
'Georgia',
'HoloLens MDL2 Assets',
'Impact',
'Ink Free',
'Javanese Text',
'Leelawadee UI',
'Lucida Console',
'Lucida Sans Unicode',
'Malgun Gothic',
'Marlett',
'Microsoft Himalaya',
'Microsoft JhengHei',
'Microsoft New Tai Lue',
'Microsoft PhagsPa',
'Microsoft Sans Serif',
'Microsoft Tai Le',
'Microsoft YaHei',
'Microsoft Yi Baiti',
'MingLiU-ExtB',
'Mongolian Baiti',
'MS Gothic',
'MV Boli',
'Myanmar Text',
'Nirmala UI',
'Palatino Linotype',
'Segoe MDL2 Assets',
'Segoe Print',
'Segoe Script',
'Segoe UI',
'Segoe UI Historic',
'Segoe UI Emoji',
'Segoe UI Symbol',
'SimSun',
'Sitka',
'Sylfaen',
'Symbol',
'Tahoma',
'Times New Roman',
'Trebuchet MS',
'Verdana',
'Webdings',
'Wingdings',
'Yu Gothic',

Lista de fuentes macOS / iOS

'American Typewriter',
'Andale Mono',
'Arial',
'Arial Black',
'Arial Narrow',
'Arial Rounded MT Bold',
'Arial Unicode MS',
'Avenir',
'Avenir Next',
'Avenir Next Condensed',
'Baskerville',
'Big Caslon',
'Bodoni 72',
'Bodoni 72 Oldstyle',
'Bodoni 72 Smallcaps',
'Bradley Hand',
'Brush Script MT',
'Chalkboard',
'Chalkboard SE',
'Chalkduster',
'Charter',
'Cochin',
'Comic Sans MS',
'Copperplate',
'Courier',
'Courier New',
'Didot',
'DIN Alternate',
'DIN Condensed',
'Futura',
'Geneva',
'Georgia',
'Gill Sans',
'Helvetica',
'Helvetica Neue',
'Herculanum',
'Hoefler Text',
'Impact',
'Lucida Grande',
'Luminari',
'Marker Felt',
'Menlo',
'Microsoft Sans Serif',
'Monaco',
'Noteworthy',
'Optima',
'Palatino',
'Papyrus',
'Phosphate',
'Rockwell',
'Savoye LET',
'SignPainter',
'Skia',
'Snell Roundhand',
'Tahoma',
'Times',
'Times New Roman',
'Trattatello',
'Trebuchet MS',
'Verdana',
'Zapfino',

FontFaceSet.check ()

const fontCheck = new Set([
  // Windows 10
'Arial', 'Arial Black', 'Bahnschrift', 'Calibri', 'Cambria', 'Cambria Math', 'Candara', 'Comic Sans MS', 'Consolas', 'Constantia', 'Corbel', 'Courier New', 'Ebrima', 'Franklin Gothic Medium', 'Gabriola', 'Gadugi', 'Georgia', 'HoloLens MDL2 Assets', 'Impact', 'Ink Free', 'Javanese Text', 'Leelawadee UI', 'Lucida Console', 'Lucida Sans Unicode', 'Malgun Gothic', 'Marlett', 'Microsoft Himalaya', 'Microsoft JhengHei', 'Microsoft New Tai Lue', 'Microsoft PhagsPa', 'Microsoft Sans Serif', 'Microsoft Tai Le', 'Microsoft YaHei', 'Microsoft Yi Baiti', 'MingLiU-ExtB', 'Mongolian Baiti', 'MS Gothic', 'MV Boli', 'Myanmar Text', 'Nirmala UI', 'Palatino Linotype', 'Segoe MDL2 Assets', 'Segoe Print', 'Segoe Script', 'Segoe UI', 'Segoe UI Historic', 'Segoe UI Emoji', 'Segoe UI Symbol', 'SimSun', 'Sitka', 'Sylfaen', 'Symbol', 'Tahoma', 'Times New Roman', 'Trebuchet MS', 'Verdana', 'Webdings', 'Wingdings', 'Yu Gothic',
  // macOS
  'American Typewriter', 'Andale Mono', 'Arial', 'Arial Black', 'Arial Narrow', 'Arial Rounded MT Bold', 'Arial Unicode MS', 'Avenir', 'Avenir Next', 'Avenir Next Condensed', 'Baskerville', 'Big Caslon', 'Bodoni 72', 'Bodoni 72 Oldstyle', 'Bodoni 72 Smallcaps', 'Bradley Hand', 'Brush Script MT', 'Chalkboard', 'Chalkboard SE', 'Chalkduster', 'Charter', 'Cochin', 'Comic Sans MS', 'Copperplate', 'Courier', 'Courier New', 'Didot', 'DIN Alternate', 'DIN Condensed', 'Futura', 'Geneva', 'Georgia', 'Gill Sans', 'Helvetica', 'Helvetica Neue', 'Herculanum', 'Hoefler Text', 'Impact', 'Lucida Grande', 'Luminari', 'Marker Felt', 'Menlo', 'Microsoft Sans Serif', 'Monaco', 'Noteworthy', 'Optima', 'Palatino', 'Papyrus', 'Phosphate', 'Rockwell', 'Savoye LET', 'SignPainter', 'Skia', 'Snell Roundhand', 'Tahoma', 'Times', 'Times New Roman', 'Trattatello', 'Trebuchet MS', 'Verdana', 'Zapfino',
].sort());

(async() => {
  await document.fonts.ready;

  const fontAvailable = new Set();

  for (const font of fontCheck.values()) {
    if (document.fonts.check(`12px "${font}"`)) {
      fontAvailable.add(font);
    }
  }

  console.log('Available Fonts:', [...fontAvailable.values()]);
})();

chris
fuente
gracias, esto es lo que también estoy buscando para un eventual diseño web a lo largo de las fuentes del sistema local para obtener mucha confiabilidad al mostrar el contenido o analizar la página de manera que no llene mucho cpu
Constantin
3

En mi búsqueda de esto, también encontré Font.js , que agrega un objeto Font muy parecido a Image, por lo que es posible verificar cuándo una fuente está realmente lista para usar. También funciona con fuentes instaladas / del sistema. La desventaja es IE9 + solo debido a la necesidad Object.defineProperty(otros navegadores lo tienen), pero si está utilizando la web moderna, esta parece una opción aún mejor. (Lamentablemente, tendré que seguir con la respuesta anterior, votar a favor y continuar por ahora. :))

Stoffe
fuente
3

Agregué dos métodos al Detector de Lalit Patel arriba:

  • addFont (family, stylesheetUrl, ruleString) -> detecta si la fuente 'familia' existe, si no, agrega una hoja de estilo cargando la fuente usando stylesheetUrl si se da o de lo contrario ruleString
  • addFontsArr (arr) -> agrega una matriz de fuentes

Con esto puedes hacer:

fonts = [ 'Arial', 'Arial Black', { family: 'Lato', stylesheetUrl: 'https://fonts.googleapis.com/css?family=Lato'}, 'Leelawadee UI']
(new FontDetector()).addFontsArr(fonts);

código:

/**
 * JavaScript code to detect available availability of a
 * particular font in a browser using JavaScript and CSS.
 *
 * Author : Lalit Patel
 * Website: http://www.lalit.org/lab/javascript-css-font-detect/
 * License: Apache Software License 2.0
 *          http://www.apache.org/licenses/LICENSE-2.0
 * Version: 0.15 (21 Sep 2009)
 *          Changed comparision font to default from sans-default-default,
 *          as in FF3.0 font of child element didn't fallback
 *          to parent element if the font is missing.
 * Version: 0.2 (04 Mar 2012)
 *          Comparing font against all the 3 generic font families ie,
 *          'monospace', 'sans-serif' and 'sans'. If it doesn't match all 3
 *          then that font is 100% not available in the system
 * Version: 0.3 (24 Mar 2012)
 *          Replaced sans with serif in the list of baseFonts
 */

/**
 * Usage: d = new Detector();
 *        d.detect('font name');
 */
function FontDetector() {
    this.detect = detect;
    this.addFont = addFont;
    this.addFontsArr = addFontsArr;

    // a font will be compared against all the three default fonts.
    // and if it doesn't match all 3 then that font is not available.
    var baseFonts = ['monospace', 'sans-serif', 'serif'];

    //we use m or w because these two characters take up the maximum width.
    // And we use a LLi so that the same matching fonts can get separated
    var testString = "mmmmmmmmmmlli";

    //we test using 72px font size, we may use any size. I guess larger the better.
    var testSize = '72px';

    var h = document.getElementsByTagName("body")[0];

    // create a SPAN in the document to get the width of the text we use to test
    var s = document.createElement("span");
    s.style.fontSize = testSize;
    s.innerHTML = testString;
    var defaultWidth = {};
    var defaultHeight = {};
    for (var index in baseFonts) {
        //get the default width for the three base fonts
        s.style.fontFamily = baseFonts[index];
        h.appendChild(s);
        defaultWidth[baseFonts[index]] = s.offsetWidth; //width for the default font
        defaultHeight[baseFonts[index]] = s.offsetHeight; //height for the defualt font
        h.removeChild(s);
    }

    function detect(font) {
        var detected = false;
        for (var index in baseFonts) {
            s.style.fontFamily = font + ',' + baseFonts[index]; // name of the font along with the base font for fallback.
            h.appendChild(s);
            var matched = (s.offsetWidth != defaultWidth[baseFonts[index]] || s.offsetHeight != defaultHeight[baseFonts[index]]);
            h.removeChild(s);
            detected = detected || matched;
        }
        return detected;
    }

    function addFont(family, stylesheetUrl, ruleString) {
        if (detect(family)) {
            //console.log('using internal font '+family);
            return true;
        }
        if (stylesheetUrl) {
            console.log('added stylesheet '+stylesheetUrl);
            var head = document.head, link = document.createElement('link');
            link.type = 'text/css';
            link.rel = 'stylesheet';
            link.href = stylesheetUrl;
            head.appendChild(link);
            return true;          
        }

        if (ruleString) {
            console.log('adding font rule:'+rule);
            var newStyle = document.createElement('style');
            newStyle.appendChild(document.createTextNode(rule));
            document.head.appendChild(newStyle);
            return true;
        }

        console.log('could not add font '+family);
    }

    function addFontsArr(arr) {
        arr.forEach(a => typeof a==='string' ? addFont(a) : addFont(a.family, a.stylesheetUrl, a.ruleString));
    }
};
kofifus
fuente
2

Tal vez esto se podría hacer de una manera completamente diferente, usando una hoja de sprites con imágenes de fuentes conocidas para un personaje específico y comparándola con instantáneas de un elemento de lienzo en el que se dibuja el mismo carácter con lo que el navegador informa como la misma fuente. La comparación se puede hacer con algo como parecido.js .

Esto es más lento, pero también debería permitirnos detectar cuando el navegador está mintiendo.

fzzylogic
fuente
2

La respuesta corta es. No ha cambiado mucho con respecto a la detección de fuentes en los navegadores en 2020, excepto que usar Flash ahora es una idea aún peor .

Actualmente no existe un sistema nativo del navegador para "enumerar" todas las fuentes disponibles. Sin embargo, los navegadores le permitirán verificar si una fuente está cargada / lista usando la API FontFaceSet . Es bastante compatible con los navegadores modernos.

Esto está destinado a mostrar si una fuente web está completamente descargada, PERO también funcionará para las fuentes del sistema. El problema es que debe proporcionar una lista de fuentes para verificar.

Por lo tanto, junto con una user agent prueba (no siempre precisa), puede producir una lista de fuentes comunes del sistema para cada tipo de dispositivo. Luego, pruebe con esas y las fuentes web que cargue.

NOTA: Esto NO le dará una lista completa de las fuentes disponibles, pero puede verificar las fuentes comúnmente instaladas por los productos de MS Office o Adobe.

Bryce Howitson
fuente
0

Recientemente he notado que si configuro el valor context.font para un lienzo HTML5, en algo no válido, como "basura", el lienzo ignora el cambio. No sé si esto es específico del navegador, pero parece funcionar de esta manera en Chrome. También he visto otras publicaciones ( se ignora la fuente de lienzo HTML 5 ) que indican que sucede en otros navegadores.

Luego, se podría escribir una cadena con el valor predeterminado, que creo que es "10px sans serif" ( https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font ), establezca la fuente a uno que esté probando y vuelva a escribir la cadena. Si es igual que el primer dibujo, la fuente no está disponible.

AFF
fuente