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

IT技术 javascript css browser fonts
2021-01-14 17:52:17

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

6个回答

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

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

概括

它是如何工作的?

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

很狡猾。这太棒了。
2021-03-13 17:52:17
起初我认为它很棒,但后来我发现了一些问题。主要问题是每个浏览器返回不同的结果。绝对不靠谱。
2021-03-23 17:52:17
谢谢,是的,一旦我有一个字体列表来测试安装的内容,这很有用,但问题是如何首先生成字体名称列表。
2021-03-24 17:52:17
这只会对是否安装字体给出是/否。
2021-03-27 17:52:17
有趣且有用,但没有回答问题。这不会检索浏览器中可用字体的名称。给一个不情愿的-1。
2021-04-04 17:52:17

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

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

您将不得不决定是以不在某些设备(iDevices、没有 Flash 插件的浏览器等)上工作为代价的确切列表,还是仅通过 JavaScript 提供更好支持部分列表

@Jared 那段一直存在。
2021-03-26 17:52:17
@Jared 提到 Flash?我没有说这是唯一的解决方案,我提到它是检测字体的最准确方法。
2021-04-02 17:52:17
@Jared 我是否需要写下我所有的答案,以便为读者提供从头开始的信息,以防他们不熟悉这门手艺?我确实解释过 Flash 需要一个专有插件,但我也提到它是目前获取所有可用字体的唯一方法(JavaScript 方法只检测字体的子集,这对于大多数用例来说可能已经足够了)。我也对不得不使用 Flash 感到不高兴,但这就是我们现在可以完成这项任务的全部内容。
2021-04-03 17:52:17
@alex 是的。它可能会给开发人员,尤其是新开发人员留下错误的印象。我建议编辑你的答案以更好地解释使用 Flash 的利弊,也许只是“不推荐,但是......”或类似的东西。
2021-04-08 17:52:17
@Jared 看到最后一段了吗?你不妨再读一遍。
2021-04-09 17:52:17

有一种方法可以使用 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;
}
  • 仅返回字体系列
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)];
}

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

看起来它只显示从服务器下载的字体。
2021-03-13 17:52:17
在 Chome 上(在此页面的控制台中!)我运行了 Array.from(document.fonts) 并且我得到了两种字体,“Roboto Slab”系列中的 bot 。显然,我的机器上安装的字体不止这 2 种。
2021-03-21 17:52:17
这个代码片段工作得很好,谢谢!``` listFonts() { let fonts = document['fonts']; const it = fonts.entries(); 让 arr = []; 让完成=假;while (!done) { const font = it.next(); if (!font.done) { arr.push(font.value[0].family); } else { 完成 = font.done; } } // 转换为 set 然后 arr 过滤重复值 return [...new Set(arr)]; }```
2021-03-30 17:52:17
这有效,它应该是公认的答案。谢谢。
2021-04-03 17:52:17
当我在 Firefox 中运行它时,它只显示网络字体(如 FontAwesome)
2021-04-04 17:52:17

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',

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

谢谢,这也是我寻找的最终网页设计沿本地系统字体以获得更多的显示内容或解析页面的方式不占用太多 cpu
2021-03-29 17:52:17

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

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

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

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

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