JavaScript 不直接加载字体,而是通过配合 CSS(font-display: swap + preload)和 FontFace API/FontFaceObserver 实现精准控制与兜底,避免 FOUT/FOIT,禁止动态改 font-family 引发二次闪烁。

JavaScript 本身不直接加载字体文件,但能配合 CSS 和 HTML 协同优化字体加载流程,从而避免文字闪烁(FOUT/FOIT)。关键不是“用 JS 加载字体”,而是用 JS 做精准控制和兜底处理——让字体切换更可控、更平滑。
用 font-display: swap + preload 组合打基础
这是防闪烁最核心的 CSS 层策略,JS 不替代它,但要确保它生效:
- @font-face 中必须写 font-display: swap:让浏览器在自定义字体未就绪时,先用备用字体显示文本,加载完成再替换,避免空白(FOIT)
- <link rel="preload"> 要严格配对:href 路径必须与 @font-face 的 src 完全一致(含大小写、查询参数),且加 as="font"、crossorigin、type="font/woff2"
- preload 标签必须放在所有 CSS 引入之前,否则浏览器解析到样式时已发起默认字体请求,预加载就失效了
用 FontFace API 主动监听与控制时机
当需要更精细干预(比如首页标题等关键文案),可用 JavaScript 的 FontFace API 手动加载并监听状态:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 创建 FontFace 实例,调用 .load() 返回 Promise,明确知道字体何时可用
- 加载成功后,用 document.fonts.add() 注册字体,再通过 CSS 类或 style 动态启用,避免全局字体切换引发的批量重排
- 可结合 loading 状态,在字体就绪前给容器加 loading 类(如 opacity: 0.8),就绪后再移除,视觉过渡更自然
用 FontFaceObserver 做降级与容错
原生 FontFace API 兼容性有限(IE 不支持),生产环境建议用轻量库 FontFaceObserver:
立即学习“Java免费学习笔记(深入)”;
- 它封装了跨浏览器字体加载检测逻辑,返回 Promise,比轮询更可靠
- 可设置超时(如 3s),超时后自动 fallback 到系统字体,并记录埋点,便于后续优化
- 支持监听多个字体族,适合多字重、多语言场景,避免某一个字体失败导致整套失效
避免 JS 动态改 font-family 引发二次闪烁
有些项目会在 DOMContentLoaded 后用 JS 设置 body 字体,这反而会触发额外的 FOUT:
- 字体声明应写在 CSS 中,由浏览器原生解析和应用;JS 只负责“增强”,不负责“首次启用”
- 如果必须动态切换(如主题切换),优先用 CSS 自定义属性(--font-main)+ class 切换,而非直接改 style.fontFamily
- 切换前可加 will-change: font-family 或临时 visibility: hidden,减少重排影响

















