跳转到内容

Local Font Access API:枚举设备上安装的字体

发布于 更新于

一句话: Local Font Access API 的 window.queryLocalFonts() 方法返回一个 Promise, 解析为描述用户设备上已安装字体的 FontData 对象数组,并由 local-fonts 权限提示所 把关。

根据 MDN,queryLocalFonts() 接受一个可选的 options 对象,其中的 postscriptNames 数组可将结果限定为特定字体;不传参数调用时,会返回浏览器愿意报告的全部字体:

const availableFonts = await window.queryLocalFonts();
for (const fontData of availableFonts) {
console.log(fontData.postscriptName, fontData.fullName, fontData.family, fontData.style);
}

根据 MDN 的 FontData 参考文档,每一项都暴露四个只读字符串属性——family、 fullName、postscriptName 和 style——以及一个 blob() 方法,解析为包含底层 SFNT 字体文件原始字节的 Blob:

const [font] = await window.queryLocalFonts({ postscriptNames: ['Verdana-Bold'] });
if (font) {
const sfntBlob = await font.blob();
console.log(sfntBlob.size, sfntBlob.type);
}

根据 MDN,queryLocalFonts() 只在安全上下文中可用,且并非 Baseline,因为它在一些 使用最广泛的浏览器中并不可用——它目前只在基于 Chromium 的桌面浏览器(Chrome、Edge 与 Opera)中提供,Firefox 和 Safari 均未实现。

根据 MDN,在没有先前用户交互的情况下调用 queryLocalFonts(),或 Permissions Policy 阻止了该功能时,会抛出 SecurityError;用户拒绝权限提示时则会抛出 NotAllowedError, 因此调用方既需要支持性检测,也需要错误处理回退:

async function listLocalFonts() {
if (!('queryLocalFonts' in window)) {
// 不受支持的浏览器(Firefox、Safari 或较旧的 Chromium):
// 回退到站点自带的内嵌/网络字体列表,而不是本地枚举。
return [];
}
try {
return await window.queryLocalFonts();
} catch (err) {
// 权限被拒绝,或未在用户手势内调用:使用同样的回退。
return [];
}
}
  • 在调用前先用 'queryLocalFonts' in window 做特性检测——Firefox 和 Safari 完全没有实现这个方法。
  • queryLocalFonts() 仅在安全上下文中可用——请据此做特性检测。可用之后,还需在 用户手势内部调用它:在没有先前用户交互的情况下调用,或 Permissions Policy 阻止 了该功能时,都会抛出 SecurityError。
  • 捕获用户拒绝授权时的 NotAllowedError,把它当作普通的权限拒绝处理,而不是 当成 bug。
  • 根据 MDN,不要假设返回列表是穷尽的,也不要假设其顺序与文件系统一致——该 API 并不需要报告每一个已安装的字体。
  • 当你只需要检查特定字体(例如某个文档已按名称内嵌的字体)时,使用 postscriptNames 过滤参数。