翻译正在进行中。

在上一节中,我们学习了多种多样的CSS选择器。但在实际的工作中,我们可能还有些疑惑,当有多个选择器作用在一个元素上时,哪个规则最终会应用到元素上?其实这是通过层叠机制来控制的,这也和样式继承(元素从其父元素那里获得属性值)有关、在本节中中我们将定义什么是层叠,什么是特异,元素属性如何从不同的规则中继承以及其重要性。

前提条件

了解HTML基本知识,了解CSS 如何工作的。

目标

了解层叠及特异,以及CSS中继承是如何实现的。

元素的最终样式可以在多个地方定义,它们以复杂的形式相互影响。这些复杂的相互作用使CSS变得非常强大,但也使其非常难于调试和理解。这篇文章旨在明晰其中的部分复杂性;如果你不能立即理解,也没关系,这是CSS 理论中最复杂的地方。你可以现在就尝试学习,或在遇到关于层叠和继承问题的时候再来翻阅。

层叠

CSS 是 Cascading Style Sheets 的缩写,这暗示层叠(cascade)的概念是很重要的。在最基本的层面上,它表明CSS规则的顺序很重要,但它比那更复杂。什么选择器在层叠中胜出取决于三个因素(这些都是按重量级顺序排列的——前面的的一种会否决后一种):

  1. 重要性(Importance)
  2. 优先级(Specificity)
  3. 源代码次序(Source order)

重要性

在CSS中,有一个特别的语法可以让一条规则优先于其他规则:!important。把它加在属性值的后面可以使这条声明有无比强大的力量。  

让我们看一下这个例子:

<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;
}

这将生成以下:

让我们一起来看看发生了什么。

  1. 你可以看到第三条规则 color 和 padding 被运用了, 但 background-color没有,为什么?实际上,这三种情况都应该应用,因为在源顺序后面的规则通常会覆盖较早的规则。
  2. 然而, 在前面的规则被运用了,因为 IDs/class 选择器优先于element选择器。 (对此,你将在下一章中学到更多)
  3. 这两个元素都有 class并带有带有 better属性, 但是第二个元素有 id 值为winning 。 因为比起class而言id优先级更高(在一个页面上id是唯一的, 但很多元素可以拥有相同的class — ID 选择器在它们的目标中是非常优先的),红色背景色和1pixel的黑色边框都应应用于第二元素,第一个元素获得灰色背景色,没有边框,如类所指定。
  4. 第二个元素获得红色背景色,但没有边框。为什么?因为 !important 在第二条规则中的声明——在 border: none之后写入它意味着尽管id具有更高的优先性,该声明也将优先于前面规则中的边界值声明。

注意: 重载这个 !important 声明的唯一方法是在后面的源码或者是一个拥有更高特殊性的源码中包含相同的 !important 特性的声明。

知道 !important存在是很有用的,这样当你在别人的代码中遇到它时,你就知道它是什么了。但是!我们建议你千万不要使用它,除非你绝对必须使用它。您可能不得不使用它的一种情况是,当您在CMS中工作时,您不能编辑核心的CSS模块,并且您确实想要重写一种不能以其他方式覆盖的样式。 但是,如果你能避免的话,不要使用它。由于 !important 改变了层叠正常工作的方式,因此调试CSS问题,尤其是在大型样式表中,会变得非常困难。

要注意一个CSS声明的重要性取决于它被指定在什么样式表为用户设置自定义样式表覆盖开发商的风格可能也是有用的,例如用户可能有视力障碍,想设置字体大小对所有网页的访问是双重的正常大小,以便更容易阅读。

相互冲突的声明将按以下顺序适用,后一种将覆盖先前的声明:

  1. 在用户代理样式表的声明 (例如:浏览器在没有其他声明的默认样式).
  2. 用户样式表中的常规声明(由用户设置的自定义样式)。
  3. 作者样式表中的正常声明(这是我们设置的样式,Web开发人员)。
  4. 作者样式表中的重要声明
  5. 用户样式表中的重要声明

它为Web开发者的样式覆盖用户样式表是有意义的,所以设计可以按照预期的方式进行,但是有时候用户有很好的理由来重写web开发人员样式,如上所述,这可以通过在用户的规则中使用!important

优先级

优先级基本上是衡量选择器的具体程度的一种方法——它能匹配多少元素。如上面所示的示例所示,元素选择器具有很低的优先级。类选择器具有更高的优先级,因此将“打败”元素选择器。“战胜”ID选择器的唯一方法是使用!important

