特异性(优先级)
特异性值可以分为三部分,如 0,0,0。实际选择器的特异性如下确定:
对于选择器中的每个ID属性值,添加1,0,0。
对于选择器中的每个类属性值、属性选择或伪类,添加0,1,0。
对于选择器中的每个元素和伪元素,添加0,0,1。
组合器对特异性没有贡献。
:where()伪类中列出的任何内容以及通用选择器添加0,0,0。(虽然它们对特异性权重没有贡献,但它们确实匹配元素,不同于组合器。)
:is()、:not()或:has()伪类的特异性等于其选择器列表参数中最特定选择器的特异性。
例如,以下规则的选择器会导致指示的具体性:
h1 {color: red;} /* 具体性 = 0,0,1 /
p em {color: purple;} / 具体性 = 0,0,2 /
.grape {color: purple;} / 具体性 = 0,1,0 */
.bright {color: yellow;} / 具体性 = 0,1,0 /
p.bright em.dark {color: maroon;} / 具体性 = 0,2,2 /
#id216 {color: blue;} / 具体性 = 1,0,0 */
: is(aside#warn, code) {color: red;} / 具体性 = 1,0,1 /
div#sidebar [href] {color: silver;} / 具体性 = 1,1,1 /
如果一个<em>元素同时被本例中的第二条和第六条规则匹配,那么该元素将呈现褐红色,因为第六条规则的具体性超过了第二条规则的具体性。
特别注意下一个选择器 : is(aside#warn, code) 。伪类 :is() 是一组具有等于选择器列表中最具体选择器的具体性的伪类之一。在这里,选择器列表是 aside#warn, code 。aside#warn 复合选择器的具体性为1,0,1,而 code 选择器的具体性为 0,0,1。因此,整个 :is() 部分的选择器设置为 aside#warn 选择器的具体性。
注意:通用选择器(*),子选择器(>),和相邻同胞选择器(+)并不在这个等级中,所以他们的权值为0。
声明和特性
一旦选择器的特性得到确定,特性值将被赋予所有关联的声明。考虑以下规则:
h1 {color: silver; background: black;}
从特性角度来看,用户代理必须将规则视为单独的规则。因此,前面的例子将变为以下内容:
h1 {color: silver;}
h1 {background: black;}
两者都具有0,0,1的特性,这就是赋予每个声明的值。同样的分组过程也发生在分组选择器中。考虑到以下规则:
h1, h2.section {color: silver; background: black;}
用户代理将其视为以下内容:
h1 {color: silver;} /* 0,0,1 /
h1 {background: black;} / 0,0,1 /
h2.section {color: silver;} / 0,1,1 /
h2.section {background: black;} / 0,1,1 */
当多个规则匹配同一个元素且部分声明冲突时,这一点变得很重要。例如,考虑以下规则:
h1 + p {color: black; font-style: italic;}
p {color: gray; background: white; font-style: normal;}
*.callout {color: black; background: silver;}
当应用于以下标记时,内容将如图4-1所示呈现:
<h1>Greetings! </h1>
<p class="callout">
It' s a fine way to start a day, don' t you think?
</p>
<p>
There are many ways to greet a person, but the words are
as the act of greeting itself.
</p>
<h1>Salutations! </h1>
<p>
There is nothing finer than a hearty welcome from one' s
</p>
<p class="callout">
Although a steaming pot of fresh-made jambalaya runs a
</p>
解决多个匹配
当一个元素被分组选择器中的多个选择器匹配时,使用最具体的选择器。
考虑以下CSS:
li, /* 0,0,1 /
.quirky, / 0,1,0 /
#friendly, / 1,0,0 /
li.happy.happy.happy#friendly { / 1,3,1 */
color: blue;
}
<li class="happy quirky" id="friendly">This will be blue. </li>
分组选择器中的每个选择器都适用于列表项!在特定性方面使用哪个选择器?最具体的。因此,在这个例子中,蓝色是以1,3,1的特性被应用的。
你可能已经注意到,我们在其中一个选择器中重复了三次happy类名。这是一种可以用于类、属性、伪类甚至ID选择器以增加特性的技巧。在使用时要小心,因为人为地增加特性可能会在未来造成问题:你可能想要用另一个规则覆盖该规则,而那个规则需要更多类名串联在一起。
零选择器特定性
通用选择器对特性没有贡献。它的特性为0,0,0,对于:where()伪类也是如此,无论它的选择器列表中有什么选择器。因此,:where(aside#warn, code)的特性为0,0,0。 组合器,包括~、>、+和空格字符,完全没有特性,甚至没有零特性。因此,它们对选择器的整体特性没有影响。
ID和属性选择器特异性
需要注意的是,ID选择器和针对id属性的属性选择器之间的特异性差异。
#meadow {color: green;} /* ID选择器 1,0,0 */
[id="meadow"] {color: red;} / * 针对id属性的属性选择器 0,1,0 */
!important 特异性
标记为' “!important” 没有特殊的具体值, 而是与不重要的声明分开考虑。 因此, 在重要的和不重
要的声明冲突的任何情况下, 重要的声明“总是” 获胜。(也就是 !important 最高)。
警告 通常在CSS中使用 !important是不好的做法,而且很少需要。如果你发现自己要使用!important,请停下来寻找其他方法来获得相同的结果,而不要使用!important。
继承
继承是某些样式不仅应用于指定元素,还应用于其后代的机制。如果给 <h1> 元素应用了一个颜色,例如,那么该颜色将应用于 <h1> 内部的所有文本,即使是在子元素中的文本也是如此:
h1 {color: gray;}
<h1 id="page-title">Meerkat <em>Central</em></h1>
<p>
Welcome to the best place on the web for meerkat information!
</p>
普通 <h1> 文本和 <em> 文本都被设置为灰色,因为 <em> 元素从 <h1> 中继承了 color 属性的值。
事实上,大多数与盒模型相关的属性——包括边距、内边距、背景和边框——都不被继承,原因相同。毕竟,您可能不希望段落中的所有链接从父元素继承30像素的左边距!
第二,继承值完全没有特异性,甚至连零特异性都没有。(优先级最低)
层叠
在本章中,我们一直避开了一个相当重要的问题:当两个具有相同特异性的规则应用于同一元素时,会发生什么?浏览器如何解决冲突?例如,考虑以下规则:
h1 {color: red;}
h1 {color: blue;}
哪个会胜出?它们的特异性都是0,0,1,所以它们的权重相等,都应该适用。但这种情况不可能发生,因为元素不能同时是红色和蓝色。那么它会是什么颜色呢?
现在,Cascading Style Sheets这个名字终于有了意义:CSS基于一种使样式层叠在一起的方法,这是通过将继承和特异性与一些规则相结合来实现的。CSS的层叠规则如下:
1.查找所有包含与给定元素匹配的选择器的规则。
2.对于给定元素的所有适用声明,按显式权重进行排序。
3.对于给定元素的所有适用声明,按来源进行排序。基本上有三种来源:作者、读者和用户代理。在正常情况下,作者的样式(即您作为页面作者的样式)优先于读者的样式,作者和读者的样式都优于用户代理的默认样式。对于标记为! important的规则,用户代理的样式优先于作者的样式,而两者都优先于读者的样式。
4.对于给定元素的所有适用声明,按封装上下文进行排序。如果样式是通过影子DOM分配的,则它具有一个封装上下文,适用于同一影子DOM内的所有元素,并且不适用于影子DOM外的元素。这允许封装的样式覆盖从外部影子DOM继承的样式。
5.对于给定元素的所有适用声明,按是否为元素附加进行排序。通过样式属性分配的样式是元素附加的。无论是外部还是嵌入式,从样式表分配的样式都不是。
6.按照层叠顺序对所有声明进行排序。对于普通权重的样式,层叠层在 CSS 中首次出现的时间越晚,优先级越高。没有层叠层的样式被视为一个“默认”的最终伪层,其优先级高于显式创建的层中的样式。对于重要权重的样式,层叠层在 CSS 中出现的时间越早,优先级越高,所有显式创建的层中的重要权重样式都会胜过默认层中的样式,无论其是否重要。层叠层可以出现在任何来源。
7.按照特异性对所有应用于给定元素的声明进行排序。具有更高特异性的元素具有比具有较低特异性的元素更大的权重。
8.按照出现顺序对所有应用于给定元素的声明进行排序。声明在样式表或文档中出现的位置越晚,给予的权重越大。出现在导入的样式表中的声明被认为是在导入该样式表的样式表中的所有声明之前出现的。
同一个标签是可以被多个选择器选中,但如果选择器后面设置了相同的样式属性,标签最终该加载哪个?
或者,在继承性中,如果多个祖先都设置了相同的文字样式,后代中该继承哪个祖先级的?
上面的冲突需要用层叠性去解决。
判断最终胜出的属性是谁,需要依赖判断优先级即权重。只有一个属性会成功加载,它会层叠、覆盖掉其他的属性。
按重要性和来源排序
如果两个规则适用于一个元素,其中一个标记为 ! 重要,则重要的规则胜出:
p { color: gray ! important; }
<p style="color: black; ">Well, <em>hello</em> there!</p>
尽管段落的样式属性中指定了一个颜色,但 ! 重要的规则仍然胜出,因此段落变为灰色。
如果重要性相同,则考虑规则的来源。
1.+创作人员的样式+>+读者人员的样式+>+用户代理的默认样式
2.+标记为重要声明(!important)的读者样式+>+一切样式
p em {color: black;} /* 作者的样式表 /
p em {color: yellow;} / 读者的样式表 /
在这种情况下,段落中的强调文本将被着色为黑色,而不是黄色,因为作者样式胜过读者样式。然而,如果两个规则都标记为 ! 重要,则情况会发生变化:
p em {color: black ! important;} / 作者的样式表 /
p em {color: yellow ! important;} / 读者的样式表 */
现在,段落中的强调文本将变为黄色,而不是黑色。
总之,CSS在声明优先级方面有八个基本级别。按照从最高到最低的优先级顺序,如下所示:
1.过渡声明(参见第18章)
2.用户代理重要声明
3.读者重要声明
4.作者重要声明
5.动画声明(参见第19章)
6.作者正常声明
7.读者正常声明
8.用户代理声明 因此,过渡样式将覆盖所有其他规则,无论其他规则是否标记为 ! 重要,或者规则来自哪个来源。
按元素关联排序
样式可以通过诸如 style 这样的标记属性附加到元素上。这些被称为元素关联样式,只有考虑来源和权重时才会被压倒。
按层叠层排序
层叠层允许作者将样式分组,以便它们在级联中共享一个优先级级别。这听起来可能与! important类似;在某些方面它们是相似的,但在其他方面则非常不同。这演示起来比描述起来更容易。创建级联层的能力意味着作者可以在各种需求之间平衡,例如组件库的需求与特定页面或网页应用部分的需求。
注意
级联层是在2021年底引入CSS的,因此只有从那时起发布的浏览器才支持它们。
如果冲突的声明适用于一个元素,并且所有具有相同的显式权重和来源,且没有元素附加,那么它们接下来将按级联层排序。层的优先顺序是根据层首次声明或使用的顺序设置的,对于普通样式,后来声明的层优先于早期声明的层。考虑以下示例:
@layer site {
h1 {color: red;}
}
@layer page {
h1 {color: blue;}
}
这些<h1>元素将被着色为蓝色。这是因为page层在CSS中出现的位置晚于site层,因此具有更高的优先级。
任何不属于命名级联层的样式都会分配到一个隐含的“默认”层,该层对于不重要的规则具有高于任何命名层的优先级。假设我们修改之前的示例,如下所示:
h1 {color: maroon;}
@layer site {
h1 {color: red;}
}
@layer page {
h1 {color: blue;}
}
现在,<h1>元素将变为褐红色,因为隐含的“默认”层比任何命名层具有更高的优先级。
您还可以为命名级联层定义一个特定的优先顺序。考虑以下CSS:
@layer site, page;
@layer page {
h1 {color: blue;}
}
@layer site {
h1 {color: red;}
}
按特异性排序
如果冲突的声明适用于某个元素,并且这些声明具有相同的显式权重、来源、元素关联(或缺乏关联)和级联层,那么它们将按特异性进行排序。最具特异性的声明获胜,如下所示:
@layer page {
p#bright#bright#bright {color: grey;}
}
p#bright {color: silver;}
p {color: black;}
<p id="bright">Well, hello there! </p>
根据这些规则,段落的文本将呈现银色,
为什么?因为 p#bright 的特异性(1,0,1)超过了 p 的特异性(0,0,1),即使后者的规则在样式表中出现得更晚。来自 page 层的样式,即使它们具有最强的选择器(3,0,1),也不会被比较。只有具有优先级的层中的声明才会产生竞争。
按顺序排序
最后,如果两个规则的显式权重、起源、元素附加、层叠层和特异性完全相同,那么在样式表中出现较后的规则将会胜出,类似于层叠层按顺序排序的方式,以便后来的层胜过早期的层。
顺序排序是经常推荐链接样式排序的原因。推荐的顺序是链接、已访问、焦点、悬停和活动,简称LVFHA,如下所示:
a:link {color: blue;}
a:visited {color: purple;}
a:focus {color: green;}
a:hover {color: red;}
a:active {color: orange;}
处理非CSS呈现提示
文档中可能包含非CSS的呈现提示,例如已废弃的<font>元素,或者仍然广泛使用的height、width和hidden属性。这些呈现提示将被作者或读者样式覆盖,但不会被用户代理的样式覆盖。在现代浏览器中,来自CSS外部的呈现提示被视为用户代理样式表的一部分。
总结
也许层叠样式表最基础的方面就是层叠本身,即用于解决冲突声明并确定文档最终呈现的过程。这个过程的核心包括选择器及其相关声明的特异性,以及继承机制。