liste todas as fontes que o navegador de um usuário pode exibir

105

Existe uma maneira em javascript de obter os nomes de todas as fontes (ou famílias de fontes) que o navegador pode mostrar? (Quero fornecer ao usuário uma lista suspensa com uma lista de todas as fontes disponíveis e permitir que ele escolha uma fonte.) Prefiro não ter que codificar esta lista antes do tempo ou enviá-la do servidor. (Intuitivamente, parece que o navegador deve saber quais fontes ele possui e isso deve ser exposto ao javascript de alguma forma.)

Mattsh
fonte

Respostas:

38

A versão JavaScript é um pouco instável. Ele obtém fontes iterando por meio de fontes conhecidas e testes.

A forma mais precisa (embora tenha que usar um plugin de propriedade) é usar o Flash . Aqui você pode obter a lista de fontes sem ter que testá-las individualmente usando as dimensões.

Você terá que decidir se deseja ter uma lista exata às custas de não funcionar em alguns dispositivos (iDevices, navegadores sem plug-in Flash, etc), ou uma lista parcial com melhor suporte apenas via JavaScript .

alex
fonte
30
@Jared Por mencionar o Flash? Não disse que era a única solução, mencionei que é a forma mais precisa de detectar fontes.
alex
4
@alex Sim. Isso pode dar uma impressão errada aos desenvolvedores, especialmente aos novos. Sugiro editar sua resposta para explicar melhor os prós e os contras do uso do Flash, talvez apenas "Não é recomendado, mas ..." ou algo parecido.
Jared
19
@Jared Preciso escrever todas as minhas respostas para fornecer informações desde o início para os leitores, caso eles sejam novos no ofício? Eu expliquei que o Flash requer um plug-in de propriedade, mas também mencionei que atualmente é a única maneira de obter todas as fontes disponíveis (o método JavaScript apenas detecta um subconjunto de fontes, o que provavelmente é bom o suficiente para a maioria dos casos de uso). Não estou feliz por ter que usar o Flash também, mas é tudo o que temos agora para essa tarefa.
alex
7
@Jared Vê aquele último parágrafo? Você pode querer ler novamente.
alex
10
@Jared Esse parágrafo sempre existiu.
alex
73

Sim existe! Estou muito feliz por você ter feito essa pergunta, porque agora também quero usá-la.

+1 para pergunta e aqui está sua resposta :)

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

Resumo

Como funciona?

Este código funciona com base no princípio simples de que cada caractere aparece de forma diferente em fontes diferentes. Assim, fontes diferentes terão larguras e alturas diferentes para a mesma seqüência de caracteres do mesmo tamanho de fonte.

Marko
fonte
2
Muito tortuoso. Isso é incrível.
recursivo
4
Obrigado, sim, isso é útil uma vez que tenho uma lista de fontes para testar o que está instalado, mas o problema é como gerar uma lista de nomes de fontes em primeiro lugar.
mattsh
43
Isso só dará um sim / não para saber se uma fonte está instalada.
rektide
2
Primeiro achei ótimo, mas depois descobri alguns problemas. O principal problema é que cada navegador retorna resultados diferentes. Definitivamente não é confiável.
Błażej Klisz
11
Interessante e útil, mas não responde à pergunta. Isso não recupera os nomes das fontes disponíveis no navegador. Dando um relutante -1.
BenjaminGolder
10

Existe uma maneira de fazer isso usando document.fonts

O valor retornado é a interface FontFaceSet do documento. A interface FontFaceSet é útil para carregar novas fontes, verificar o status das fontes carregadas anteriormente, etc.

  • Os valores retornados são detalhados com 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;
}
  • Retorna apenas a família da fonte
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)];
}

Eu testei sem vincular nenhuma fonte no HTML, depois vinculei a fonte Roboto, testei novamente e ela foi adicionada ao resultado.

