先记住这个答案
自定义属性(--*)在 CSS 中默认是继承的,类似于 color、font 等可继承属性。这意味着如果父元素设置了 --main-color,而子元素没有定义,那么子元素会继承该值。但继承仅发生在属性未被覆盖时;子元素可以显式设置相同的自定义属性来覆盖继承值。若想强制继承或重置,可以使用 inherit、initial、unset 等关键字。
- 自定义属性默认继承
- 子元素可覆盖继承值
- initial重置为无效,unset等同inherit
继承机制与自定义属性的特殊性
自定义属性(--*)被设计为继承的,这意味着当在某个元素上声明了 --main-color: red,它的所有后代元素都能通过 var(--main-color) 获取该值,除非某个后代自己声明了同名自定义属性,从而覆盖该继承值。这与 color 等普通可继承属性的行为类似。
当自定义属性设置为 initial 时,其值变为‘保证无效值’(guaranteed-invalid),此时若在 var() 中引用且无备用,声明会变为无效。而 unset 则根据该属性是否可继承:可继承时等同于 inherit,不可继承时等同于 initial(即保证无效值)。
:root { --main-color: #333; }
.parent { --main-color: #555; }
.child { background: var(--main-color, #000); }若 .child 的祖先为 .parent,则 --main-color 值为 #555;若 .parent 未定义则继承 :root 的 #333;若都没有设置则取备用值 #000。
在主题切换中的应用
需求:实现一个支持明暗主题切换的组件,要求组件内部所有颜色都根据主题变化,且允许子组件覆盖特定主题变量。实现:在 :root 上定义整套 --theme- 前缀变量,组件内部默认使用这些变量,但允许在组件根元素上覆盖以定制局部主题。
方法:在 :root { --bg: white; --fg: black; },组件 .card { background: var(--bg); color: var(--fg); }。若某个卡片需要暗色,只需在该卡片元素上设置 { --bg: #333; --fg: white; },由于继承,其内部元素自动使用新变量,而其它卡片不受影响。
继承的失效边界与处理
当自定义属性未注册时,其初始值是一个‘保证无效值’,此时 var() 引用会失效。此外,自定义属性不参与动画,除非用 @property 注册并指定 syntax。继承在元素树上生效,伪元素同样继承其父元素的自定义属性。
若要阻止继承,可以在子元素上设置 initial 或显式声明一个值;若想要局部作用域,可在组件根元素定义变量,并通过 CSS 模块或 BEM 约定管理命名以避免冲突。注意,自定义属性名区分大小写,--main-color 和 --Main-color 是两个不同的属性。
容易答错的地方
- 误以为自定义属性不继承
- 实际上默认继承,与普通可继承属性相同。若在父元素设置 --x: red,子元素未设置时会继承该值,除非子元素显式覆盖。
- 认为 initial 会继承父值
- initial 将属性设置为初始值,而非继承值。对于未注册的自定义属性,initial 使其为‘保证无效值’,此时 var() 引用无效。
面试官还会怎么问?
如何强制子元素不使用继承的自定义属性?
可在子元素上设置 --x: initial;,此时 var(--x) 在没有备用时失效;也可设置 --x: unset; 但由于自定义属性默认可继承,unset 会继承祖先值,不会阻止继承,因此要强制不使用继承,应使用 initial 或显式声明一个值。
自定义属性在伪元素上是否继承?
是的,自定义属性遵循正常的继承机制。伪元素如 ::before 和 ::after 是父元素的子元素,因此会继承父元素上定义的自定义属性值。例如,若父元素设置 --main-color: red,那么 ::before 中的 var(--main-color) 会得到 red。同样,伪元素自身也可以声明自定义属性,但其值不会影响父元素或其他兄弟元素。
用 @property 注册的自定义属性继承如何控制?
在 @property 中设置 inherits: false,则该属性不会继承,这与未注册时默认继承的行为相反;若设置 inherits: true,则保持继承,与默认一致。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。