MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

这篇翻译不完整。请帮忙从英语翻译这篇文章

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

In a previous article, we got into the various CSS selectors. At some point in your work, you'll find yourself in the situation where multiple CSS rules will have selectors matching the same element. In such cases, which CSS rule "wins", and ends up being the one that is finally applied to the element? This is controlled by a mechanism called the Cascade; this is also related to inheritance (elements will take some property values from their parents, but not others.) In this article we will define what the cascade is, what specificity is, what importance is, and how properties inherit from different rules.

前提条件

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

Basic computer literacy, basic software installed, basic knowledge of working with files, HTML basics (study Introduction to HTML), and an idea of How CSS works (study the previous articles in this module.)

目标

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

To learn about the cascade and specificity, and how inheritance works in CSS.

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

层叠

CSS 是 Cascading Style Sheets 的缩写,这暗示层叠(cascade)的概念是很重要的。At its most basic level it indicates that the order of CSS rules matter, but it's more complex than that. What selectors win out in the cascade depends on three factors (these are listed in order of weight — earlier ones will overrule later ones):

  1. 重要性(importance)
  2. 特殊性(specificity)
  3. 源代码次序

重要性

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

 

 

Let's look at an example:

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

This produces the following:

Let's walk through this to see what's happening.

  1. 你可以看到第三条规则 color 和 padding 被运用了, 但 background-color没有,为什么? 三条规则都的确被添加了, 但是在后面出现的规则覆盖了前面的。
  2. 然而, 在前面的规则被运用了,因为 IDs/class 选择器比element选择器有更高的优先级。 (对此,你将在下一章中学到更多)
  3. 每一个元素都有 class并带有带有 better属性, 但是第二个元素有 id 值为winning 。 因为 IDs 有更高 的优先级比起class(在一个页面上id是唯一的, 但很多元素可以拥有相同的class — ID 选择器对于它的所属元素来说最独特), the red background color and the 1 pixel black border should both be applied to the 2nd element, with the first element getting the gray background color, and no border, as specified by the class.
  4. The 2nd element does get the red background color, but no border. Why? Because of the !important declaration in the second rule — including this after border: none means that this declaration will win over the border value in the previous rule, even though the ID has higher specificity.

Note: The only way to override this !important declaration would be to include another !important declaration of the same specificity, later in the source order.

It is useful to know that !important exists so that you know what it is when you come across it in other people's code. BUT. We would advise you to never use it unless you absolutely have to. One situation in which you may have to use it is when you are working on a CMS where you can't edit the core CSS modules, and you really want to override a style that can't be overridden in any other way. But really, don't use it if you can avoid it. Because !important changes the way the cascade normally works, it can make debugging CSS problems really hard to work out, especially in a large stylesheet.

It is also useful to note that the importance of a CSS declaration depends on what stylesheet it is specified in — it is possible for users to set custom stylesheets to override the developer's styles, for example the user might be visually impaired, and want to set the font size on all web pages they visit to be double the normal size to allow for easier reading.

