先记住这个答案
对于可继承属性(如 color),inherit 取父元素计算值,initial 取初始值(通常黑色),unset 等价于 inherit,因为默认行为是继承。对于不可继承属性(如 margin),inherit 强制取父元素计算值,initial 取初始值(如 0),unset 等价于 initial,因为默认不继承。关键在于 unset 是动态依据属性类型的。
- inherit 强制继承父元素计算值
- initial 强制使用属性初始值
- unset 按属性继承性自动选择
属性继承性决定 unset 的关键行为
CSS 的每个属性都有预设的继承性:有的默认从父元素继承(如 color、font-family),有的默认不继承(如 margin、padding)。这三个关键字之所以重要,在于它们绕过普通层叠规则直接指定如何取值。inherit 无论属性是否可继承,都强制使用父元素的计算值;initial 则强制使用该属性的初始化值,该值由规范定义,与元素或父级无关。
unset 的设计是让开发者无需判断属性继承性:若属性默认可继承,则 unset 等同于 inherit;若默认不可继承,则等同于 initial。例如对 div 设置 color: unset,结果等同于 color: inherit,因为 color 可继承;而 margin: unset 则等同于 margin: initial(即 0),因为 margin 不可继承。理解这一动态等价是掌握 unset 的核心。
组件重置样式中如何安全使用 unset
假设构建一个卡片组件,希望重置内部所有元素的样式以隔离外部影响。你书写 .card { all: unset; } 是否可行?all 是简写属性,unset 会应用于所有属性,但效果取决于每个属性的继承性。字体和颜色等可继承属性将继承 .card 的父级值,而 margin 等不可继承属性则回退到初始值。若想让卡片完全不被外部文字样式污染,仅靠 all: unset 不够,因为继承属性仍会从父级取值。
正确处理是显式设置 .card { all: unset; color: initial; font: initial; } 或使用 .card { all: revert; }(但 revert 不在本题范围)。实际工程中,对于不可控的外部环境,偏好在组件根节点同时声明 all: unset 和关键可继承属性为 initial,阻断向上继承。这样保证内部默认样式与父级无关,代价是失去有意继承的便捷性,需自行设计具体值。
失效边界:不适用于非计算值且需理解继承源
一个常见误区是将 inherit 用于获取父元素的指定值而非计算值。实际上 inherit 取回的是父元素的计算值,若父元素某属性值为未显式设置,可能继承自更高祖先。例如 body 未设置 color,则段落 color: inherit 取 body 的计算值即浏览器默认黑色。对于可继承属性,unset 并不会阻断继承链中的已有继承值,它只是让属性回到“自然”状态。
另一种失效场景是属性为简写或逻辑属性时。例如 margin-inline: unset 会展开为 margin-inline-start/end 的 unset,而它们各自动态选择 initial 或 inherit。由于 margin-inline-start/end 均不可继承,unset 等价于 initial。若父元素只设置了 margin-left,子元素设置 margin-inline-start: inherit,取的是父元素中 margin-inline-start 的计算值,该值在父元素未设置时为初始值 0,而非 margin-left 的值。因此需要区分物理属性和逻辑属性。在不明确细节时,使用 all 关键字更简单,但 all: unset 依然受属性继承性影响,不能期待它消灭一切继承。
容易答错的地方
- 认为 unset 总是等价于 initial
- 错误。unset 依据属性是否为继承属性而决定。对于 color 这类可继承属性,unset 等价于 inherit,会从父级取值;对于 margin 则等价于 initial。如果误以为 unset 一律重置为初始值,会破坏继承效果。
- 混淆 all: unset 与 all: initial 的效果
- all: unset 会按每个属性分别应用 inherit 或 initial,可继承属性将继承父值,不可继承属性被置为初始值。all: initial 则全部置为初始值,会切断所有继承,但二者行为不同。
面试官还会怎么问?
为什么继承属性上使用 inherit 常常是多余的?
因为可继承属性本来就默认继承,只要没有其他规则覆盖,普通声明就会取父元素计算值。需要显式 inherit 的地方是当另一条更高优先级规则试图覆盖该属性时,用 inherit 强制恢复继承。
initial 与直接不声明属性有何不同?
直接不声明时,可继承属性会从父级继承,而不可继承属性用初始值;initial 则无视继承性,全部置为规范定义的初始值。例如对可继承的 color 设置 initial 会变成黑色(通常),而非继承父级颜色。
如何快速判断 unset 在某属性上的效果?
查阅该属性的 MDN 文档中的 Formal definition 部分,查看 Inherited: 是否为 yes。若是,unset 相当于 inherit;否则等价于 initial。对于自定义属性,unset 等价于 inherit,因为自定义属性默认继承。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。