先记住这个答案
判断同一元素、同一属性的冲突时,先比较来源与重要性。整体从低到高是:用户代理普通声明、用户普通声明、作者普通声明、关键帧动画产生的值、作者 !important、用户 !important、用户代理 !important、正在运行的 CSS 过渡值。普通声明中作者优先,重要声明中来源顺序反转。@layer 在同一来源内继续排序,不会让低来源的声明跨越高来源。
!important反转来源优先级,用户代理最高。- 层叠层中
!important顺序反转。 - 过渡样式高于所有
!important声明。
准确排序:先确定比较范围,再看选择器
先筛掉不匹配元素、条件不成立或无效的声明,再比较来源与重要性。同一来源内部还涉及层顺序、内联样式等规则;只有前面的条件打平,选择器特异性才有决定作用。支持 @scope 时,特异性打平后还可能比较作用域接近程度,最后才比较出现顺序。因此不能看到 ID 选择器就直接宣布它获胜。
例如,真正处于用户来源的普通 #content p 与作者来源的普通 p 同时设置颜色,后者会胜出;给用户规则加上 !important 后,用户重要声明又高于作者重要声明。这里改变结果的是来源与重要性,而不是选择器写得更长。面试回答可先给出完整顺序,再说明题目是否排除了动画、过渡、层和内联样式。
工程冲突:用户偏好与网页作者样式
假设用户样式表设置 p { color: gray !important; },网页作者设置 p { color: black !important; },并且没有正在影响该属性的过渡。用户重要声明获胜,段落显示灰色。这是同一元素上的声明竞争,不是继承;若灰色仅来自父元素,子元素自身的声明与继承值也不能按这一例子直接比较。
用户可能通过自定义样式提高对比度或调整阅读体验。作者不应试图通过更高特异性压过用户的重要声明,@layer 也不能改变来源之间的顺序。管理组件库和业务 CSS 的冲突时,可以在作者来源内划分层;验证用户来源的行为则要确认注入方式,扩展插入一个普通 <style> 标签仍属于作者样式,不能据此声称测试了用户样式。
适用边界:层、内联样式、动画和过渡
在同一来源中比较样式表规则时,普通声明通常是后声明的层优先,未分层普通声明又高于分层普通声明;重要声明则反过来,先声明的层优先,分层重要声明高于未分层重要声明。这个反转发生在来源内部,前面列出的来源顺序仍然成立。作者内联样式还需单独处理:普通内联声明高于作者样式表普通声明,但低于重要声明;重要内联声明高于作者样式表重要声明,仍低于用户和用户代理的重要声明。
关键帧动画产生的值高于普通声明、低于重要声明;关键帧里的 !important 声明本身会被忽略。正在运行的过渡为属性提供插值时,这个过渡值位于重要声明之上,但不是说 !important 永远不起作用:过渡是否触发、目标值是什么、是否被取消都要结合属性变化判断,过渡结束后仍按正常层叠确定最终值。
示例:在同一作者来源内观察层反转
将下面内容保存成 HTML,在支持 @layer 的浏览器中打开。它只验证作者样式表中的层顺序,不模拟用户或用户代理来源,也没有设置动画、过渡或内联样式。
验证“CSS !important cascade precedence order”时,应固定输入、运行环境与触发顺序,并同时记录正常结果和失败结果。这样能确认本节结论来自目标机制,而不是缓存、旧状态或偶然时序。
<style>
@layer base, theme;
@layer base {
p { color: red; }
}
@layer theme {
p { color: blue !important; }
}
p { color: green !important; }
</style>
<p>文本颜色?</p>文本应为蓝色:theme 层的重要声明高于未分层的重要声明,普通的红色声明也无法与它竞争。若给 base 层的红色声明也加上 !important,文本应改为红色,因为 base 比 theme 更早声明。用开发者工具查看命中的声明及被划掉的候选,再对照计算样式,可以把“来源”和“层”的比较范围分开验证。
容易答错的地方
- 认为 !important 让选择器权重无限大
!important是重要性标记,不是给选择器特异性加一个巨大数字。用户来源的重要声明可以压过作者来源的重要内联样式。排查时先看来源与重要性,再进入同一比较范围检查层、特异性等条件。- 认为 @layer 能改变作者与用户的先后
- 层只在各自来源内部排序,不能让作者普通声明超过用户重要声明。把第三方普通样式放到较早的层可以降低它在作者来源中的优先级;如果第三方用了重要声明,则要按反转后的层顺序分析,不能继续套用普通声明的口诀。
面试官还会怎么问?
为什么重要声明要反转来源顺序?
这样用户的重要偏好能覆盖页面作者的样式,用户代理的重要约束又能优先于两者。这对阅读偏好和浏览器控制有意义。回答时应强调覆盖能力属于不同来源,而不是建议业务代码靠不断叠加 !important 解决冲突。
style 属性中的 !important 一定最高吗?
它高于作者样式表中同属性的重要声明,包括分层的重要声明,但仍低于用户重要、用户代理重要以及生效中的过渡值。讨论内联优先级必须说明来源与重要性,不能只说“内联大于外部 CSS”。
过渡期间 important 被覆盖,结束后怎么办?
过渡期间显示的是过渡产生的插值;结束、取消或不再参与该属性的计算后,按剩余声明和效果重新确定值。因此要分别查看触发前的值、目标状态下的层叠结果和当前过渡状态,不能把一帧的颜色当成重要声明永久失效。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。