前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 custom property inheritance behavior
CSS层叠与选择器

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

自定义属性默认继承,和 color、font-size 一样会沿着 DOM 树传给后代。子元素声明同名属性就能覆盖继承值。特殊的地方在于:未注册的自定义属性初始值是「保证无效值」,用 initial 重置后 var() 引用会失效,而不是变成某个具体值。

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

自定义属性的继承行为

  1. 默认继承和 color 一样沿 DOM 树向下传递
  2. 覆盖子元素声明同名自定义属性就屏蔽继承值
  3. initial重置为「保证无效值」,不是空字符串也不是 0

unset 对自定义属性等同于 inherit,因为它默认就是可继承的。想阻止继承要用 initial 或 @property 设 inherits: false。

核心回答

先记住这个答案

CSS 自定义属性(--*)默认是继承的。在父元素上声明 --color: red,子元素不声明的话就会继承这个值,通过 var(--color) 拿到的就是 red。子元素可以声明同名的自定义属性来覆盖继承值,只影响自己和自己的后代。这和 color、font-size 这些普通可继承属性的行为完全一样。 特殊的是初始值。普通属性的初始值是规范定义好的(比如 color 的初始值是 canvastext),但未注册的自定义属性初始值是一个叫「保证无效值」的特殊标记。把自定义属性设成 initial,它就变成这个标记,var() 引用时会当作未定义来处理。

  • 自定义属性默认会继承
  • 子元素声明同名属性可以覆盖继承值
  • initial 可使自定义属性无效
  • inherits: false 可关闭继承

继承在 DOM 树上一层层传

自定义属性的继承和普通属性走同一套机制:从 :root 开始,沿着 DOM 树逐层向下。中间任何一个节点声明了同名属性,它下面的后代就用新值,不再往上找。

继承链上的覆盖CSS
:root { --main-color: #333; }
.parent { --main-color: #555; }
.child { background: var(--main-color, #000); }

如果 .child 是 .parent 的后代,--main-color 取到的是 #555,因为 .parent 覆盖了 :root 的值。如果 .child 不在 .parent 下面,取到的是 :root 的 #333。如果连 :root 都没声明,var() 的第二个参数 #000 生效。 这个机制非常适合做主题切换。在 :root 上定义一整套 --theme-* 变量,组件默认使用这些变量。某个区域需要不同主题时,在这个区域的根元素上重新声明同名变量,所有后代自动用新值,不需要改组件代码。

initial 不是空值,是「保证无效值」

很多人以为 --x: initial 会让 --x 变成空字符串或者 0,实际上未注册的自定义属性的初始值是一个特殊标记,叫 guaranteed-invalid value。这个值不是任何合法的 CSS 值,任何引用它的 var() 都会被视为变量未定义,走回退逻辑。

initial 和 unset 的区别CSS
.parent { --x: red; }

/* initial:重置为保证无效值,var(--x) 在这里未定义 */
.child-a { --x: initial; color: var(--x, blue); }

/* unset:自定义属性默认继承,所以 unset 等同于 inherit */
.child-b { --x: unset; color: var(--x, blue); }

.child-a 用了 initial,--x 变成保证无效值,var(--x, blue) 走回退,color 是 blue。.child-b 用了 unset,因为自定义属性默认继承,unset 等同于 inherit,所以 --x 继承父元素的 red,color 是 red。 这个区别很容易搞混。记住一个判断方法:unset 对可继承属性等同于 inherit,对不可继承属性等同于 initial。自定义属性默认可继承,所以 unset 就是 inherit。

用 @property 控制继承行为

默认情况下自定义属性都会继承,但有时候你希望某个变量只在声明它的元素上有效,不要传给后代。CSS 的 @property 规则可以做到。

@property 用来注册一个自定义属性,给它指定类型、初始值和是否继承。设置 inherits: false 后,这个属性就不再继承了。子元素要用的话必须自己声明。

注册一个不继承的属性CSS
@property --local-size {
  syntax: '<length>';
  inherits: false;
  initial-value: 16px;
}

注册之后,--local-size 的初始值不再是「保证无效值」而是 16px,并且不会继承。没声明的元素取到的是 16px,不是父元素的值。注册还有一个好处:指定了 syntax 之后浏览器知道值的类型,就可以做过渡动画了。 伪元素(::before、::after)也遵循继承机制。它们被当作父元素的子元素,会继承父元素的自定义属性值。用 @property 设了 inherits: false 的属性,伪元素同样拿不到继承值。

回答前,多想一步

容易答错的地方

以为自定义属性不继承
这是最常见的错误。自定义属性默认就是继承的,不需要额外声明。除非用 @property 显式设置 inherits: false,否则它一定会沿 DOM 树向下传递。
以为 initial 和 unset 效果一样
对自定义属性来说,initial 会把值重置为保证无效值(变量相当于未定义),而 unset 等同于 inherit(继承父元素的值)。两者效果完全不同,混用会导致样式出错。
试着用自己的话回答

面试官还会怎么问?

怎么阻止子元素继承某个自定义属性?

两种办法。第一种是在子元素上显式声明 --x: initial,让它变成未定义。第二种是用 @property 注册时设置 inherits: false,从根源上关掉继承。第二种更干净,不需要在每个子元素上都写一遍。

伪元素能拿到父元素的自定义属性吗?

可以。::before 和 ::after 在继承关系上属于父元素的子元素,自定义属性照常继承。如果在父元素上声明了 --color: red,伪元素里的 var(--color) 能正常取到 red。

自定义属性名区分大小写吗?

区分。--main-color 和 --Main-color 是两个完全不同的属性,不会互相覆盖。实际项目里建议统一用小写加连字符的命名风格,避免混乱。

从一道题,走向一组知识

把知识连起来

层叠与选择器

inherit、initial 和 unset 分别把属性重置到哪个值?

这篇详细对比 inherit 和 initial 以及 unset 三个关键字在普通属性上的行为,和自定义属性的差异刚好可以对照看。

层叠与选择器

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

自定义属性的值确定后还要经过层叠排序,!important 的层叠优先级规则同样适用于包含 var() 的声明。

层叠与选择器

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

var() 的第二个参数是回退值,它只在变量未定义时生效,和 initial 导致的失效走的是同一条回退路径。

参考资料

  • Custom properties (--*): CSS variables

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

本题目录
  1. 先记住这个答案
  2. 继承在 DOM 树上一层层传
  3. initial 不是空值,是「保证无效值」
  4. 用 @property 控制继承行为
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

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

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