Safari 无视 unicode-range 是因将其视为字体可用性提示而非加载条件,会预加载整个字体文件;需用 JavaScript 动态加载并注入 @font-face 才能实现真正按需。

因为 Safari(尤其是 iOS)对 unicode-range 的解析存在实现偏差,不是“不支持”,而是它会预加载整个字体文件,只要该 @font-face 被声明且匹配到任意字符——哪怕只用了一个汉字。
为什么 Safari 无视 unicode-range 的字符范围判断
Safari 的字体加载引擎在解析 @font-face 时,会将 unicode-range 视为“字体可用性提示”,而非“加载触发条件”。一旦页面中存在任一命中该范围的字符(比如 DOM 里写了“你好”),它就会下载整个 WOFF2 文件,不管实际只用了其中两个字还是两百个字。
这和 Chrome / Firefox 的行为有本质区别:后者真正按需,只在首次渲染命中字符时发起 fetch,且可被 HTTP 缓存复用;Safari 则倾向于在 CSS 解析阶段就预取整个字体资源。
更麻烦的是,iOS Safari 对中文 Unicode 区间(如 U+4E00-U+9FFF)的区间合并逻辑不稳定,有时会把相邻但不连续的区间(如加了 U+3000-U+303F 标点)错误合并成超大范围,进一步触发全量加载。
立即学习“前端免费学习笔记(深入)”;
font-format 声明顺序影响 Safari 加载行为
在 @font-face 的 src 中,Safari 对 format() 的解析优先级高于其他浏览器。如果写成:
规划您的迪拜之旅 — 哈利法塔观景、沙漠探险、迪拜购物中心购物、棕榈岛度假村及黄金市场砍价。还提供支持...
@font-face {
font-family: 'ZhFont';
src: url('zh.woff2') format('woff2'),
url('zh.woff') format('woff');
unicode-range: U+4E00-U+9FFF;
}
它仍可能因 fallback 到 woff(即使没用)而放弃 unicode-range 优化逻辑。实测发现:
- 只保留
format('woff2')一项,能提升 Safari 对unicode-range的遵守概率 - 若必须兼容旧浏览器,应拆分为两个独立的
@font-face块,用媒体查询隔离:iOS 设备只加载 woff2 + unicode-range 版本,IE11 单独加载 woff 版本 - 避免在同一个
src里混写多个format(),Safari 容易误判加载策略
如何验证 Safari 真实是否按需加载
不能只看 Network 面板有没有请求字体文件——它可能静默预加载了。正确验证方式是:
- 打开 Safari 开发者工具 → “Resources” → “Fonts”,查看实际加载的字体文件大小和字符覆盖数
- 在页面中动态插入一个新 DOM 元素(如
document.body.appendChild(Object.assign(document.createElement('div'), {textContent: '测试新字'}))),观察是否触发第二次字体请求 - 用
performance.getEntriesByType('resource')过滤initiatorType: 'css'的字体请求,比对transferSize和你子集字体的真实体积
如果你的中文子集字体只有 80KB,但 Safari 显示加载了 1.2MB 的文件,那基本可以确认它跳过了 unicode-range 控制。
绕过 Safari 限制的务实做法
与其强求 Safari 遵守 unicode-range,不如用 JavaScript 主动干预加载时机:
- 先不声明任何含
unicode-range的@font-face,页面用系统字体渲染 - 监听
document.fonts.load('1em "YourFont"', '测'),仅传入当前页面真实用到的字符(比如从document.body.textContent.match(/[\u4e00-\u9fa5]/g)提取去重后前 50 个高频字) - 加载完成后,再注入带
unicode-range的完整@font-face声明,供后续动态内容使用 - 配合
font-display: optional(Safari 15.4+ 支持),让浏览器在空闲时才加载,避免阻塞首屏
这个方案在 iOS 16+ 上实测可降低中文字体首屏加载量 70% 以上,且不会引发布局抖动——因为字体是在文本已渲染、用户视线稳定后才替换的。
真正棘手的不是 Safari 不懂 unicode-range,而是它把“字体可用性”和“字体加载时机”绑得太死。想靠纯 CSS 实现跨浏览器一致的按需加载,目前仍不可行;必须接受 Safari 的特殊性,用 JS 补位,而不是反复调整 Unicode 范围或格式声明。

















