能力 · API
Local Font Access API
发布于 更新于
window.queryLocalFonts() 在 local-fonts 权限提示之后,兑现为描述用户设备上已安装字体的 FontData 数组。每个 FontData 暴露 PostScript 名、全名、家族名、样式名,以及返回原始 SFNT 字节的 blob() 方法;设计类工具要用用户自己的字体而不是 Web 字体来排版文字时,需要的正是这些数据。
支持仅限桌面 Chromium:Chrome 103,以及基于它的 Edge 与 Opera 版本。Android 上的 Chrome、Firefox、Safari 的任何版本都没有实现(BCD api.Window.queryLocalFonts);该方法带 [SecureContext],在 localhost 以外的 http:// 源上同样不存在。
window.queryLocalFonts()window.queryLocalFonts(options)
fontData.blob()queryLocalFonts() 返回 Promise<sequence<FontData>>,按 postscriptName 升序排列。blob() 返回 Promise<Blob>,其 type 为 application/octet-stream。规范写明浏览器不必报告每一个已安装字体,所以结果是用户代理愿意暴露、并经用户在选择器中(如果浏览器显示选择器)筛选过的集合。
queryLocalFonts() 接受一个可选的 options 参数,类型为只有一个成员的 QueryOptions 字典。
| 成员 | 类型 | 必填 | 说明 |
|---|---|---|---|
postscriptNames |
sequence<DOMString> |
否 | 只返回 PostScript 名在列表内的字体,例如 ["Verdana-Bold", "Arial"]。空列表什么都不返回;不传该成员则返回全部可选字体。匹配是精确的,带空格的 "Verdana Bold" 不会匹配任何字体。 |
返回的每个 FontData 有四个只读 USVString 属性和一个方法。
| 成员 | 类型 | 说明 |
|---|---|---|
postscriptName |
USVString |
PostScript 名,如 "Arial-Bold";也是结果的排序键。 |
fullName |
USVString |
家族名加子家族名,如 "Arial Bold"。 |
family |
USVString |
CSS font-family 使用的家族名,如 "Arial"。 |
style |
USVString |
子家族或样式名,如 "Regular"、"Bold Italic"。 |
blob() |
Promise<Blob> |
字体文件字节(SFNT 容器:TrueType、OpenType、WOFF 或 WOFF2)。 |
名称以字体 name 表的美式英语或用户语言本地化字符串单一返回;需要其他语言的页面要自己从 blob() 解析 name 表。
queryLocalFonts() 以下列 DOMException 名称拒绝,顺序即规范的检查顺序。
| 异常 | 条件 |
|---|---|
SecurityError |
文档的源是 opaque origin(例如没有 allow-same-origin 的沙箱 iframe);或文档不允许使用 local-fonts 这一受策略控制的特性(默认允许列表为 'self');或调用时没有瞬时用户激活。 |
NotAllowedError |
用户拒绝了 local-fonts 权限提示。 |
blob() 没有定义任何拒绝情形。Chromium 增加了规范未列出的拒绝:枚举后端缺失时以 NotSupportedError 和 Not yet supported on this platform. 拒绝,标签页隐藏时以 SecurityError 和 Page needs to be visible. 拒绝,DataError 和 Font data exceeds memory limit.,以及其他后端失败时的 UnknownError(权限被拒的情形 Chromium 也另有处理,见实测框)。
两个示例都在 click 处理函数中运行,先检测 window 上的 queryLocalFonts,API 缺失或用户拒绝时回退到页面自带的字体。
用设备字体填充字体选择器,并带一份内置回退列表
Section titled “用设备字体填充字体选择器,并带一份内置回退列表”回退列表就是页面已经加载的 Web 字体,这样在 Firefox、Safari 或移动端 Chrome 中选择器也不会为空。鉴于上文所述的拒绝行为,Chrome 返回空结果时按同样方式处理。
const BUNDLED = ['Inter', 'Source Serif 4', 'JetBrains Mono'];
async function listFontFamilies() { if (!('queryLocalFonts' in window)) return BUNDLED;
try { const fonts = await window.queryLocalFonts(); if (fonts.length === 0) return BUNDLED; // Chrome 中被拒绝,或没有可选字体 return [...new Set(fonts.map((f) => f.family))]; } catch (err) { if (err.name === 'SecurityError' || err.name === 'NotAllowedError') return BUNDLED; throw err; }}
document.querySelector('#pick-fonts').addEventListener('click', async () => { const select = document.querySelector('#font-family'); select.replaceChildren(...(await listFontFamilies()).map((name) => new Option(name)));});按 family 去重是必要的,因为一个家族的每种字重和样式都是单独一个 FontData:"Arial"、"Arial-Bold"、"Arial-Italic"、"Arial-BoldItalicMT" 是共享家族名 "Arial" 的四个条目。
渲染文档前确认某个特定字体是否存在
Section titled “渲染文档前确认某个特定字体是否存在”postscriptNames 把提示和结果都收窄到你关心的字体。字体缺失时改用文档内嵌的 Web 字体渲染,并告知用户版面可能有差异。
async function hasLocalFont(postscriptName) { if (!('queryLocalFonts' in window)) return false; try { const matches = await window.queryLocalFonts({ postscriptNames: [postscriptName] }); return matches.length === 1; } catch { return false; // 没有手势、被策略拦截,或用户拒绝 }}
document.querySelector('#open-document').addEventListener('click', async () => { const useLocal = await hasLocalFont('Verdana-Bold'); document.body.style.fontFamily = useLocal ? '"Verdana"' : '"Verdana Web", sans-serif'; document.querySelector('#font-note').hidden = useLocal;});只有当你必须自己读取字形轮廓或 name 表时(canvas 文本编辑器、字体检查器)才需要 blob();CSS 按家族名引用已安装字体并不需要它。
- File System Access API:读写本地文件,另一个每次调用都要用户手势的桌面 Chromium 文件级能力
- 字体与图片优化:font-display、picture 与 AVIF/WebP,Web 字体回退路径
- 桌面上的 PWA
- Local Font Access API: queryLocalFonts() method(wicg.github.io)
- Local Font Access API: local-fonts permission(wicg.github.io)
- Window: queryLocalFonts() browser compatibility(developer.mozilla.org)
规范
| 规范 | 状态 |
|---|---|
| Local Font Access API: queryLocalFonts() method | WICG 草案 |
| Local Font Access API: FontData interface | WICG 草案 |