列出用户浏览器可以显示的每种字体

mat*_*tsh 84 javascript css browser fonts

有没有办法在javascript中获取浏览器可以显示的所有字体(或字体系列)的名称?(我想给用户一个下拉列表,其中包含所有可用字体的列表,并允许用户选择字体.)我不希望提前对此列表进行硬编码或从服务器发送.(直观地说,似乎浏览器应该知道它有什么字体,这应该以某种方式暴露给javascript.)

Mar*_*rko 62

就在这里!我很高兴你问这个问题,因为我现在也想用这个.

问题+1,这是你的答案:)

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

代码来自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;
};
Run Code Online (Sandbox Code Playgroud)

摘要

它是如何工作的?

此代码的工作原理很简单,即每个字符在不同字体中的显示方式不同.因此,对于相同字体大小的相同字符串,不同的字体将采用不同的宽度和高度.

  • 对于是否安装了字体,这只会给出是/否. (37认同)
  • 有趣但有用,但没有回答这个问题.这不会检索浏览器中可用字体的名称.给一个不情愿的-1. (9认同)
  • 谢谢,是的,一旦我有一个字体列表来测试安装的内容,这是有用的,但问题是如何生成一个字体名称列表. (3认同)
  • 非常狡猾.这太棒了. (2认同)
  • 首先,我认为这很好,但后来我发现了一些问题.主要问题是每个浏览器返回不同的结果.绝对不可靠. (2认同)

ale*_*lex 30

JavaScript版本有点不稳定.它通过迭代已知字体和测试来获取字体.

最准确的方法(尽管必须使用适当的插件)是使用Flash.在这里,您可以获得字体列表,而无需使用尺寸单独测试它们.

你必须决定是否有一个确切的列表,而不是在某些设备上工作(iDevices,没有Flash插件的浏览器等),或者仅通过JavaScript提供更好支持部分列表.

  • @Jared提到Flash?我没有说这是唯一的解决方案,我提到它是检测字体最准确的方法. (24认同)
  • -1表示使用Flash.它(现在)死了,在某些移动设备上不受支持,你应该寻找其他选择. (21认同)
  • @Jared我是否需要写下我的所有答案,以便为读者提供从头开始提供信息的机会?我确实解释过Flash需要一个专有的插件,但我也提到它是目前获取所有可用字体的唯一方法(JavaScript方法只检测字体的子集,这对于大多数用例来说可能已经足够了).我也不高兴不得不使用Flash,但现在我们只能完成这项任务. (15认同)
  • @Jared那个段落总是存在的. (7认同)
  • @Jared看到最后一段?您可能希望再次阅读. (5认同)
  • @jared刚刚比较了日期和时间.您的陈述评估为"您是盲人". (4认同)
  • 这是一个Flash + JS,用你的字体显示示例文本,这正是我所寻找的.https://github.com/gabriel/font-detect-js (3认同)
  • @alex是的.它可能给开发人员带来错误的印象,特别是新的开发人员.我建议编辑你的答案,以更好地解释使用Flash的利弊,也许只是"不推荐,但......"或类似的东西. (3认同)
  • 虽然我是不使用Flash的主要支持者,但我认为当你说它已经死了,你会把它与那个说它已经死了的人的状态混为一谈.http://isflashdeadyet.com/ (2认同)

You*_*gla 20

有一种方法可以使用 document.fonts

返回值为文档的 FontFaceSet 接口。FontFaceSet 接口对于加载新字体、检查先前加载字体的状态等很有用。

  • 返回的值是冗长的,包括权重、样式等。
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;
}
Run Code Online (Sandbox Code Playgroud)
  • 仅返回字体系列
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)];
}
Run Code Online (Sandbox Code Playgroud)

我在没有链接 HTML 中的任何字体的情况下对其进行了测试,然后链接了 Roboto 字体,再次测试并将其添加到结果中。

  • 看起来它只显示从服务器下载的字体。 (8认同)
  • 当我在 Firefox 中运行它时,它只显示网络字体(如 FontAwesome) (3认同)
  • 在 Chome 上(在本页的控制台中!)我运行了 Array.from(document.fonts) 并获得了两种字体,即“Roboto Slab”系列中的 bot。显然我的机器上安装的字体不止这两种。 (2认同)

chr*_*ris 16

FontFaceSet.check() 解决方法

  • 检测所有可用字体是常见的浏览器指纹识别技术,因此不太可能添加任何直接返回列表的 JS API。
  • FontFaceSet.check()支持足以使用,但需要回退,例如针对旧浏览器的此答案
  • 检查以下字体列表需要 150 毫秒以上,因此只需要根据需要运行并缓存结果。

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',
Run Code Online (Sandbox Code Playgroud)

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',
Run Code Online (Sandbox Code Playgroud)

FontFaceSet.check()

'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',
Run Code Online (Sandbox Code Playgroud)

  • 在2022年的当下,这就是最好的答案。 (4认同)

Ric*_*all 12

您可以使用新的本地字体访问 API来枚举所有字体:

console.log(await queryLocalFonts());
Run Code Online (Sandbox Code Playgroud)

还可以检查用户是否已授予权限:

const {state} = await navigator.permissions.query({name: 'local-fonts'});

console.log(state); // Either 'granted', 'prompt' or 'denied'
Run Code Online (Sandbox Code Playgroud)


Igo*_*sow 7

Chrome 87 中提供了字体访问 API :

// Query for all available fonts and log metadata.
const fonts = navigator.fonts.query();
try {
  for await (const metadata of fonts) {
    console.log(`${metadata.family} (${metadata.fullName})`);
  }
} catch (err) {
  console.error(err);
}

// Roboto (Roboto Black)
// Roboto (Roboto Black Italic)
// Roboto (Roboto Bold)
Run Code Online (Sandbox Code Playgroud)

更多信息请点击此处


Bry*_*son 6

简短的回答是。2020 年浏览器中的字体检测没有太大变化,除了使用 Flash 现在是一个更糟糕的主意

目前没有浏览器本机系统来“列出”所有可用的字体。但是,浏览器将允许您使用FontFaceSet API检查字体是否已加载/准备就绪。它在现代浏览器中得到了很好的支持。

这旨在显示网络字体是否已完全下载,但它也适用于系统字体。问题是您必须提供要检查的字体列表

因此,结合user agent 测试(并非总是准确),您可以为每种设备类型生成一个常用系统字体列表。然后针对这些字体和您加载的任何网络字体进行测试。

注意:这不会为您提供可用字体的完整列表,但您可以检查 MS Office 或 Adob​​e 产品通常安装的字体。


kof*_*fus 5

我在上面的 Lalit Patel 探测器中添加了两种方法:

  • addFont(family, stylesheetUrl,ruleString) -> 检测字体“family”是否存在,如果不存在,则添加一个样式表,使用 stylesheetUrl(如果给定)或其他规则字符串加载字体
  • addFontsArr(arr) -> 添加字体数组

有了这个你可以这样做:

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

代码:

/**
 * 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));
    }
};
Run Code Online (Sandbox Code Playgroud)