一个选择器的优先级量是用四种不同的值(或组件)来衡量的,它们可以被认为是千位,百位,十位和个位——四个列中的四个数字:

  1. 千位:如果声明在一个style 属性中该列加1分(这样的声明没有选择器,所以它们的特性总是简单的1000。)否则为0。
  2. 百位:在整个选择器中每包含一个ID选择器就在该列中加1分。
  3. 十位:对于每包含一个类选择器,属性选择器,或者包含在全局选择器中的伪类就在该列中加1分。
  4. 个位 在这个:对于在整个选择器中包含的每一个元素选择器或伪元素就在该列中加1分。

注意: 通用选择器 (*), 关系选择器 (+, >, ~, ' ') 和否定伪类 (:not) 在优先级中无影响。

下表显示了几个示例。试着通过这些,并确保你理解他们为什么具有我们给予他们的优先级。

Selector Thousands Hundreds Tens Ones Total specificity
h1 0 0 0 1 0001
#important 0 1 0 0 0100
h1 + p::first-letter 0 0 0 3 0003
li > a[href=*"en-US"] > .inline-warning 0 0 2 2 0022
#important div > div > a:hover, inside a <style> element 1 1 1 3 1113

注意: 如果多个选择器具有相同的重要性和优先级,则选择哪一个选择器取决于 Source order.

在我们继续之前,让我们看看一个行动中的例子。这是我们将要使用的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;
}

/* specificity: 0104 */
#outer div ul li a {
  color: yellow;
}

/* specificity: 0113 */
#outer div ul .nav a {
  color: white;
}

/* specificity: 0024 */
div div li:nth-child(2) a:hover {
  border: 10px solid black;
}

/* specificity: 0023 */
div li:nth-child(2) a:hover {
  border: 10px dashed black;
}

/* specificity: 0033 */
div div .nav:nth-child(2) a:hover {
  border: 10px double black;
}

a {
  display: inline-block;
  line-height: 40px;
  font-size: 20px;
  text-decoration: none;
  text-align: center;
  width: 200px;
  margin-bottom: 10px;
}

ul {
  padding: 0;
}

li {
  list-style-type: none;
}

我们从这个代码中得到的结果如下:

这里发生了什么?首先,我们只对本例的前七个规则感兴趣,正如您将注意到的,我们已经在每个注释中包含了它们的优先级值。

  • 前两个选择器正在竞争链接的背景颜色的样式——第二个赢得并使背景色为蓝色,因为它有一个额外的ID选择器在链中:其优先级值为201比101。
  • 第三个和第四个选择器在链接文本颜色的样式上进行竞争——第二个选择器获胜,使文本变白,因为缺少一个元素选择器,缺少的选择器被换成类选择器,它的值是十,而不是个位。所以优先级值为113和104。
  • 选择器5 - 7在徘徊在链接附近时的样式进行竞争。选择器六明显地输给了了五,其优先级值为23和24——它在链中少了一个元素选择器。选择器七,但同时击败五和六——它有与五相同数量的子选择器在链中,但一个元素已被换为了了一个类选择器。所以获胜的优先级值是33比23和24。

注意:如果您还没有准备好,请再次复习所有选择器,以确保您理解为什么会授予特定的优先级值。

源代码次序

(目前翻译到这里,之后的是上一个人翻的,翻译之前的部分给我的感觉就是像机翻的一样,建议后部分读原文,我尽快翻译。)

如上所述,如果多个相互竞争的选择器具有相同的重要性和特殊性,那么第三个因素将起到帮助决定哪一个规则获胜的目的,即以后的规则将战胜先前的规则。例如:

p {
  color: blue;
}

/* This rule will win over the first one */
p {
  color: red;
}

而在这个例子中的第一个规则赢因为源秩序推翻的特异性:

/* This rule will win */
.footnote {
  color: blue;
}

p {
  color: red;
}

关于规则混合的一点注记

当考虑到所有级联理论,以及应用于其他样式的样式时,应该记住的一点是,所有这些都发生在属性级别上——属性覆盖其他属性,但是没有覆盖其他规则的全部规则。当几个CSS规则匹配同一个元素时,它们都应用于该元素。只有在这之后,任何相互冲突的属性才会被评估,以确定哪种风格会战胜其他类型。.

让我们看一个例子。首先,一些HTML:

<p>I'm <strong>important</strong></p>

现在一些CSS风格与它:

/* specificity: 0002 */
p strong {
  background-color: khaki;
  color: green;
}

/* specificity: 0001 */
strong {
  text-decoration: underline;
  color: red;
}

Result:

