
FontFaceSet.load() 为什么总是返回 pending 状态
调用 FontFaceSet.load() 后 Promise 一直不 resolve,大概率是因为字体文件未被真正“注册”进 document.fonts。浏览器只对通过 new FontFace() 显式构造并调用 document.fonts.add() 的字体实例才视为可加载目标。
常见错误是直接传入字体 URL 而不构造 FontFace:
document.fonts.load('16px "MyFont"'); // ❌ 不会触发网络请求,始终 pending
正确做法是先创建、添加、再加载:
- 用
new FontFace('MyFont', 'url(/fonts/myfont.woff2)')创建实例 - 立即调用
document.fonts.add(fontFace) - 再调用
document.fonts.load('16px "MyFont"')—— 此时才会发起真实请求
如何判断字体是否真正可用(而非仅加载完成)
FontFaceSet.load() 的 Promise resolve 只表示字体资源已下载并解析完毕,不代表能立即渲染。有些字体在 Chrome 中即使加载完成,首次使用时仍可能回退到备用字体(FOIT),甚至出现短暂空白(FOUT)。
更可靠的检测方式是结合 FontFace.status 和 document.fonts.check():
-
fontFace.status为'loaded'表示该实例就绪(注意:需监听load事件,不能只靠load()Promise) -
document.fonts.check('16px "MyFont"')返回true才说明当前环境下该字体可被 CSS 引用并实际渲染 - 建议在
fontFace.loaded.then(...)内部做check(),避免竞态
编辑器中动态换字体时,如何避免 layout shift 和样式闪烁
在 HTML 编辑器(如基于 contenteditable 的富文本编辑器)里切换自定义字体,若直接修改 style.fontFamily,浏览器可能因字体未就绪而先渲染 fallback 字体,等新字体加载完再重绘,造成跳动。
关键控制点有三个:
- 提前预加载:在编辑器初始化阶段就用
FontFace加载常用字体,不要等到用户选中才开始 - 阻塞渲染:对关键段落(如标题),用
@font-face { font-display: block; }或 JS 中等待document.fonts.load()完成后再应用样式 - 降级兜底:设置
font-family: "MyFont", system-ui, sans-serif;,确保 fallback 字体与目标字体度量接近(比如都用无衬线、相似 x-height),减少重排幅度
IE 和 Safari 15.4 之前版本不支持 FontFaceSet 怎么办
document.fonts 在 IE 中完全不存在;Safari 直到 15.4 才支持 load() 方法(早期版本只支持 ready Promise)。强行 polyfill FontFaceSet 成本高且不可靠。
务实方案是分层降级:
- 用
if ('fonts' in document)检测原生支持 - 对不支持的环境,改用
CSS @import或<link rel="stylesheet">预载字体,并依赖document.fonts.ready(Safari 15.4+)或简单延时 +setTimeout模拟就绪 - 避免在低版本 Safari 中调用
load(),否则抛TypeError: document.fonts.load is not a function
真正难处理的是字体加载状态与编辑器 UI 同步——比如按钮置灰逻辑,在 Safari 15.3 及更早版本里没法准确知道字体是否 ready,只能按经验设一个保守超时(如 3s)后解锁。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











