先记住这个答案
内联样式和 !important 是 CSS 层叠机制中两个不同层面的东西。内联样式写在 HTML 元素的 style 属性上,不经过选择器,在普通作者声明中高于样式表里的选择器规则。!important 不是在选择器优先级的三列里加了一列,而是把声明提升到一个更高的层叠层级——重要声明按来源、层和选择器等规则排序。完整层叠还包括用户、浏览器来源以及动画和过渡值,不能把内联重要样式说成全局最高。
- 普通作者内联样式高于作者选择器规则
!important把声明提到更高的层叠层级- 作者重要声明高于普通内联样式
- 两条都带
!important时仍比选择器优先级
层叠的完整比较顺序
浏览器决定一个属性的最终值时,先按来源和层级把所有声明分组,再在组内按选择器优先级排名。
/* 1. 普通选择器规则(最低)*/
.box { color: blue; }
/* 2. 内联样式(赢过所有选择器规则)*/
/* <div class="box" style="color: red;"> */
/* 3. !important 选择器规则(赢过内联)*/
.box { color: green !important; }
/* 4. !important 内联样式(最高)*/
/* <div style="color: orange !important;"> */只比较这些作者声明,从低到高排:普通选择器规则、内联样式、!important 选择器规则、!important 内联样式。上面的例子里如果四条都作用于同一个元素,最终颜色是橙色,因为在这四条作者声明中,重要内联的优先级最高。
这个顺序说明两件事。一是 !important 的层级高于内联样式。所以在样式表里写 .box { color: green !important; } 可以覆盖 style="color: red;"。二是同为 !important 时,优先级比较重新回到选择器体系:#id { color: green !important; } 赢过 .class { color: red !important; },因为 ID 优先级高于类。
什么时候会碰到内联样式
日常手写 HTML 时很少用内联样式,但有几个场景会不经意间产生它。JavaScript 通过 element.style.color = 'red' 设置的就是内联样式,React 的 style={{ color: 'red' }} 也是。邮件模板里几乎全部用内联样式,因为邮件客户端不一定支持 <style> 标签。第三方富文本编辑器输出的内容也经常带内联样式。
想从样式表覆盖这些内联样式,只能用 !important。这就是为什么有些项目会在全局重置样式里看到 !important——它不是乱加的,而是为了覆盖 JavaScript 或第三方代码注入的内联值。
!important 的层叠层交互
引入 @layer 之后,!important 的比较规则会反转。普通声明里,后声明的层优先级更高;但在 !important 声明里,先声明的层反而更高。这是规范刻意设计的:基础层里的 !important 应该是不可覆盖的保护性样式。
比如 @layer base, override; 中,普通声明 override 层赢过 base 层,但 !important 声明 base 层赢过 override 层。同理,未入层的 !important 声明反而低于层内的 !important 声明——这和普通声明里未入层高于层内的关系完全相反。
面试时把这个反转规则说出来,是明显的加分点。
容易答错的地方
- 以为
!important是在优先级上加了一列 !important不参与选择器优先级的三列计算。它的作用是把声明从普通层级提升到!important层级,两个层级分开排名。只有在同一层级内部,才按选择器优先级比大小。- 以为内联样式不可覆盖
- 外部样式表里加
!important就能覆盖内联样式。!important层级高于内联层级。但!important内联样式就真的很难覆盖了,只有用户样式表的!important或浏览器特殊机制才能赢过它。
面试官还会怎么问?
两个 !important 声明冲突了怎么判?
回到正常的优先级比较。先比选择器优先级:ID 列高的赢。优先级也一样就比来源顺序:后写的赢。如果用了 @layer,注意层间比较是反转的,先声明的层里的 !important 赢过后声明的层。
JavaScript 的 element.style 为什么优先级这么高?
element.style 设置的就是内联样式,写在元素的 style 属性上。内联样式不走选择器,天然高于所有选择器规则。要用 CSS 覆盖它只能加 !important。
有什么办法不用 !important 就覆盖内联样式?
CSS 层面没有。但可以用 JavaScript 把内联值清空,比如 element.style.color = '',让元素回退到样式表规则。或者用 element.style.setProperty('color', 'blue', 'important') 在 JavaScript 端设置一个带 !important 的内联值。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。