在这个例子中,因为层叠性的关系,第一条规则中的color属性覆盖掉了第二条中的颜色值。但是,对于第一条中的 background-color和第二条中的text-decoration 的属性都在strong元素之中得到了体现。你也注意到了这个元素之中的字体是加粗的:这是浏览器默认的样式规则。

继承

CSS继承是我们需要调查的最后一部分,以获取所有信息并了解什么样式应用于元素。其思想是,应用于某个元素的一些属性值将由该元素的子元素继承,而有些则不会。

  • For example, it makes sense for font-family and color to be inherited, as that makes it easy for you to set a site-wide base font by applying a font-family to the <html> element; you can then override the fonts on individual elements where needed. It would be really annoying to have to set the base font separately on every element.
  • As another example, it makes sense for margin, padding, border, and background-image to NOT be inherited. Imagine the styling/layout mess that would occur if you set these properties on a container element and had them inherited by every single child element, and then had to unset them all on each individual element!

默认情况下继承哪些属性,哪些属性不是普通意义上的。但是,如果你想确定,你可以查阅 CSS Reference — 每个单独的属性页都会从一个汇总表开始,其中包含有关该元素的各种详细信息,包括是否继承了该元素。

控制继承

CSS 提供了三个特殊值来处理继承:

  • inherit: 该值将应用到选定元素的属性值设置为与其父元素一样。
  • initial :该值将应用到选定元素的属性值设置为与浏览器默认样式表中该元素设置的值一样。如果浏览器默认样式表中没有设置值,并且该属性是自然继承的,那么该属性值就被设置为 inherit
  • unset :该值将属性重置为其自然值,即如果属性是自然继承的,那么它就表现得像 inherit,否则就是表现得像 initial

The inherit value is the most interesting — it allows us to explicitly make an element inherit a property value from its parent.

让我们看一个例子。首先是一些HTML:

<ul>
  <li>Default <a href="#">link</a> color</li>
  <li class="inherit">Inherit the <a href="#">link</a> color</li>
  <li class="initial">Reset the <a href="#">link</a> color</li>
  <li class="unset">Unset the <a href="#">link</a> color</li>
</ul>

现在一些CSS样式:

body {
  color: green;
}

.inherit a {
  color: inherit;
}

.initial a {
  color: initial
}

.unset a {
  color: unset;
}

Result:

让我们解释这里发生了什么:

  •  我们首先设置<body>color为绿色。
  • 由于color属性是自然继承的,所有的body子元素都会有相同的绿色。需要注意的是默认情况下浏览器设置链接的颜色为蓝色,而不是自然继承color属性,因此在我们列表中的第一个链接是蓝色的。
  • 第二条规则是设置了链接在一个使用了类 inherit 来继承自父元素color的元素上。 在这种情况下, 意思是说链接继承了父元素<li>的颜色, 默认情况下li的颜色来自于它的父元素 <ul> , 最后ul的颜色继承自 <body>元素, 而body的color 根据第一条规则设置成了绿色。
  • 第三个规则选择了在元素上使用类initial的任意链接然后设置他们的颜色为initial。通常,initial的值被浏览器设置成了黑色,因此该链接被设置成了黑色。
  • 最后一个规则选择了在元素上使用类unset的所有链接然后设置它们的颜色为unset — 即我们不设置值。因为color属性是一个自然继承的属性,它实际上就像把值设置成inherit一样。结果是,该链接被设置成了与body一样的颜色  — 绿色。

主动学习: playing with the cascade

在这个活跃的学习中,我们希望您尝试编写一个新的规则,它将覆盖我们在默认情况下应用到链接的颜色和背景颜色。 Can you use one of the special values we looked at in the Controlling_inheritance 要在一个新规则中写一个声明,将背景颜色重置为白色,而不使用实际的颜色值?

如果你犯了一个错误,你可以用重置按钮重新设置它。如果你真的卡住了,按下显示解决方案按钮看一个潜在的答案。

下一步是什么

如果你理解了这篇文章的大部分内容,那么你已经开始熟悉CSS的基本原理了。最后一点的核心理论是盒子模型,我们将在下一章中讨论。

如果你没有完全理解级联、专一性和继承性,那就不用担心了!这绝对是我们迄今为止所涉及到的最复杂的事情,甚至是专业的Web开发人员有时也会发现棘手的问题。我们建议你在继续进行这门课的过程中几次回到这篇文章,并继续思考它。如果您开始遇到样式不适用的奇怪问题,请返回这里。它可能是一种特异性问题。

文档标签和贡献者

 最后编辑者: Froggy,