对页面上的元素来说,通常会有很多样式应用于其上,但是一个元素不可能背景色既是红色又是绿色。
所以当样式的定义发生冲突时浏览器会通过如下规则来判断最终采用哪条样式来渲染元素。
这个过程就称为样式的层叠 (Cascade)。
重要规则(包含关键字 !important
)优先于普通规则,例如以下样式:
p { color: red !important }
那么无论你在何处以什么样的选择器去定义另外的 color
只要不使用 !important
段落的字体颜色最终都是红色
如果是俩条重要规则发生冲突呢 ?
首先根据来源判断:读者定义的重要规则 > 开发人员定义的重要规则
如果把普通规则也加入排序的话:
读者定义的重要规则 > 开发人员定义的重要规则 > 开发人员定义的普通规则 > 读者定义的普通规则 > 浏览器默认规则
Ps: 通常来说不建议使用 !important
除非你需要覆盖一些不受你控制的内联样式
当俩条规则的重要性相同时,则接下来需要判断特殊性。
特殊性是针对选择器而言的:
内联样式没有选择器,特殊性永远为 1-0-0-0
,所以内联样式比所有通过选择器定义的样式优先级都要高
规则中每出现一个 ID 选择器特殊性增加 0-1-0-0
每出现一个类选择器/伪类选择器/属性选择器特殊性增加 0-0-1-0
每出现一个元素选择器/伪元素选择器增加 0-0-0-1
连接符/通配符特殊性为 0-0-0-0
继承而来的规则没有特殊性
Ps: 需要特别注意的一点是特殊性为 0-0-0-0
和没有特殊性是不一样的
简单来讲就是通配符设置的样式会覆盖掉元素继承而来的样式,这点很容易导致问题,所以通常不建议使用通配符来设置页面样式,例如有如下样式:
* {
color: red;
}
p {
color: black;
}
我们希望页面上的段落中字体颜色都为黑色,由于样式继承的存在,假设我们的文档结构如下
<p>...<em>...</em>...</p>
我们会认为 <em>
会继承 <p>
的样式,字体颜色同样为黑色,但结果可能会出乎意料 <em>
的字体颜色会显示为红色。
这是因为继承而来的样式没有特殊性,而通配符设置的样式特殊性为 0,哪怕是 0 特殊性仍然会覆盖掉没有特殊性的样式。
下面都在讨论选择器的特殊性,所以为了看起来方便把最高位代表内联样式的 0 去掉了
此外还有如下个种特殊情况:
:where()
虽然是伪类但特殊性为 0, 0, 0
例如
.qux:where(em, #foo#bar#baz)
的特殊性为0, 1, 0
:is()
:not()
:has()
的特殊性与其参数列表中特殊性最高的选择器相同例如
:is(em, #foo)
的特殊性为1, 0, 0
:nth-child()
:nth-last-child()
的特殊性为其参数列表中特殊性最高的选择器加上其作为伪类的特殊性例如
:nth-child(even of li, .item)
的特殊性为0, 2, 0
最后举几个例子来更好的理解特殊性:
* /* 0, 0, 0 */
li /* 0, 0, 1 */
ul li /* 0, 0, 2 */
ul ol+li /* 0, 0, 3 */
h1 + *[REL=up] /* 0, 1, 1 */
ul ol li.red /* 0, 1, 3 */
li.red.level /* 0, 2, 1 */
#x34y /* 1, 0, 0 */
#s12:not(FOO) /* 1, 0, 1 */
.foo :is(.bar, #baz) /* 1, 1, 0 */
需要注意特殊性是按位进行比较的,所以只有当高位的值相等时才会继续对低位进行比较。例如 1, 0, 0
> 0, 10, 0
> 0, 0, 100
如果俩条规则的重要性/来源/特殊性都一致,则在样式表中更靠后出现的样式会覆盖先前的样式。
对于作用于同一元素的任意俩条规则,首先比较来源 > 来源相同再比较重要性 > 重要性相同再比较特殊性 > 都相同最后比较先后顺序。
这样最终一定能确定哪一条规则会胜出。