CSS 代表层叠样式表(Cascading Style Sheets),理解第一个词层叠(cascade)很重要——层叠的表现方式是理解 CSS 的关键。
在某些时候,在做一个项目过程中你会发现一些应该产生效果的样式没有生效(还可能是因为HTML元素的原因:如行盒设置宽高、垂直margin无效)。通常的原因是你创建了两个应用于同一个元素的规则。与层叠密切相关的概念是优先级(specificity),决定在发生冲突的时候应该使用哪条规则。
我们在编写元素样式规则时可能不是期望的规则,因此需要了解这些机制是如何工作的。
层叠冲突处理(权重计算)
1. 比较源的重要性
什么是 源?
所谓的源,其实就是:CSS样式规则的来源。
来源有 3 种:
- 用户代理样式表(user agent stylesheet):浏览器默认样式
- 用户样式表(user stylesheet):用户自定义样式
- 作者样式表(author stylesheet):页面作者写的样式
代码示例:
<style>
/* 作者样式 */
p {
background-color: #ccc;
}
</style>
<body>
<p>Lorem, ipsum dolor.</p>
</body>
知道了什么是源以及都有哪些源之后,我们来看一下源的优先级(重要性)
重要性由高到低:
- 用户代理样式表中的
!important声明 - 用户样式表中的
!important声明 - 作者样式表中的
!important声明 - 作者样式表中的常规声明(这些是我们 web 开发人员设置的样式)
- 用户样式表中的常规声明(由用户设置的自定义样式)
- 用户代理样式表中的常规声明(例如,浏览器的默认样式,在没有设置其他样式时使用)
⚠️注意:
- 在上述 6 种重要性中,只有:作者样式表中的
!important声明;作者样式表中的常规声明;用户代理样式表中的常规声明;这 3 种,是我们在开发中常用的。- 标记为
!important的样式优先级顺序是颠倒的。web 开发人员的样式表覆盖用户的样式表是有意义的,这样我们写的样式就可以按预期生效,但是有时用户有充足的理由覆盖 web 开发人员的样式,此时就可以使用!important来实现。
2. 比较特殊性(选择器优先级)⭐
当不同的选择器选择了相同的元素时,浏览器会根据选择器的优先级来决定使用哪个规则
总体来说,选择器的选择范围越窄,就越特殊,优先级就越高。比如:
- 一个元素选择器不是很具体,范围比较广,会选择页面上的所有该类型元素,所以它的优先级就会低一些。
- 一个类选择器稍微具体一点,范围比较窄,会选择该页面中有特定
class属性值的元素,所以它的优先级就要高一点。
了解了总体的规则后,让我们来看看浏览器如何具体的计算优先级。
我们已经知道一个元素选择器比类选择器优先级更低,会被其覆盖。
本质上,不同类型的选择器,有不同的分数值,把这些分数相加就得到特定选择器的权重,然后就可以进行匹配。
一个选择器的优先级可以说是由三个不同的值(或分量)相加,可以认为是百(ID)十(类)个(元素)——三位数的三个位数:
- ID:选择器中包含 ID 选择器则百位得一分。
- 类:选择器中包含类选择器、属性选择器或者伪类则十位得一分。
- 元素:选择器中包含元素、伪元素选择器则个位得一分。
⚠️注意:
通用选择器(*)、组合符(+、>、~、' ')和调整优先级的选择器(:where())不会影响优先级
否定(:not())和任意匹配(:is())伪类本身对优先级没有影响,但它们的参数会带来影响。参数中,对优先级算法有贡献的参数中优先级最大值将作为该伪类选择器的优先级。
可能有点抽象,我们通过几个例子来看:
| 选择器 | ID | 类 | 元素 | 优先级 |
|---|---|---|---|---|
h1 | 0 | 0 | 1 | 0-0-1 |
h1 + p::first-letter | 0 | 0 | 3 | 0-0-3 |
li > a[href*="en-US"] > .inline-warning | 0 | 2 | 2 | 0-2-2 |
#app | 1 | 0 | 0 | 1-0-0 |
button:not(#marginBtn, .cta) | 1 | 0 | 1 | 1-0-1 |
优先级在比较的时候,从高位到低位进行比较,如果相同则继续比较下一位,否则直接得出优先级大小。
3. 比较书写顺序
当指向同一个元素的多个选择器的优先级相同时,写在后面的就是实际生效的规则。
4. 应用
-
重置样式表(reset.css)
书写一些作者样式表,覆盖浏览器的默认样式
常见的重置样式表:normalize.css、reset.css、meyer.css
-
a 元素 伪元素的书写顺序(LVHA)
:link - :visited - :hover - :active
思考一下为啥要按照这个顺序写才会生效?
当你点击 a 链接时,其实是处于 link、hover、active 这 3 种样式的叠加态,这样就会有层叠冲突啊
我们需要选择出一个此时最合适的样式,那就是点击active的样式
因此,我们把 active 写到最后,其他同理。
有关 CSS 层叠冲突处理规则就先讲到这里,后续会出CSS属性值计算过程、盒模型、视觉格式化模型等相关知识的文章,所有相关文章都会收录到专栏《你不知道的CSS》中,欢迎收藏。