font-family中var()回退链必须将完整合法字体列表作为第二个参数,如var(--font-zh, "Noto Sans SC", system-ui, sans-serif),而非var(--font-zh), sans-serif或var(--font-zh, sans-serif),因后者不构成有效回退链且部分浏览器解析失败。

font-family里用var()时,回退链怎么写才真正生效
直接写 font-family: var(--font-zh) 是危险的——变量值一旦不可用(比如字体名拼错、文件404、CORS失败),浏览器不会自动跳到你期望的系统字体,而是直接回退到 user-agent 默认字体(如 Times New Roman),而不是你页面里定义的 sans-serif 或 system-ui。
正确写法是显式把回退链塞进 var() 的第二个参数里:
-
font-family: var(--font-zh, "Noto Sans SC", system-ui, sans-serif)✅ -
font-family: var(--font-zh), sans-serif❌(逗号在 var 外,不构成回退链) -
font-family: var(--font-zh, sans-serif)❌(sans-serif是通用族名,不是具体字体值,部分浏览器解析失败)
关键点:第二个参数必须是**完整、合法的字体列表值**,不能省略引号,也不能只写通用族名。
[lang="zh-CN"] 选择器里要不要再套 var()?
不用。既然已经用 [lang="zh-CN"] 精准命中语言环境,就该直接声明字体链,别绕一圈再查变量。
立即学习“前端免费学习笔记(深入)”;
错误示范:html[lang="zh-CN"] { --font-zh: "PingFang SC"; } body { font-family: var(--font-zh, system-ui); }——变量更新异步,且无法保证所有元素都继承新值。
推荐写法:html[lang="zh-CN"] body, html[lang="zh-CN"] p, html[lang="zh-CN"] h1 { font-family: "Noto Sans SC", "PingFang SC", system-ui, sans-serif; }
好处有三:
- 样式立即生效,无 JS 干预延迟
- 不依赖变量作用域链,避免 Shadow DOM 或第三方组件漏匹配
- 字体链清晰可测,调试时一眼看出 fallback 顺序
多级变量回退:var(--a, var(--b, #000)) 能用在 font-family 吗?
能,但要小心作用域和值合法性。
例如:font-family: var(--font-main, var(--font-fallback, system-ui, sans-serif)) 是合法的,前提是:
-
--font-fallback在当前作用域(比如:root或当前选择器)已声明为字符串值,不能是空字符串或initial - 嵌套里的
system-ui, sans-serif必须加引号包裹成单个值:"system-ui, sans-serif"才算合法 CSS 值(实际中更推荐拆成多层变量,而非拼字符串) - 若
--font-main已声明但值为空(如--font-main: ""),回退不会触发——浏览器认为“已定义”,哪怕值无效
真正稳妥的多级控制,是把 fallback 字体链提至 :root 变量,再逐层覆盖::root { --font-base: system-ui, sans-serif; } :root[lang="zh-CN"] { --font-base: "Noto Sans SC", system-ui, sans-serif; },然后全局用 font-family: var(--font-base)。
字体加载失败时,为什么 getComputedStyle 拿不到预期 fallback?
因为 getComputedStyle(el).fontFamily 返回的是**最终计算值**,不是声明值。如果字体文件加载失败,浏览器仍会把 var(--font-zh) 解析为字符串字面量(比如 "CustomFontButNotOnTheSitePage"),而不会自动替换为 fallback 链里的下一个字体。
这意味着:
- 你无法靠 JS 读取这个值来判断字体是否加载成功
- 想做字体可用性检测,得用
document.fonts.check()或监听fontfaceSet.loadEvent - 视觉 fallback(如
font-display: swap)和 JS 可读 fallback 是两回事,别混为一谈
最易被忽略的一点:字体回退发生在渲染管线底层,不暴露给 JS;你看到的“回退效果”,其实是浏览器在绘制阶段做的,不是 CSS 计算阶段决定的。


















