先记住这个答案
子元素上只要有任何一条规则直接设置了同一个属性,继承值就不会生效。继承在层叠中的优先级最低——它不是一个"声明",而是属性没有任何声明时的回退机制。哪怕子元素上的声明来自通配符 *,特异性只有 (0,0,0),也比继承值优先。
- 继承值优先级低于任何直接声明
- 通配符
*的声明也能覆盖继承 - 没有直接声明时才回退到继承
inherit关键字是直接声明,不是被动继承
层叠里的"声明"和"继承"是两回事
CSS 判断一个属性的最终值时,先收集所有匹配到该元素并设置了该属性的声明,按来源、重要性、特异性和出现顺序决出胜者。继承值不在这个竞争队列里。只有当竞争队列为空——也就是没有任何规则匹配到这个元素并设置这个属性时——继承值才会作为兜底出场。
/* 父元素 */
.parent { color: red; }
/* 通配符匹配所有元素,特异性 (0,0,0) */
* { color: black; }.parent 的子元素颜色是 black,不是从父元素继承的 red。因为 * 是直接匹配子元素的声明,优先级再低也比继承值高。如果去掉 * { color: black } 这条规则,子元素上没有任何 color 声明了,这时才会继承到父元素的 red。
inherit 关键字和被动继承的区别
写 color: inherit 看起来和自动继承效果一样,但它的身份完全不同。color: inherit 是一条直接声明——选择器匹配了这个元素,声明了 color 属性,值是 inherit。它和 color: red 一样参与层叠竞争,优先级取决于选择器特异性,不会因为值是 inherit 就降低。
inherit 声明参与正常的特异性竞争CSS.parent { color: red; }
/* 类选择器,特异性 (0,1,0) */
.child { color: blue; }
/* 通配符,特异性 (0,0,0),想强制继承 */
* { color: inherit; }.child 元素的颜色是 blue,因为 .child 的特异性高于 * 的特异性。inherit 关键字不会给声明加任何特殊权重。如果想让 inherit 生效,要提高选择器的特异性,或者加 !important。
在开发者工具里怎么分辨
在 Chrome 开发者工具的 Elements 面板中,选中一个元素查看 Styles 标签页。所有直接匹配该元素的声明都会列出来,优先级低的被划线划掉。继承来的值则单独显示在"Inherited from xxx"分组里。
如果你看到某个属性在 Inherited 分组里有值,但在 Styles 里也有一条直接声明,最终一定是直接声明生效。只有 Styles 列表里完全没有出现这个属性,Inherited 的值才会生效。排查样式问题时,先看有没有直接声明,再考虑继承。
容易答错的地方
- 以为继承值也参与特异性比较
- 继承值没有特异性可言。有人会说"父元素的
.parent选择器特异性是 (0,1,0),比子元素的*高",但这个比较没有意义。.parent的color: red是匹配父元素的声明,它给父元素设了red。子元素的继承值来自父元素的计算值,但它本身不携带任何特异性。 - 以为
inherit是"继承"所以优先级低 inherit是一个 CSS 关键字值。写了color: inherit,这就是一条正常的声明,参与正常的层叠竞争。它和color: red在层叠中的身份完全相同,区别只是最终取的值不同。
面试官还会怎么问?
如果父元素用了 !important,子元素的普通声明还能赢吗?
能。父元素的 !important 只影响父元素自身属性的层叠结果。子元素从父元素拿到的是计算值,这个计算值到了子元素身上就变成了一个普通的继承值,不带 !important。子元素上的任何直接声明都能覆盖它。
在 @layer 里声明的样式,优先级还是高于继承吗?
是的。@layer 只影响同一来源内多条直接声明之间的排序。哪怕某条声明在优先级最低的层里,它对当前元素来说仍然是直接声明,优先级仍然高于继承值。
怎么让子元素强制用父元素的值?
写 inherit 关键字。比如 color: inherit 会让子元素取父元素的 color 计算值。如果其它声明特异性更高覆盖了这条 inherit,可以提高选择器的特异性或者加 !important。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。