Conflicting declarations will be applied in the following order, with later ones overriding earlier ones:

  1. Declarations in user agent style sheets (e.g. the browser's default styles, used when no other styling is set).
  2. Normal declarations in user style sheets (custom styles set by a user).
  3. Normal declarations in author style sheets (these are the styles set by us, the web developers).
  4. Important declarations in author style sheets
  5. Important declarations in user style sheets

It makes sense for web developers' stylesheets to override user stylesheets, so the design can be kept as intended, but sometimes users have good reasons to override web developer styles, as mentioned above — this can be achieved by using !Important in their rules.

特殊性

Specificity is basically a measure of how specific a selector is — how many elements it could match. As shown in the example seen above, element selectors have low specificity. Class selectors have a higher specificity, so will win against element selectors. ID selectors have an even higher specificity, so will win against class selectors. The only way to win against an ID selector is to use !important.

The amount of specificity a selector has is measured using four different values (or components), which can be thought of as thousands, hundreds, tens and ones — four single digits in four columns:

  1. Thousands: Score one in this column if the matching selector is inside a <style> element or the declaration is inside a style attribute (such declarations don't have selectors, so their specificity is always simply 1000.) Otherwise 0.
  2. Hundreds: Score one in this column for each ID selector contained inside the overall selector.
  3. Tens: Score one in this column for each class selector, attribute selector, or pseudo-class contained inside the overall selector.
  4. Ones: Score one in this column for each element selector or pseudo-element contained inside the overall selector.

Note: Universal selector (*), combinators (+, >, ~, ' ') and negation pseudo-class (:not) have no effect on specificity.

The following table shows a few isolated examples to get you in the mood. Try going through these, and making sure you understand why they have the specificity that we have given them.

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

Note: If multiple selectors have the same importance and specificity, which selector wins is decided by which comes later in the Source order.

Before we move on, let's look at an example in action. Here is the HTML we are going to use:

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

And here is the CSS for the example:

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

The result we get from this code is as follows:

So what's going on here? First of all, we are only interested in the first seven rules of this example, and as you'll notice, we have included their specificity values in a comment before each one.

  • The first two selectors are competing over the styling of the link's background color — the second one wins and makes the background color blue because it has an extra ID selector in the chain: its specificity is 201 versus 101.
  • The third and fourth selectors are competing over the styling of the link's text color — the second one wins and makes the text white because although it has one less element selector, the missing selector is swapped out for a class selector, which is worth ten rather than one. So the winning specificity is 113 versus 104.
  • Selectors 5–7 are competing over the styling of the link's border when hovered. Selector six clearly loses to five with a specificity of 23 versus 24 — it has one fewer element selectors in the chain. Selector seven, however, beats both five and six — it has the same number of sub-selectors in the chain as five, but an element has been swapped out for a class selector. So the winning specificity is 33 versus 23 and 24.

Note: If you haven't already, review all the selectors one more time, just to make sure you understand why the specificity values have been awarded as shown.

源代码次序

As mentioned above, if multiple competing selectors have the same importance and specificity, the third factor that comes into play to help decide which rule wins is source order — later rules will win over earlier rules. For example:

p {
  color: blue;
}

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

Whereas in this example the first rule wins because source order is overruled by specificity:

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

p {
  color: red;
}

A note on rule mixing

One thing you should bear in mind when considering all this cascade theory, and what styles get applied over other styles, is that all this happens at the property level — properties override other properties, but you don't get entire rules overriding other rules. When several CSS rules match the same element, they are all applied to that element. Only after that are any conflicting properties evaluated to see which individual styles will win over others.

Let's see an example. First, some HTML:

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

And now some CSS to style it with:

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

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

Result:

In this example, because of its specificity, the first rule's color property overrides the color property of the second rule. However, both the background-color from the first rule and the text-decoration from the second rule are applied to the <strong> element. You'll also notice that the text of that element is bolded: this comes from the browsers' default stylesheet.

继承

CSS inheritance is the last piece we need to investigate to get all the information and understand what style is applied to an element. The idea is that some property values applied to an element will be inherited by that element's children, and some won't.

  • 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!

Which properties are inherited by default and which aren't is largely down to common sense. If you want to be sure however, you can consult the CSS Reference — each separate property page starts off with a summary table including various details about that element, including whether it is inherited or not.

控制继承

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.

Let's take a look at an example. First some 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>

Now some CSS for styling:

body {
  color: green;
}

.inherit a {
  color: inherit;
}

.initial a {
  color: initial
}

.unset a {
  color: unset;
}

Result:

Let's explain what's going on here:

  • We first set the color of the <body> to green.
  • As the color property is naturally inherited, all child elements of body will have the same green color. It's worth noting that browsers set the color of links to blue by default instead of allowing the natural inheritance of the color property, so the first link in our list is blue.
  • The second rule sets links within an element with the class inherit to inherit its color from its parent. In this case, it means that the link inherits its color from its <li> parent, which, by default inherits its color from its own <ul> parent, which ultimately inherits its color from the <body> element, which had its color set to green by the first rule.
  • The third rule selects any links within an element with the class initial and sets their color to initial. Usually, the initial value set by browsers for the text color is black, so this link is set to black.
  • The last rule selects all links within an element with the class unset and sets their color to unset — we unset the value. Because the color property is a naturally inherited property it acts exactly like setting the value to inherit. As a consequence, this link is set to the same color as the body — green.

Active learning: playing with the cascade

In this active learning we'd like you to experiment with writing a single new rule that will override the color and background color that we've applied to the links by default. Can you use one of the special values we looked at in the Controlling_inheritance section to write a declaration in a new rule that will reset the background color back to white, without using an actual color value?

If you make a mistake, you can always reset it using the Reset button. If you get really stuck, press the Show solution button to see a potential answer.

What's next

If you understood most of this article, then well done — you've started getting familiar with the fundamental mechanics of CSS. The last bit of central theory is the box model, which we'll cover next.

If you didn't fully understand the cascade, specificity, and inheritance, then don't worry! This is definitely the most complicated thing we've covered so far in the course, and is something that even professional web developers sometimes find tricky. We'd advise that you return to this article a few times as you continue through the course, and keep thinking about it. Refer back to here if you start to come across strange issues with styles not applying as expected. It could be a specificity issue.

文档标签和贡献者

 此页面的贡献者: iaei, lavenderming, xiaojichao, firefire
 最后编辑者: iaei,