Youssef AbouEgla
fonte
este trecho de código funcionou perfeitamente, obrigado! `` `listFonts () {let fonts = document ['fonts']; const it = fonts.entries (); deixe arr = []; deixe pronto = falso; while (! done) {const font = it.next (); if (! font.done) {arr.push (font.value [0] .family); } else {done = font.done; }} // convertido para definir e 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
fonte
2
@Robert Sköld, sim, parece ser apenas para o IE. Ainda é útil para muitos propósitos, embora quando usado seriamente, você deve ter alguma detecção de recurso para que as pessoas que usam outros navegadores entendam; ver, por exemplo, cs.tut.fi/~jkorpela/listfonts1.html
Jukka K. Korpela
Ele não funcionará no IE11 para windows phone ?? há mais alguma coisa que eu preciso adicionar para windows phone ??
jats de
4

Solução FontFaceSet.check ()

  • Detectar todas as fontes disponíveis é uma técnica comum de impressão digital do navegador , portanto, é improvável que alguma API JS seja adicionada, o que retornará diretamente uma lista.
  • O suporte a FontFaceSet.check () é bom o suficiente para ser usado, mas precisará de um fallback, por exemplo, esta resposta para navegadores mais antigos.
  • Verificar a lista de fontes a seguir leva mais de 150 ms, portanto, precisará ser executado somente quando necessário e o resultado armazenado em cache.

Lista de fontes do 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 fontes 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
fonte
obrigado, isso é o que eu procuro também para um eventual web design junto com fontes do sistema local para ganhar muita fiabilidade em mostrar conteúdo ou analisar a página de forma a não preencher muito CPU
Constantin
3

Em minha busca por isso, também encontrei Font.js , que adiciona um objeto Font muito parecido com Image, então é possível verificar quando uma fonte está realmente pronta para uso. Também funciona com fontes instaladas / do sistema. A desvantagem é o IE9 + apenas devido à necessidade Object.defineProperty(outros navegadores o têm), mas se você estiver fazendo uma web moderna, esta parece ser uma opção ainda melhor. (Eu terei, infelizmente, que ir com a resposta acima, voto positivo e continuando por enquanto. :))

Stoffe
fonte
3

Eu adicionei dois métodos ao Detector de Lalit Patel acima:

  • addFont (family, stylesheetUrl, ruleString) -> detecta se a fonte 'family' existe, se não adiciona uma folha de estilo carregando a fonte usando stylesheetUrl se fornecido ou, caso contrário, ruleString
  • addFontsArr (arr) -> adiciona uma variedade de fontes

Com isso você pode fazer:

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
fonte
2

Talvez isso pudesse ser feito de uma maneira completamente diferente, usando uma spritesheet com imagens de fontes conhecidas para um caractere específico e comparando isso com instantâneos de um elemento de tela no qual o mesmo caractere é desenhado com o que o navegador informa como a mesma fonte. A comparação pode ser feita com algo como resemble.js .

Isso é mais lento, mas também deve nos permitir detectar quando o navegador está mentindo.

fzilógico
fonte
2

A resposta curta é. Não mudou muito em relação à detecção de fontes em navegadores em 2020, exceto que usar o Flash agora é uma ideia ainda pior .

Atualmente não há sistema nativo do navegador para "listar" todas as fontes disponíveis. No entanto, os navegadores permitem que você verifique se uma fonte está carregada / pronta usando a API FontFaceSet . É muito bem suportado em navegadores modernos.

A intenção é mostrar se uma fonte da web foi completamente baixada, MAS também funcionará com fontes do sistema. O problema é que você precisa fornecer uma lista de fontes a serem verificadas.

Portanto, em conjunto com um user agent teste (nem sempre preciso), você pode produzir uma lista de fontes comuns do sistema para cada tipo de dispositivo. Em seguida, teste essas e quaisquer fontes da web carregadas.

NOTA: Isso NÃO fornecerá uma lista completa das fontes disponíveis, mas você pode verificar as fontes normalmente instaladas por produtos MS Office ou Adobe.

Bryce Howitson
fonte
0

Recentemente, notei que se eu definir o valor context.font para uma tela HTML5, como algo inválido, como "lixo", a alteração será ignorada pela tela. Não sei se isso é específico do navegador, mas parece funcionar assim no Chrome. Eu também vi outros posts (a fonte canvas HTML 5 sendo ignorada ) que indicam que isso acontece em outros navegadores.

Pode-se então escrever uma string com o valor padrão, que acredito ser "10px sans serif" ( https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font ), definir a fonte para aquele que você está testando e escreva a string novamente. Se for igual ao primeiro desenho, a fonte não está disponível.

AFF
fonte