CSS变量在@font-face的src中无效,因url()仅接受字面量,var()不被解析,整条规则被丢弃;需构建时替换、JS注入或服务端渲染实现动态路径。

为什么 var(--font-url) 在 @font-face 里直接写死就报错
CSS 变量根本不会在 @font-face 的 src 声明中被解析——浏览器看到 url(var(--font-url)),会立刻判定为非法函数调用,整条 @font-face 规则被丢弃,不参与样式计算,也不触发任何网络请求。这不是“没生效”,是压根没通过语法校验。
常见错误现象包括:
- Network 面板完全看不到字体请求(连 404 都没有)
- 控制台静默,无报错、无警告
- 字体回退到系统默认(如 Times New Roman 或 SimSun),但你查不到原因
根本原因是:url() 函数只接受字面量字符串或合法的 CSS URL token,var() 不是其中之一;calc()、加号拼接、模板字符串等在 url() 内部全无效。
@font-face 中的 url() 路径到底相对谁?
路径是相对于 .css 文件所在位置,不是 HTML 页面,也不是 Vue 组件或 SCSS import 上下文。这点极易踩坑,尤其在 Vue + SCSS 项目中:
- 如果
iconfont.scss放在@/styles/下,而它写了url('./fonts/icon.woff2'),那实际找的是@/styles/fonts/icon.woff2 - Vue CLI 项目里用
~@/assets/fonts/xxx.woff2是 webpack 别名,但仅对style-resources-loader或css-loader生效,@font-face里的url()必须是真实可解析的静态路径 - SCSS 编译时不会重写
url(),所以@import不改变路径基准点
想动态换字体,真不能靠纯 CSS 变量?
不能。CSS 变量是运行时作用域变量,而 @font-face 是声明式规则,解析发生在样式表加载阶段,两者生命周期不重叠。可行路径只有三种:
- 构建时替换:用
string-replace-loader把__FONT_PATH__替换成实际路径,确保生成的 CSS 是静态合法的url('./fonts/xxx.woff2') - JS 动态注入:用
document.createElement('style')拼出完整的@font-face字符串并插入 DOM,注意要等字体文件预加载完成再应用font-family - 服务端渲染:后端根据用户偏好生成带具体路径的 CSS 片段,避免前端做任何路径计算
PostCSS 插件如 postcss-custom-properties 默认不处理 @font-face,需额外配置或改用 postcss-font-magician 这类专用工具。
连写死路径都 404?先确认这三件事
即使不用变量,@font-face 仍可能失败。排查优先级应是:
- 检查 Network 面板是否发出了字体请求 —— 没发出说明 CSS 规则被跳过(语法错、拼写错、引号不匹配)
- 确认请求返回状态码:404 是路径错;403 是服务器拒绝;CORS 错误需配
Access-Control-Allow-Origin - 验证
font-family名称是否严格一致:定义时用了双引号"My Font",使用时也必须写font-family: "My Font",不能漏引号、不能换单引号、不能大小写混用
最常被忽略的一点:某些浏览器(比如宙斯)会主动拦截字体加载,尤其是开启“极速模式”或禁用第三方字体时,Network 里能看到请求被 cancel,但控制台不提示 —— 这时候得去浏览器 flags 里开 font loading 开关。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











