前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库CSS var() fallback value cascade
CSS层叠与选择器

var() 里写多个备用值能逐个回退吗?

不能。var() 只接受两个参数:自定义属性名和一个可选的备用值。写 var(--x, red, blue) 时,备用值是整个 red, blue 字符串,不会先试 red 再试 blue。想要多级回退,只能嵌套:var(--a, var(--b, red))。

前端进阶之旅 · 一题精讲更新于 2026.09.29
CSS#层叠与选择器
先看核心答案读代码示例
理解线索

`var()` 的回退机制

  1. 两参数上限var(--prop, fallback) 逗号后的所有内容算一个备用值
  2. 触发条件自定义属性未定义或为 guaranteed-invalid 时才启用备用值
  3. 嵌套回退var(--a, var(--b, red)) 是唯一的多级回退写法

变量已定义但值对目标属性非法时(比如把 20px 用在 color 上),不会触发备用值,属性直接按 unset 处理。

核心回答

先记住这个答案

var() 函数只接收两个参数:第一个是自定义属性名,第二个是可选的备用值。从第一个逗号到结尾的所有内容都被当作一个备用值,不会拆成多个候选项。写 var(--x, red, blue) 时,备用值是 red, blue 这个整体字符串;如果 --x 未定义而且 red, blue 对当前属性不合法,整个声明变成无效,属性按 unset 处理。

  • var() 只接受一个备用值
  • 多个逗号值合并为一个整体
  • 变量已定义但值非法不触发回退
  • 多级回退用嵌套 var()

var() 语法只允许一个备用值

规范里 var() 的形式是 var( <custom-property-name> , <declaration-value>? ),最多两个参数。第二个参数虽然允许包含逗号,但逗号不会起到"分隔多个候选"的作用。比如 background: var(--bg, linear-gradient(red, blue)) 里的备用值是完整的 linear-gradient(red, blue) 渐变,逗号只是渐变语法的一部分。

多个逗号值被当成一个整体CSS
:root {
  /* --accent 未定义 */
}

.box {
  /* 备用值是整个 "red, blue",不是两个候选 */
  color: var(--accent, red, blue);
  /* "red, blue" 对 color 来说不合法 */
  /* 最终 color 按 unset 处理,可能继承父级颜色 */
}

.card {
  /* 正确的多级回退:嵌套 var() */
  background: var(--card-bg, var(--theme-bg, #f5f5f5));
}

.box 的 color 不会变红也不会变蓝,因为 red, blue 整体不是合法的颜色值。而 .card 用嵌套 var() 实现了三级回退:先看 --card-bg,没有就看 --theme-bg,都没有才用 #f5f5f5。

正确的多级回退要嵌套 var()

真正的多级回退只能通过嵌套来做。每一层 var() 的备用值本身又是一个 var() 表达式,内层先解析,解析不了再往下一层走。写成 var(--a, var(--b, var(--c, fallback))) 就能实现三级回退。

主题色的三级回退示例CSS
.button {
  /* 优先用组件级变量 --btn-bg */
  /* 没有就用主题级变量 --theme-primary */
  /* 都没有就用硬编码兜底 */
  background: var(--btn-bg, var(--theme-primary, #1976d2));
}

开发者有时会错写成 var(--btn-bg, var(--theme-primary), #1976d2)。这时如果 --btn-bg 未定义,整个备用值变成 var(--theme-primary), #1976d2。浏览器把它替换进 background 后,内部的 var(--theme-primary) 会被求值,但最终拼出来的值格式可能不合法,导致声明无效。把 #1976d2 放进最内层 var() 的备用位才是正确写法。

已定义但值非法时不触发备用

有一个容易踩的坑:备用值只在自定义属性 guaranteed-invalid 时才启用。所谓 guaranteed-invalid,指的是变量未声明、显式设为 initial(且未用 @property 注册),或者存在循环依赖。

如果变量已经定义了,但值对目标属性不合法——比如 --x: 20px 然后写 color: var(--x, red)——浏览器不会用 red。变量替换发生在属性解析之前,替换后得到 color: 20px,这时才发现不合法,但已经来不及回退了,color 直接按 unset 处理。这个行为叫"无效值替换"(invalid at computed-value time)。

另外要注意 CSS 全局关键字:如果 --x 设成 inherit 或 revert,它们可能解析出有效值,同样不会触发备用。所以"变量存在就不用备用"和"变量有效才不用备用"是两回事,var() 走的是前一种逻辑。

回答前,多想一步

容易答错的地方

以为 var(--a, red, blue) 会依次尝试每个颜色
不会。逗号后面的所有内容是一个备用值 red, blue,不会拆开。如果属性只接受单个颜色值,这个备用值就不合法,属性变成 unset,既不是红也不是蓝。
把变量非法值和未定义混为一谈
变量未定义时备用值生效;变量已定义但值对属性不合法时,备用值不生效,属性直接走 unset。这两种情况的结果完全不同,面试时需要分开讲。
试着用自己的话回答

面试官还会怎么问?

除了嵌套 var(),还有其他方式给变量设默认值吗?

可以用 @property 注册自定义属性并指定 initial-value。这样变量未定义时自动用初始值,不需要在每个使用处写备用。但 @property 只能为单个变量提供一层默认值,不能替代嵌套 var() 的多级回退。

var() 的备用值可以包含哪些字符?

几乎任意字符都行,包括逗号和空格,但不能有未闭合的括号、分号和感叹号。也可以嵌套另一个 var()。逗号虽然能写,但它属于同一个备用值的一部分,不会分出新参数。

自定义属性未定义而且没写备用值会怎样?

var(--x) 在 --x 未定义时解析为 guaranteed-invalid,整条声明变成无效,属性按 unset 处理。如果属性是可继承的就继承父级的值,否则用初始值。

从一道题,走向一组知识

把知识连起来

层叠与选择器

CSS 自定义属性默认会继承吗?和普通属性有什么不一样?

自定义属性通过继承传递,和 var() 的备用值一起构成了 CSS 变量的完整取值逻辑。

层叠与选择器

当同时存在带 !important 和不带 !important 的规则时,默认的层叠优先级顺序是什么?

!important 改变的是层叠优先级,而 var() 回退走的是变量替换路径,对比两者能理清"值从哪来"的不同机制。

参考资料

  • var() CSS function

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. var() 语法只允许一个备用值
  3. 正确的多级回退要嵌套 var()
  4. 已定义但值非法时不触发备用
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