var()的第二个参数是回退值,仅在变量完全未声明或为unset时生效;若已声明为空字符串、initial、inherit或无效值,则不触发回退,且回退值中禁止嵌套var()。

var() 的第二个参数不是“默认值”,而是“回退值”
很多人误以为 var(--color, red) 中的 red 是变量未定义时的“默认值”,其实它只是当 --color **完全未声明**(或声明为 unset)时才生效的回退值。如果 --color 被设为 initial、空字符串、inherit,甚至一个无效颜色如 bluue,这个回退值都不会触发——浏览器会继续尝试解析并应用那个非法值,最终可能降级为 initial 或继承值,而不是跳到 red。
所以别指望它兜底所有“无效情况”,它只兜底“未定义”这一种情形。
回退值不支持嵌套 var(),但可以写 CSS 函数或计算值
var() 的第二个参数不能是另一个 var(),比如 var(--main-color, var(--fallback-color, #ccc)) 是非法语法,会导致整个声明失效(该 CSS 属性被忽略)。
- ✅ 允许:
var(--color, rgba(0, 0, 0, 0.5))、var(--size, calc(1rem + 2px))、var(--bg, linear-gradient(to right, #f00, #00f)) - ❌ 禁止:
var(--color, var(--default-color))、var(--x, --y)(第二个参数不是值,是自定义属性名) - ⚠️ 注意:回退值里的函数(如
calc())会在回退发生时实时计算,不依赖外部作用域变量
回退值在 :root 里声明时,无法访问组件局部变量
如果你在组件类选择器里设置了 --color: blue,但在全局 :root 的某个样式中写 color: var(--color, black),此时回退值不会“感知”组件内的定义——因为 var() 查找的是**继承链上最近的有效声明**,而 :root 没有继承组件的自定义属性,除非你显式把变量传下去(比如用 inherit 或层层 set)。
立即学习“前端免费学习笔记(深入)”;
- 回退值永远只在当前作用域查找变量;它不“向上搜索未定义就向下找”
- 想让组件控制全局回退行为?得把变量提升到共同祖先,或用 JS 动态设置
:root上的 fallback 变量 - 常见误判:以为
div { --c: red; color: var(--x, var(--c)) }能生效——不行,第二个var()在回退位置非法
回退值对性能无影响,但滥用会让调试变困难
浏览器解析 var(--a, red) 时,无论 --a 是否存在,都只做一次查找+一次回退判断,开销可忽略。真正的问题在于可维护性:
- 多个层级嵌套的回退(比如按钮组件里写
background: var(--btn-bg, var(--theme-bg, #fff)))看似灵活,实则违反 CSS 自定义属性的设计原则——它本就不支持链式 fallback - 开发者看到
var(--x, #000)时,会默认--x应该由上层提供;如果实际没提供,又没报错,颜色就静默变成黑色,很难定位源头 - 建议:只在明确“这个变量可能完全不存在”的场景用回退值(如第三方皮肤包未覆盖某变量),而不是当作“备选方案”泛滥使用


















