第 8 课 9 / 18 | 编码:L08-12
核心知识

特异性的计算与比较

先确认同一元素、同一属性;再比特异性,相同才看书写顺序。

两个例子共用这份 HTML

<section class="panel">
  <p class="card active">活动通知</p>
</section>

.card.active 连写:同一个元素同时有两个类。
.card .active 有空格:选中 .card 内带 active 类的后代。

例①:后写的不一定生效

.panel .card.active { color: crimson; }
.panel .card        { color: teal; }

两条都匹配段落:(0,3,0) 高于 (0,2,0),文字为深红色。交换顺序也不变。

例②:相同时,后写的生效

.panel .card   { color: teal; }
.panel > .card { color: crimson; }

两条都是 (0,2,0),文字为深红色;交换顺序后变为青绿色。> 不加分。

① 计数:统计选择器组成部分的数量

把组成部分分成三组,分别数有几个,按顺序记为:

(ID 数,类/属性/伪类数,元素/伪元素数)

.panel .card 没有 ID,有 2 个类,没有元素或伪元素选择器,所以记为 (0,2,0)。

② 从左向右,逐组比较

第一组相同才比第二组,第二组相同才比第三组;不相加、不进位。

(1,0,0) > (0,3,0) > (0,2,0)。空格、> 和 * 不增加计数。

③ 什么时候才看顺序?

同一个元素的同一个属性发生竞争,并且前面的层叠条件相同时,先比特异性。三组都相同,才由后写的声明胜出。

这里看的是 CSS 声明的顺序,不是 HTML 中类名的顺序。class="card active" 与 class="active card" 不改变这些类选择器的匹配结果或特异性。

本页限定:作者样式中的普通规则,不含行内样式、!important、层叠层、@scope、动画或过渡。

运行演示:例①比较特异性,例②比较书写顺序

例①:比较特异性

<style>
.panel .card.active { color: crimson; }
.panel .card        { color: teal; }
</style>
<section class="panel">
  <p class="card active">活动通知</p>
</section>

例②:比较书写顺序

<style>
.panel .card   { color: teal; }
.panel > .card { color: crimson; }
</style>
<section class="panel">
  <p class="card active">活动通知</p>
</section>
补充对照:.card.active 与 .card .active

.card.active 要求同一个元素同时具有 card 和 active 两个类;写成 .active.card 含义也相同。

.card .active 中的空格表示后代关系:选中 .card 内部具有 active 类的元素,不限于直接子元素。

<style>
.card.active { color: crimson; }
.card .active { color: teal; }
</style>
<p class="card active">A:同一个元素有两个类</p>
<div class="card">
  <p class="active">B:active 元素在 card 内部</p>
</div>

A 为深红色:A 自己同时有两个类,匹配 .card.active;但它不在另一个 .card 内部,不匹配 .card .active。

B 为青绿色:B 自己只有 active 类,外层元素有 card 类,因此匹配 .card .active,不匹配 .card.active。

先看匹配,再谈优先级:两个选择器的特异性都是 (0,2,0)。本例颜色不同,是因为选中了不同元素,并不是其中一个选择器的特异性更高;没有匹配该元素的规则,不参加比较。

补充对照:HTML 类名顺序不影响样式优先级

下面两个段落只有 class 中类名的顺序不同,但它们都具有 card 和 active 两个类。

<style>
.active { color: crimson; }
.card { color: teal; }
</style>
<p class="card active">A:card 写在前面</p>
<p class="active card">B:active 写在前面</p>

运行结果:两个段落都是青绿色。两条规则都匹配这两个段落,特异性也同为 (0,1,0),因此后写的 .card 声明决定颜色。

只调换 HTML 类名顺序:仍然都是青绿色。class 列出元素具有哪些类,不是在排列样式优先级。

调换 CSS 规则顺序:让 .active { color: crimson; } 写在后面,两个段落都会变为深红色。

本例中其他层叠条件相同:先比较选择器特异性;特异性相同,再比较 CSS 声明的书写顺序,不比较 HTML 类名的排列顺序。

拓展:特殊伪类的特异性计数

:where() 的特异性为零;:is()、:not()、:has() 本身不按一个普通伪类计数,而采用参数列表中最高的特异性。例如 :is(#notice, .card) 为 (1,0,0)。本页两个基础例子不涉及这些例外。