# CSS 层叠与继承

本文为读
[Cascade and inheritance](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance) 的笔记。

着重理解 CSS 三个基础概念------cascade, specificity,
inheritance。这三点控制 CSS 如何应用于 HTML，样式之间的冲突如何解决。

### Conflicting rules {#conflicting-rules}

CSS 的全称是 Cascading Style
Sheets。当出现矛盾规则（两个不同的值应用到同一个选择器的同一个属性上）时，cascade,
specificity 是解决这类问题的措施。

#### Cascade {#cascade}

样式层叠意味着，原始样式、层叠的部分以及 CSS 规则的顺序是重要的。
*当两个规则来自相同的层叠层，并且有着相同的特异性，那么最后定义的那一个的样式会被用在
HTML 中。*

举例：

```css
    h1 {
      color: red;
    }
    h1 {
      color: blue;
    }
```

两个 style blocks
具有相同特异性，所以两者的顺序会决定哪一个的样式会被应用。根据前述规则，h1
最终的颜色会是蓝色。

#### Specificity {#specificity}

特异性是浏览器使用的算法，用来决定将哪一个属性值应用到元素上。

如果在多个样式块（有着不同选择器）中配置了相同属性的不同值。特异性决定哪一个属性值会被应用到元素上。特异性是一种方法------它能确定一个选择器有多特别。

- 一个元素选择器的特异性最小，因为它会选择所有是该元素的元素。它的特异性权重最小。
- 类选择器的权重提升一些，它只会选择具有某个类的元素，与元素选择器相比权重增大一些。

举例：

```css
    .main-heading {
      color: red;
    }
    h1 {
      color: blue;
    }
```

h1 元素的颜色是红色。因为 class
选择器的特异性权重更高，所以无视顺序问题。

#### Inheritance {#inheritance}

什么是继承？

一些为父元素设置的样式会由子元素继承，而另外一些样式（为父元素设置的）则不会被子元素继承。

举例：

```css
    body {
      color: blue;
    }
    span {
      color: black;
    }
```

```
    <p>As the body has been set to have a color of blue this is inherited through the descendants.</p>
    <p>We can change the color by targeting the element with a selector, such as this <span>span</span>.</p>
```

这两段文字，除了 span 其余全是黑色。

有些属性可继承，如 color, font-family；有些则不可以，如 width。

如何查找？

在每一个 CSS 属性的页面都有一个"Formal
definition"。在那里可以找到当前属性是否可继承。

### Understanding how the concepts work together {#understanding-how-the-concepts-work-together}

通过 Firefox Developer Tools 可以很方便地查看、更改、调试，CSS 规则。

### Understanding inheritance {#understanding-inheritance}

```
    <ul class="main">
        <li>Item One</li>
        <li>Item Two
            <ul>
                <li>2.1</li>
                <li>2.2</li>
            </ul>
        </li>
        <li>Item Three
            <ul class="special">
                <li>3.1
                    <ul>
                        <li>3.1.1</li>
                        <li>3.1.2</li>
                    </ul>
                </li>
                <li>3.2</li>
            </ul>
        </li>
    </ul>
```

```css
    .main {
        color: rebeccapurple;
        border: 2px solid #ccc;
        padding: 1em;
    }

    .special {
        color: black;
        font-weight: bold;
    }
```

color 是可继承的。所以 `&lt;li&gt;` 继承了 .main 的样式；.special
的子元素变成了黑色。

width、margin、padding、border 不可继承。

#### Controlling inheritance {#controlling-inheritance}

CSS 提供了五个通用属性值，用来控制 CSS 继承。每一个 CSS 属性都适用。

这五个属性值分别为：inherit, initial, revert, revert-layer, unset。

通过快捷属性 all 能够一次性重置很多属性。

#### Understanding the cascade {#understanding-the-cascade}

决定层叠优先级的三个要素：

- Source order
- Specificity
- Importance

- Source order

  <!--listend-->

```css
    p {
      color: red;
    }
    p {
      color: black;
    }
```

根据 Source order，两个 CSS block 内的 Specificity
权重是一致的。哪一个样式会被应用，取决于顺序，哪一个在后会被应用。因此，p
的颜色是黑色。

1. Specificity

如果两个 Specificity 权重不一致，如下：

```css
    .para {
      color: red;
    }
    p {
      color: black;
    }
```

