先记住这个答案
var() 函数只接收两个参数:第一个是自定义属性名,第二个是可选的备用值。若提供多个逗号分隔的值,则从第一个逗号到结尾的所有内容都被当作单个备用值,而非多个独立选项。因此写 var(--x, red, blue) 时,备用值是字符串 "red, blue";当 --x 未定义且该备用值对当前属性不是合法值时,声明按 unset 处理,而不是先回退 red 再回退 blue。仅当自定义属性为 guaranteed-invalid 时才启用备用值。
- var() 最多一个备用值,语法不允许第二个独立参数
- 多个逗号值会被合并为一个备用值,通常无效
- 备用值仅在自定义属性不可用时才触发,而非逐层降级
语法结构决定了无多重回退
规范中 var() 的形式为 var( <custom-property-name> , <declaration-value>? ),即最多两个参数。第二个参数作为整个回退值,允许包含逗号,但逗号不会分隔出多个备用项。例如 var(--a, red, blue) 中,备用值是视为一个 token 序列 "red, blue",并非两个候选。如果该值不合法于当前属性,则整个 var() 解析为无效,属性按 unset 处理。
真正的“多级回退”只能通过嵌套 var() 模拟:var(--a, var(--b, red))。内层 var() 先解析,若 --b 也未定义且无更内层回退,则最终红。这种写法是单个回退值本身也是一个 var() 表达式,与函数多参数完全不同。
.box { color: var(--undefined-color, red, blue); }
/* 若 --undefined-color 未定义,则备用值是 'red, blue',对 color 无效,.box 颜色变为 unset */此示例演示变量未定义时,多值备用会被解析为一个整体值 'red, blue',因不合法的 color 值导致整个声明无效,属性回退为 unset。可在浏览器开发者工具中验证计算样式。
误用多备用值的组件主题场景
某设计系统为按钮提供颜色变量 --btn-bg,并希望未设置时依次回退到 --theme-accent,再回退到 #1976d2。开发者误写作 var(--btn-bg, var(--theme-accent), #1976d2)。因 --btn-bg 未定义,整个备用值会成为 "var(--theme-accent), #1976d2" 并替换进 background。随后浏览器解析这个值,内部 var() 依然会被求值,但最终值通常会因不符合 background 的单值预期而判为无效声明。
正确实现是嵌套 var:background: var(--btn-bg, var(--theme-accent, #1976d2))。这样当 --btn-bg 未定义时,使用内层 var() 的解析结果;若 --theme-accent 也未定义,再取 #1976d2。修改后组件在任何上下文中都能得到预期颜色,且不会触发无效值级联。
失效边界与注意事项
备用值启用仅当自定义属性是 guaranteed-invalid,即未声明且无 @property 注册初始值,或显式声明为 initial 且非注册,或存在循环依赖。若自定义属性已声明但值对目标属性非法,如 --x: 20px 用于 color,此时 var(--x, red) 不会使用 red,而是让 color 变为 unset——因为变量替换发生在用时,而非声明时,语法错误被延迟。
另一个边界是 CSS 全局关键字作为变量值:若 --x 设为 inherit 或 revert,它们可能解析出有效值,不触发备用。因此不要假设“变量不存在就用备用”等同于“变量无效就用备用”。处理这个边界需确认变量的实际值,或在 @property 中注册语法并指定 initial-value,使未定义时自动用初始值而非备用值。
容易答错的地方
- 认为 var(--a, red, blue) 会依次尝试每个颜色
- 错误。该写法把逗号后的全部内容视为一个回退值,不会拆分。若属性需要单个颜色,则回退值本身无效,最终属性变成 unset,而非使用 red 或 blue。
- 把变量无效值与未定义混为一谈
- 未定义可能触发备用,但变量已定义且值非法时不会使用备用,而是令属性 unset。例如 --x: 20px,color: var(--x, red) 结果不是红色,而是 unset,因为替换后 color: 20px 非法。
面试官还会怎么问?
如何实现真正的多重回退?
通过嵌套 var():var(--a, var(--b, var(--c, initial)))。每次备用的值本身可以是另一个 var() 表达式,这是唯一能实现多级回退的纯 var() 方式。@property 注册变量并指定 initial-value 只能为单个变量提供默认值,无法替代嵌套结构;若只有一层备选,可以用它简化。
var() 的备用值可以包含哪些字符?
可以包含除换行、未闭合括号、分号、感叹号以外的任意字符,且允许嵌套 var()。但若包含逗号,它属于同一备用值的一部分,不影响参数拆分。
自定义属性未定义时,var() 没有备用值会怎样?
这时 var() 解析为 guaranteed-invalid,整个声明变成无效值,属性按 unset 处理。注意这与彩色文字示例不同:color: var(--x) 若 --x 未定义,则 color 变为 unset,可能继承或为初始色。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。