当有多个选择器作用在一个元素上时,哪个规则最终会应用到元素上?
其实这是通过层叠机制来控制的,这也和样式继承(元素从其父元素那里获得属性值)有关。
元素的最终样式可以在多个地方定义,它们以复杂的形式相互影响。这些复杂的相互作用使CSS变得非常强大,但也使其非常难于调试和理解。
层叠
CSS 是 Cascading Style Sheets 的缩写,这暗示层叠(cascade)的概念是很重要的。在最基本的层面上,它表明CSS规则的顺序很重要,但它比那更复杂。什么选择器在层叠中胜出取决于三个因素(这些都是按重量级顺序排列的——前面的的一种会否决后一种):
- 重要性(Importance)
- 专用性(Specificity)
- 源代码次序(Source order)
重要性
在CSS中,有一个特别的语法可以让一条规则总是优先于其他规则:!important
。(常见于应用于iconfont图标属性后面)把它加在属性值的后面可以使这条声明有无比强大的力量。
让我们看一下这个例子:
<p class="better">This is a paragraph.</p>
<p class="better" id="winning">One selector to rule them all!</p>
#winning {
background-color: red;
border: 1px solid black;
}
.better {
background-color: gray;
border: none !important;
}
p {
background-color: blue;
color: white;
padding: 5px;
}
这将生成以下:
让我们一起来看看发生了什么。
你可以看到第三条规则
color
和padding
被运用了, 但background-color
没有,为什么?实际上,这三种情况都应该应用,因为在源顺序后面的规则通常会覆盖较早的规则。然而, 在前面的规则被运用了,因为 IDs/class 选择器优先于element选择器。
这两个元素都有
class
并带有better
属性, 但是第二个元素有id
值为winning
。 因为比起class而言id专用性更高(在一个页面上id是唯一的, 但很多元素可以拥有相同的class — ID 选择器在它们的目标中是非常优先的),红色背景色和1pixel的黑色边框都应应用于第二元素,第一个元素获得灰色背景色,没有边框,如类所指定。第二个元素获得红色背景色,但没有边框。为什么?因为
!important
在第二条规则中的声明——在border: none
之后写入它意味着尽管id具有更高的优先性,该声明也将优先于前面规则中的边界值声明。
注意: 重载这个 !important
声明的唯一方法是在后面的源码或者是一个拥有更高特殊性的源码中包含相同的 !important
特性的声明。
知道 !important
存在是很有用的,这样当你在别人的代码中遇到它时,你就知道它是什么了。但是!我们建议你千万不要使用它,除非你绝对必须使用它。您可能不得不使用它的一种情况是,当您在CMS中工作时,您不能编辑核心的CSS模块,并且您确实想要重写一种不能以其他方式覆盖的样式。 但是,如果你能避免的话,不要使用它。由于 !important
改变了层叠正常工作的方式,因此调试CSS问题,尤其是在大型样式表中,会变得非常困难。
要注意一个CSS声明的重要性取决于它被指定在什么样式表内——用户可以设置自定义样式表覆盖开发商的样式,例如用户可能有视力障碍,想设置字体大小对所有网页的访问是双倍的正常大小,以便更容易阅读。
相互冲突的声明将按以下顺序适用,后一种将覆盖先前的声明:
- 在用户代理样式表的声明 (例如:浏览器在没有其他声明的默认样式).
- 用户样式表中的普通声明(由用户设置的自定义样式)。
- 作者样式表中的普通声明(这是我们设置的样式,Web开发人员)。
- 作者样式表中的重要声明
- 用户样式表中的重要声明
Web开发者的样式表覆盖用户的样式表是合理的,所以设计可以保持预期,但是有时候用户有很好的理由来重写web开发人员样式,如上所述,这可以通过在用户的规则中使用!important
。
专用性
专用性基本上是衡量选择器的具体程度的一种方法——它能匹配多少元素。如上面所示的示例所示,元素选择器具有很低的专用性。类选择器具有更高的专用性,所以将战胜元素选择器。ID选择器有甚至更高的专用性, 所以将战胜类选择器. 战胜ID选择器的唯一方法是使用 !important
。
一个选择器具有的专用性的量是用四种不同的值(或组件)来衡量的,它们可以被认为是千位,百位,十位和个位——在四个列中的四个简单数字:
- 千位:如果声明是在
style
属性中该列加1分(这样的声明没有选择器,所以它们的专用性总是1000。)否则为0。 - 百位:在整个选择器中每包含一个ID选择器就在该列中加1分。
- 十位:在整个选择器中每包含一个类选择器、属性选择器、或者伪类就在该列中加1分。
- 个位:在整个选择器中每包含一个元素选择器或伪元素就在该列中加1分。
注意: 通用选择器 (*
), 复合选择器 (+
, >
, ~
, ' ') 和否定伪类 (:not
) 在专用性中无影响。
下表显示了几个示例。试着通过这些,并确保你理解他们为什么具有我们给予他们的专用性。
选择器 | 千位 | 百位 | 十位 | 个位 | 合计值 |
---|---|---|---|---|---|
h1 |
0 | 0 | 0 | 1 | 0001 |
#important |
0 | 1 | 0 | 0 | 0100 |
h1 + p::first-letter |
0 | 0 | 0 | 3 | 0003 |
li > a[href*="zh-CN"] > .inline-warning |
0 | 0 | 2 | 2 | 0022 |
#important div > div > a:hover , 在一个元素的 <style> 属性里 |
1 | 1 | 1 | 3 | 1113 |
在我们继续之前,让我们看看一个行动中的例子。
这是我们将要使用的HTML:
<div id="outer" class="container">
<div id="inner" class="container">
<ul>
<li class="nav"><a href="#">One</a></li>
<li class="nav"><a href="#">Two</a></li>
</ul>
</div>
</div>
下面是CSS的示例:
/* specificity: 0101 */
#outer a {
background-color: red;
}
/* specificity: 0201 */
#outer #inner a {
background-color: blue;
}
/* sp