只通过 Source order 确定 CSS
的样式选择就不可行了。由这段代码可得出结论：
**类选择器比元素选择器具有更大的权重** 。

*注意：应用于 HTML 文本和组件的各 CSS block
的样式并非全被覆盖，只有那些在多个 CSS block 声明的属性会被覆盖。*
这样做的好处是避免重复设置样式。通常的实践是：先定义通用样式，然后再根据各组件需要修改部分。

```css
    h2 {
      font-size: 2em;
      color: #000;
      font-family: Georgia, "Times New Roman", Times, serif;
    }

    .small {
      font-size: 1em;
    }

    .bright {
      color: rebeccapurple;
    }
```

后两个类同样是应用在 h2 元素上。

一个选择器的 specificity 数目由三个值确定：ID、CLASS、ELEMENT。

- Identifiers: 在整个选择器中，出现一个 id 选择器加 1
- Classes: 在整个选择器中，出现一个类、属性或伪类选择器加 1
- Elements: 在整个选择器中，出现一个元素或伪元素选择器加 1

*注意：通用选择器（ `*` ）、选择符（+, >, ~,
''）和某些特定选择器（:where()）不具备 specificity。*

两个伪类 `:not()` 和 `:is()` 无法改变
specificity，但它们的参数能够改变。The specificity each contributes to
the specificity algorithm is the specificity of the selector in
parameter that has the greatest weight.(这句不理解)

一些 specificity 计算的例子：

| Selector                                    | Identifiers   | Classes   | Elements   | Total specificity   |
| --- | --- | --- | --- | --- |
| `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               |
| `#identifier`                               | 1             | 0         | 0          | 1-0-0               |
| `button:not(#mainBtn, .cta)`                | 1             | 0         | 1          | 1-0-1               |

*注意：每一个选择器都有自己的特异性（specificity），低特异性水平的选择器不能覆盖掉高特异性水平的选择器。举例，10
个类选择器的特异性比不过 1 个 id 选择器的特异性。*

**评估特异性的最佳方式是为不同水平的特异性从高到低打分。在进行比较时，只有两个集合的对应序列打分相同时，才可进行下一序列的比较。**

两个特异性集合：(a, b, c), (d, e, f)，只有当 `a=d` 时，b 和 e
的比较才有意义。如果 `a>d` ，那么 (a, b, c) 的特异性大于 (d, e, f)。如果
`a<d` ，那么 (d, e, f) 的特异性大于 (a, b, c)。

1. 内嵌样式

内嵌样式指的是通过全局属性 style 来对具体元素设置样式。它的特异性最高
(1-0-0-0)。

```
    <p style="color: red;">This is a paragraph.</p>
```

1. !important

有时，设置样式的时候，会因为太过复杂而导致样式产生冲突。想要样式不发生改变，可以通过在样式属性值后面加
`!important` 。

```css
    p {
      color: red !important;
    }
```

它会破坏正常的特异性。它会覆盖一般的层叠规则，甚至是内嵌样式。

*注意：要在确定需要它的情况下使用。因为它对正常 CSS
样式的破坏，使得对包含它的 CSS 调试变得很困难，随着 CSS
的复杂程度增长，调试的困难程度跟着倍增。*

#### The effect of CSS location {#the-effect-of-css-location}

最后，需要注意的是，CSS 声明的优先级取决于指定它的样式表和级联层。

1. Order of overriding declarations

样式冲突的优先级（高优先级的样式被应用，优先级由低到高）：

- 浏览器的默认样式
- 用户的自定义样式
- 开发者的自定义样式
- 开发者自定义样式中有 `!important` 的部分样式
- 用户自定义样式中有 `!important` 的部分样式
- 浏览器默认样式中有 `!important` 的部分样式

- Order of cascade layers

什么是 @layer[^1]？

它能够用来声明一个级联层，还可用于定义多层级联情况下的优先顺序。

在级联层中声明样式时，层的顺序决定了优先级。层外的所有样式形成一个未命名的层，位于其他层的最后，（在正常样式中）是有着最高的优先级的级联层。在正常的样式中，层越靠后优先级越高。如果有
`!important`
，正好相反，层越靠前优先级越高。在级联层中，内嵌样式的优先级高于所有
author 样式，与级联层无关。

[^1]: [@layer - CSS -
       MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer)
