层叠和继承
W3C 规范
CSS 的基本设计原则之一是 层叠,它允许多个样式表影响文档的表示。
当不同的声明尝试为同一元素设置值时,必须以某种方式解决冲突。
而在默认情况下,若没有声明为元素设置值时,则会通过 继承 或使用属性的默认值来计算最终的结果。
相关信息
与层叠密切相关的概念是 优先级。
值的计算过程
一旦浏览器将 HTML 文档解析并生成了 DOM Tree,那么必须给每一个元素都设置对应的样式。
最终的 CSS 属性值会经过多个步骤的计算:
- 首先,收集每个元素上每一个属性应用的所有 声明值;
- 层叠产生 层叠值,每个元素的每个属性最多有一个层叠值;
- 默认值将产生 指定值,每个元素的每个属性正好有一个指定值;
- 解析值的依赖关系将产生 计算值,每个元素的每个属性正好有一个计算值;
- 格式化文档会生成 使用值,一个元素只有在一个给定的属性适用于该元素时才具有该属性的使用值;
我的理解是:若一个元素没有该属性,则没有使用值。
- 最后,根据显示环境的不同,将使用值转换为 实际值。与使用值一样,元素上的给定属性可能有也可能没有实际值。
声明值 Declared Values
每个应用于元素的属性声明都会给该属性提供一个声明值,这些值会被层叠处理以选择一个单一的「获胜值」。
层叠值 Cascaded Values
层叠值代表层叠的结果:它是赢得层叠的声明值(在层叠的输出中被排序在前面)。如果层叠的输出是一个空列表,那就没有层叠值。
指定值 Specified Values
指定值是一个给定的属性值,是样式表作者为该元素设置的。它是把层叠值通过默认过程处理的结果,保证每个元素上的每个属性都有一个指定的值。
在许多情况下,指定值是层叠的值。然而,如果根本没有层叠值,那么就会取默认的值。
计算值 Computed Values
计算值是对指定值进行解析的结果,通常是将其绝对化以准备继承。
注意
计算值是在继承过程中父代传递给子代的值。由于历史原因,它不一定是 getComputedStyle()
函数返回的值,该函数有可能会返回 使用值。CSSOM
除外,计算值是一个抽象的数据表示:它们的定义反映了该数据表示,而不是该数据如何被序列化。例如,序列化规则通常允许省略某些在解析过程中隐含的值,但这些值仍然是计算值的一部分。
EXAMPLE
一个指定的值可以是绝对的(如 red
或 2px
),也可以是相对的(如 auto
、2em
)。计算一个相对值通常会将其绝对化:
- 相对单位的值(
em
、ex
、vh
、vw
)必须通过与合适的参考尺寸相乘而成为绝对值 - 某些关键字(如
smaller
、bloder
)必须根据其定义进行替换 - 某些属性的百分比必须乘以一个参考值(由属性定义)
- 有效的相对 URL 必须被解析为绝对值
注意
一般来说,计算值会尽可能地解析指定值,而不需要执行其他难以并行的操作,例如解析网络请求或从元素和它的父级元素以外的地方检索值。
即使该属性不适用,计算值也会存在。然而一些属性可能会根据该属性是否适用于该元素而改变它们确定计算值的方式。
使用值 Used Values
使用值是将计算值和完成任何剩余计算的结果,使其成为文档格式化中使用的绝对理论值。
EXAMPLE
比如,在不知道该元素的祖先布局的情况下,width: auto
声明不能被解析为一个长度,所以计算值是 auto
,而使用值是一个绝对长度,如 100px
。
如果一个属性不适用于这个元素或盒子类型,那么它对该类型的盒子或元素没有直接的格式化效果,因此对该属性没有使用值。
EXAMPLE
例如,flex
属性在不是 flex
项目的元素上没有使用值。
注意
定义为适用于「所有元素」的属性适用于所有元素和显示类型,但不一定适用于所有伪元素类型,因为伪元素通常有自己的特定渲染模型或其他限制。然而,::before
和 ::after
伪元素被定义为几乎完全像普通元素一样,因此被定义为接受所有适用于「所有元素」的属性。
实际值 Actual Values
原则上,一个使用值是可以被使用的,但是用户代理可能无法在特定的环境中使用这个值。
例如,用户代理可能只能呈现整数像素宽度的边框,因此必须近似宽度的使用值。
另外,一个元素的字体大小可能需要根据字体的可用性和字体大小调整属性的值来调整。
实际值就是进行此类调整后的使用值。
例子
完整例子见 Examples
属性 | 获胜值 | 层叠值 | 指定值 | 计算值 | 使用值 | 实际值 |
---|---|---|---|---|---|---|
text-align | text-align: left | left | left | left | left | left |
width | (none) | (none) | auto (继承的值) | auto | 120px | 120px |
border-width | border-width: inherit | inherit | 4.2px | 4.2px | 4.2px | 4px |
font-size | font-size: 1.2em | 1.2em | 1.2em | 14.1px | 14.1px | 14px |
width | width: 80% | 80% | 80% | 80% | 354.2px | 354px |
层叠
层叠接收一个无序的列表,该列表是给定元素上给定属性的声明值,按照下面确定的声明优先级对它们进行排序,然后输出一个单一的 层叠值。
层叠排列顺序
层叠根据以下标准对声明进行排序,其优先级由高到低排列:
起源和重要性
一个声明的起源是基于它的来源,而它的重要性是指它是否用 !important
声明(见 下文)。各种起源的优先级按降序排列如下:
- 过渡声明 css-transitions-1
- 重要的用户代理声明
- 重要的用户声明
- 重要的作者声明
- 动画声明 css-animations-1
- 正常的作者声明
- 正常的用户声明
- 正常的用户代理声明
来自这个列表中较早起源的声明胜过来自较晚起源的声明。
特异性
选择器模块 Calculating a selector's specificity 描述了如何计算一个选择器的特异性。具有最高特异性的声明获胜。
出现顺序
文档中最后一个出现的声明获胜。这是为了:
- 来自导入的样式表的声明被排序,就像它们的样式表被替换成了
@import
规则。 - 来自独立于原生文档的样式表的声明被视为按照链接顺序连接起来的,由主文档语言决定。
- 来自样式属性的声明是根据样式属性出现的元素的文档顺序来排序的,并且都放在任何样式表之后。
级联的输出是一个(可能是空的)排序的列表,其中包括每个元素上的每个属性的声明值。
层叠来源
每个样式规则都有一个级联原点,它决定了它在哪里进入级联。CSS定义了三个核心原点:
作者起源
作者根据文档语言的惯例为一个源文档指定样式表。例如,在HTML中,样式表可以包含在文档中,也可以从外部链接。
用户起源
用户可能能够为一个特定的文档指定样式信息。例如,用户可以指定一个包含样式表的文件,或者用户代理可以提供一个生成用户样式表的界面(或者表现得像它一样)。
用户代理的起源
符合要求的用户代理必须应用一个默认的样式表(或者表现得像他们一样)。一个用户代理的默认样式表应该以满足文档语言的一般表现期望的方式呈现文档语言的元素(例如,对于视觉浏览器,HTML中的EM元素使用斜体字呈现)。例如,见HTML用户代理样式表。[HTML]
对CSS的扩展定义了以下额外的起源:
动画起源
CSS动画 css-animations-1 在运行时产生代表其效果的 "虚拟 "规则。
过渡起源
与CSS动画一样,CSS过渡 css-transitions-1 在运行时产生代表其效果的 "虚拟 "规则。
重要声明: !important
注释
CSS 试图在作者和用户的样式表之间建立一种权力平衡。
默认情况下,作者的样式表中的规则优先于用户的样式表中的规则,而用户的样式表又优先于用户代理的默认样式表中的规则。
为了平衡这一点,一个声明可以被标记为重要的,这将增加它在级联中的权重并颠倒优先顺序。
一个重要的声明优先于一个普通的声明。作者和用户的样式表都可以包含重要声明,用户源的重要声明优先于作者源的重要声明。
这个CSS特性通过让有特殊要求的用户(大字体、颜色组合等)控制表现形式来提高文档的可访问性。
所有来源的重要声明都优先于动画的声明。这允许作者在重要情况下覆盖动画值。(动画值通常优先于所有其他规则)。
用户代理样式表也可能包含重要的声明。这些声明覆盖了所有作者和用户的声明。
继承
当级联不产生一个值时,必须以其他方式找到指定的值。
继承的属性通过继承从它们的父元素中获取它们的默认值;所有其它的属性都采取它们的初始值。
作者可以通过inherit和initial关键字明确要求继承或初始化。
初始值
每个属性都有一个初始值,在该属性的定义表中定义。如果该属性不是一个继承的属性,并且级联没有产生一个值,那么该属性的指定值就是其初始值。
继承性
继承将属性值从父元素传播到它们的子元素。一个元素上的属性的继承值是该元素的父元素上的属性的计算值。对于根元素,它没有父元素,继承值是属性的初始值。
伪元素根据为每个伪元素描述的虚构的标签序列来继承。
有些属性是继承的属性,这在其属性定义表中有定义。这意味着,除非层叠的结果是一个值,否则该值将由继承来决定。
一个属性也可以明确地被继承。参见 继承关键字。
注意
继承遵循文档树,不被 匿名盒子 拦截,也不被盒子树的其他操作所影响。
明确默认
下面定义了几个 CSS 范围内的属性值;声明一个属性拥有这些值,明确地指定了一个特定的默认行为。所有的CSS属性都可以接受这些值。
重置一个属性:initial
关键字
如果一个属性的层叠值是 initial
关键字,那么该属性的 指定值 就是其初始值。
显式继承:inherit
关键字
如果一个属性的层叠值是 inherit
关键字,那么该属性的指定值和计算值就是继承值。
擦除所有声明:unset
关键字
如果一个属性的层叠值是 unset
关键字,那么如果它是一个继承的属性,这将被视为继承,如果它不是,这将被视为初始。
这个关键字有效地抹去了在层叠中较早出现的所有声明的值,正确地继承或不继承都适合于该属性(或一个速记的所有长文)。