CSS 层叠与继承

本文为读 Cascade and inheritance 的笔记。

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

#Conflicting rules

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

#Cascade

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

举例:

1
2
3
4
5
6
h1 {
  color: red;
}
h1 {
  color: blue;
}

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

#Specificity

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

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

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

举例:

1
2
3
4
5
6
.main-heading {
  color: red;
}
h1 {
  color: blue;
}

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

#Inheritance

什么是继承?

一些为父元素设置的样式会由子元素继承,而另外一些样式(为父元素设置的)则不会被子元素继承。

举例:

1
2
3
4
5
6
body {
  color: blue;
}
span {
  color: black;
}
1
2
<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

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

#Understanding inheritance

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<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>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
.main {
    color: rebeccapurple;
    border: 2px solid #ccc;
    padding: 1em;
}

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

color 是可继承的。所以 <li> 继承了 .main 的样式;.special 的子元素变成了黑色。

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

#Controlling inheritance

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

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

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

#Understanding the cascade

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

  • Source order

  • Specificity

  • Importance

  • Source order

1
2
3
4
5
6
p {
  color: red;
}
p {
  color: black;
}

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

  1. Specificity

如果两个 Specificity 权重不一致,如下:

1
2
3
4
5
6
.para {
  color: red;
}
p {
  color: black;
}

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
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 计算的例子:

SelectorIdentifiersClassesElementsTotal specificity
h10010-0-1
h1 + p::first-letter0030-0-3
li > a[href*="en-US"] > .inline-warning0220-2-2
#identifier1001-0-0
button:not(#mainBtn, .cta)1011-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)。

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

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

1
2
3
p {
  color: red !important;
}

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

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

#The effect of CSS location

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

  1. Order of overriding declarations

样式冲突的优先级(高优先级的样式被应用,优先级由低到高):

  • 浏览器的默认样式

  • 用户的自定义样式

  • 开发者的自定义样式

  • 开发者自定义样式中有 !important 的部分样式

  • 用户自定义样式中有 !important 的部分样式

  • 浏览器默认样式中有 !important 的部分样式

  • Order of cascade layers

什么是 @layer[1]

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

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

Layout of comment panels