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

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

85630 次浏览

有的! 我很高兴你问了这个问题,因为我现在也想用这个。

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

来自 href = “ http://www.lalit.org/wordpress/wp-content/uploads/2008/05/fontdett.js? ver = 0.3”rel = “ nofollow noReferrer”> 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;
};

摘要

How does it work?

这段代码的工作原理很简单,每个字符都会出现 不同的字体。所以不同的字体将采取不同的 width and height for the same string of characters of same font-size.

The JavaScript version is a bit flaky. It gets fonts by iterating through known fonts and testing.

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

你将不得不决定是否有一个精确的列表在不工作的代价在一些设备(iDevice,浏览器没有 Flash 插件等) ,或 只通过 JavaScript 提供更好的支持的部分列表

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

在我的搜索中,我还发现了 Font.js,它添加了一个与 Image 非常相似的 Font 对象,因此可以检查字体是否真的可以使用。也可用于安装/系统字体。缺点是 IE9 + 只是因为需要 Object.defineProperty(其他浏览器有它) ,但如果你正在做现代网络,这似乎是一个更好的选择。(遗憾的是,我不得不接受上面的答案,投了赞成票,现在继续前进。:))

也许这可以用一种完全不同的方式来完成,使用一个已知字体图像的电子表格来处理特定的字符,并将其与画布元素的快照进行比较,画布元素上绘制了相同的字符,而浏览器报告的是相同的字体。这个比较可以用类似 像 Js的东西来完成。

这比较慢,但是也应该允许我们检测浏览器什么时候在说谎。

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

  • addFont(family, stylesheetUrl, ruleString) -> detects if the font 'family' exists, if not adds a stylesheet loading the font using either stylesheetUrl if given or otherwise ruleString
  • AddFontsArr (arr)-> 添加字体数组

With this you can do:

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

密码:

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

我最近注意到,如果我将 HTML5画布的 context.font 值设置为无效的值,比如“垃圾”,那么画布就会忽略这个更改。我不知道这是否是浏览器特有的,但是在 Chrome 上似乎是这样工作的。我还看到其他帖子(HTML 5画布字体被忽略)表明这种情况发生在其他浏览器中。

然后可以用默认值(我认为是“10px sans serif”(https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font))写出一个字符串,将字体设置为您正在测试的字符串,然后再次写出字符串。如果它与第一个绘图相同,则字体不可用。

有一种方法可以使用 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 字体,再次测试,它得到了添加到结果。

简单来说就是 2020年,浏览器中的字体检测没有太大的改变,除了使用 Flash 现在是一个更糟糕的想法。

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

这是为了显示一个网络字体是否完全下载,但它将工作的系统字体以及。要检查的字体是 你必须提供一份名单

因此,结合 user agent 测试(并不总是准确的) ,您可以为每种设备类型生成一个 共同制度字体共同制度字体列表。然后测试这些字体和你加载的任何网页字体。

注意: 这不会给你一个可用字体的完整列表,但是你可以检查通常由 MS Office 或 Adobe 产品安装的字体。

Check ()解决方案

  • 检测所有可用的字体是常用的 浏览器指纹识别技术,所以不太可能添加任何 JS API,这将直接返回一个列表。
  • FontFaceSet.check() support is good enough to be used but will need a fallback e.g. this answer for older browsers.
  • 检查下面的字体列表需要150ms 以上,因此只需要根据需要运行并缓存结果。

Windows10字体列表

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

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)

更多信息 给你

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

console.log(await queryLocalFonts());

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

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


console.log(state); // Either 'granted', 'prompt' or 'denied'