必须用 var(--x, #fallback) 语法在第二参数提供静态值,旧浏览器忽略 var() 时才生效;不可拆成两行声明,所有变量须定义在 :root;高危属性如 background、border、font 需拆解为原子属性并单独设 fallback。

怎么用 :root + var() 实现变量降级,而不是直接写死值
老系统不支持 CSS 变量?那不能只靠 var(--color-primary) 就完事。必须给每个变量配一个静态后备值,且这个后备值得在变量解析失败时真正生效。
关键不是“写了变量”,而是“浏览器没解析到变量时,是否退到了你写的值”。这取决于写法顺序和语法合法性:
- 后备值必须写在
var()的第二个参数里,比如color: var(--text-color, #333);—— 这样 IE 和旧 Safari 才会忽略整条声明、继续看下一条(如果有的话) - 千万别写成两行:
color: #333; color: var(--text-color);,因为旧浏览器会把第二行当无效声明跳过,但第一行生效了,看起来像“兼容”了,实际新浏览器又会覆盖它,导致维护混乱 - 所有变量定义必须放在
:root里,不要分散在组件选择器中,否则无法全局 fallback,也难统一管理
如何批量生成带后备值的 CSS 变量声明(避免手写漏掉)
手动给几十个变量补后备值,极易漏、易错、后期难对齐。最稳的方式是用构建时工具注入,而不是靠人眼检查。
推荐用 PostCSS 插件 postcss-css-variables 或自定义脚本,在编译阶段把 var(--x, #fff) 展开为:
color: #fff; color: var(--x, #fff);
注意:展开后的第一行是纯静态值,第二行才是带变量的现代写法。这样旧浏览器只认第一行,新浏览器优先用第二行。
- 别依赖运行时 JS 注入变量,老系统往往连
getComputedStyle都不可靠 - 如果项目没构建流程(比如纯 HTML + CDN 引入 CSS),那就老老实实写两遍,但务必用脚本校验:跑一遍正则
/var\(--\w+,\s*[^)]+\)/g确保每个var()都有第二个参数 - 后备值不能是另一个变量,比如
var(--color-bg, var(--fallback-bg))—— 旧浏览器不理解嵌套var(),直接当无效值丢弃
哪些 CSS 属性加变量后备最危险,必须重点检查
不是所有属性加了 var() 都安全。有些属性一旦 fallback 失败,视觉就完全崩了,而且不容易被发现。
-
background:写成background: var(--bg, #fff) url(...) no-repeat;是错的 —— 整个声明会被当做一个值,旧浏览器解析失败直接丢弃整条,背景变透明。正确写法是拆成background-color和background-image两条 -
border:同理,border: var(--border, 1px solid #ccc);在旧浏览器里整个失效。应拆为border-width、border-style、border-color -
font:复合属性 fallback 极不可靠,尤其涉及font-weight或font-family变量时,建议只对font-size和color用变量,其余保持静态
为什么不能靠 CSS 自定义属性“自动降级”到 :root 之外的声明
有人试过这样写:.btn { --c: red; color: var(--c); } .legacy .btn { color: blue; },以为旧浏览器会走 .legacy .btn 分支 —— 不行。
问题在于:CSS 变量作用域是继承的,但 var() 解析失败时,浏览器不会回退到父级或同级选择器里的同名属性,而是直接把该声明置为无效,然后继续走层叠规则。也就是说:
- 旧浏览器看到
color: var(--c);→ 语法错误 → 忽略这一条 → 如果前面没有其他color声明,就用继承值或初始值(通常是黑色) - 它不会主动去找
.legacy .btn { color: blue; },除非你显式写出来,且它的权重更高 - 所以“兼容性”不是靠作用域兜底,而是靠同一声明内的
var(--x, #xxx)第二参数,或同一属性的前一条静态声明
变量抽离本身不解决兼容问题,只是让后备值更集中、更可控。真正在意老系统,就得接受:每个用到变量的地方,都得亲手(或靠工具)确保 fallback 存在且合法。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











