1. 简介
CSS 的基本设计原则之一是层叠(cascading),它允许多个样式表影响文档的呈现。当不同的声明尝试为相同的元素/属性组合设置值时,必须以某种方式解决冲突。
当没有任何声明试图为元素/属性组合设置值时,会出现相反的问题。在这种情况下,将通过继承或查看属性的初始值来确定该值。
层叠和默认值过程以一组声明作为输入,并输出每个元素上每个属性的指定值。
本规范描述了为文档中所有元素上的所有属性查找指定值的规则。页面上下文及其边距框中的指定值查找规则描述于 [css-page-3] 中。
1.1. 模块交互
本节是规范性的。
本模块替换并扩展了 [CSS2] 第 6 章中定义的分配属性值、层叠和继承的规则。
其他 CSS 模块可能会扩展此处定义的某些语法和功能。例如,媒体查询第 4 级规范在与本模块结合时,扩展了本规范中使用的 <media-query> 值类型的定义。
2. 导入样式表:@import 规则
@import 规则允许用户从其他样式表导入样式规则。如果 @import 规则指向有效的样式表,用户代理必须将该样式表的内容视为在 @import 规则处编写的一样,但有两个例外。
-
如果某个功能(例如 @namespace 规则)明确定义为仅适用于特定样式表而不适用于任何导入的样式表,则它不适用于该导入的样式表。
-
如果某个特性依赖于样式表中两个或多个构造的相对顺序(例如 @namespace 规则之前不得有除 @import 之外的任何其他规则),则该要求仅适用于同一样式表中的构造。
例如,来自导入样式表的样式规则中的声明与层叠的交互,就像它们被字面地写在样式表中的 @import 处一样。
任何 @import 规则都必须位于样式表中所有其他有效的 at-rule 和样式规则(忽略 @charset)之前,否则该 @import 规则无效。@import 的语法为:
@import [ <url> | <string> ] <media-query-list>? ;
其中 <url> 或 <string> 给出了要导入的样式表的 URL,而可选的 <media-query-list>(导入条件)说明了它适用的条件。
如果提供了 <string>,则必须将其解释为具有相同值的 <url>。
2.1. 条件 @import 规则
导入条件允许导入依赖于媒体类型。在没有任何导入条件的情况下,导入是无条件的。(为 <media-query-list> 指定 all 具有相同的效果。)如果导入条件不匹配,则导入样式表中的规则不适用,就像导入的样式表被包裹在具有给定媒体查询的 @media 块中一样。
@import url ( "fineprint.css" ) print; @import url ( "bluish.css" ) projection, tv; @import url ( "narrow.css" ) handheld and( max-width:400 px );
因此,只要媒体查询不匹配,用户代理就可以避免获取依赖于媒体的导入。
导入条件的评估和完整语法由媒体查询规范 [MEDIAQ] 定义。
2.2. 处理样式表导入
当同一个样式表在多个地方被导入或链接到文档时,用户代理必须处理(或表现得好像处理了)每个链接,就像该链接指向一个独立的样式表一样。
注:这不对资源获取提出任何要求,仅涉及样式表如何在 CSSOM 中反映以及在本规范等规范中如何使用。假设缓存得当,UA 只获取一次样式表是完全合适的,即使它被多次链接或导入。
导入样式表的来源是导入它的样式表的来源。
导入样式表的环境编码是导入它的样式表的编码。[css-syntax-3]
2.3. CSS 样式表的 Content-Type
导入样式表的处理取决于链接资源的实际类型。如果资源没有 Content-Type 元数据,或者宿主文档处于怪异模式 (quirks mode) 且与导入的样式表具有相同来源,则链接资源的类型为 text/css。否则,类型将根据其 Content-Type 元数据确定。
如果链接资源的类型为 text/css,则必须将其解释为 CSS 样式表。否则,必须将其解释为网络错误。
3. 简写属性
某些属性是简写属性,意味着它们允许作者通过单个属性指定多个属性的值。简写属性设置其所有的长写子属性,就像原地展开一样。
当简写形式中省略了值时,除非另有定义,否则每个“缺失的”子属性都会被分配其初始值。
例如,编写 background: green 而不是 background-color: green 可确保背景颜色覆盖任何先前可能已将背景设置为具有 background-image 的图像的声明。
h1{ font-weight : bold; font-size : 12 pt ; line-height : 14 pt ; font-family : Helvetica; font-variant : normal; font-style : normal; }
因此可以重写为
h1{ font : bold12 pt /14 pt Helvetica}
在某些情况下,简写可能具有不同的语法或特殊关键字,这些语法或关键字不直接对应其子属性的值。(在这种情况下,简写将明确定义其值的展开。)
在其他情况下,属性可能是简写的仅重置子属性:像其他子属性一样,当未指定时,它会被简写重置为其初始值,但简写可能不包含将其设置为其任何其他值的语法。例如,border 简写将 border-image 重置为其初始值 none,但没有将其设置为其他值的语法。[css-backgrounds-3]
如果将简写指定为 CSS 全局关键字 [css-values-3] 之一,它会将所有子属性设置为该关键字,包括任何仅重置子属性。(请注意,这些关键字不能在单个声明中与其他值组合,即使在简写中也不行。)
将简写属性声明为 !important 等同于将该简写的所有子属性声明为 !important。
3.1. 重置所有属性:all 属性
| 名称 | all |
|---|---|
| 值 | initial | inherit | unset |
| 初始值 | 见各个属性 |
| 应用于 | 见各个属性 |
| 可继承 | 见各个属性 |
| 百分比 | 见各个属性 |
| 计算值 | 见各个属性 |
| 动画类型 | 见各个属性 |
| 规范顺序 | 按语法 |
all 属性是一个简写,用于重置所有 CSS 属性,除了 direction 和 unicode-bidi。它仅接受 CSS 全局关键字。它不会重置自定义属性 [css-variables-1]。
注:例外的 CSS 属性 direction 和 unicode-bidi 实际上是标记级功能,不应在作者的样式表中设置。(它们仅作为 CSS 属性存在,用于样式化 UA 不支持的文档语言。)作者应改用适当的标记,例如 HTML 的 dir 属性。[css-writing-modes-3]
这对于包含在页面中的“小部件”的根元素很有用,因为它不希望继承外部页面的样式。但请注意,应用于该元素的任何“默认”样式(例如,来自 UA 样式表中块级元素如 <div> 的 display: block)也将被清除。
4. 值处理
一旦用户代理解析了文档并构建了文档树,它就必须为树中的每个元素,以及格式化结构中的每个框,为目标媒体类型适用的每个属性分配一个值。
给定元素或盒子的 CSS 属性的最终值是多步计算的结果:
- 首先,为每个元素上的每个属性收集应用于该元素的所有声明值。应用于该元素的声明值可能有零个或多个。
- 层叠产生层叠值。每个元素上的每个属性最多有一个层叠值。
- 默认设定产生指定值。每个元素上的每个属性恰好有一个指定值。
- 解决值依赖关系产生计算值。每个元素上的每个属性恰好有一个计算值。
- 格式化文档产生使用值。仅当给定属性适用于该元素时,该元素才具有该属性的使用值。
- 最后,使用值根据显示环境的约束转换为实际值。与使用值一样,元素上的给定属性可能存在也可能不存在实际值。
4.1. 声明值
每个应用于元素的属性声明都会贡献一个与该元素关联的该属性的声明值。详细信息请参阅过滤声明。
这些值随后由层叠处理,以选择单个“获胜值”。
4.2. 层叠值
层叠值代表层叠的结果:它是胜出层叠(在层叠输出中排名第一)的声明值。如果层叠输出是一个空列表,则没有层叠值。
4.3. 指定值
指定值是样式表作者为该元素预期的给定属性的值。它是将层叠值通过默认值处理过程的结果,确保每个元素上的每个属性都有一个指定值。
在许多情况下,指定值就是层叠值。但是,如果没有层叠值,则指定值会被赋予默认值。CSS 全局关键字在作为属性的层叠值时会进行特殊处理,根据该关键字的要求设置指定值,请参阅§ 7.3 显式默认值。
4.4. 计算值
计算值是将指定值按照属性定义表中的“计算值”行定义进行解析的结果,通常是在为继承做准备时将其绝对化。
注意:计算值是在继承期间从父级传递到子级的值。出于历史原因,它不一定是 getComputedStyle() 函数返回的值,该函数有时会返回使用值。[CSSOM] 此外,计算值是一种抽象数据表示:其定义反映了数据表示,而不是数据如何序列化。例如,序列化规则通常允许省略在解析期间隐含的某些值;但这些值仍然是计算值的一部分。
- 具有相对单位(em, ex, vh, vw)的值必须通过乘以相应的参考尺寸来绝对化
- 某些关键字(例如 smaller, bolder)必须根据其定义进行替换
- 某些属性上的百分比必须乘以参考值(由属性定义);
- 有效的相对 URL 必须解析为绝对 URL。
参见下表中的示例 (f)、(g) 和 (h)。
注意:通常,计算值会尽可能地解析指定值,而无需进行文档布局或执行其他昂贵或难以并行化的操作,例如解析网络请求或检索除元素及其父元素以外的值。
即使在属性不适用时,计算值也存在。但是,某些属性可能会根据该属性是否适用于该元素来改变其确定计算值的方式。
4.5. 使用值
使用值是将计算值并完成任何剩余计算,使其成为格式化文档时使用的绝对理论值的结果。
例如,width: auto 的声明如果不了解元素祖先的布局,就无法解析为长度,因此计算值为 auto,而使用值是一个绝对长度,例如 100px。[CSS2]
再举一个例子,一个 <div> 的 break-before 计算值可能为 auto,但通过从其第一个子元素传播,获得了 page 的使用 break-before 值。[css-break-3]
如果一个属性不适用于该元素或框类型(正如其“Applies to”行中所述),那么它对该类型的框或元素没有直接的格式化影响,因此该属性没有使用值。
例如,flex 属性在非弹性项目 (flex items) 的元素上没有使用值。
p 元素(默认情况下为 display: block)上设置 text-transform 会产生影响,尽管 text-transform 仅适用于内联框,因为该属性会继承到段落的匿名根内联框中。注意:定义为适用于“所有元素”的属性适用于所有元素和显示类型,但不一定适用于所有伪元素类型,因为伪元素通常有其特定的渲染模型或其他限制。然而,::before 和 ::after 伪元素被定义为生成几乎与普通元素完全相同的框,因此被定义为接受所有适用于“所有元素”的属性。关于伪元素的更多信息,请参阅 [CSS-PSEUDO-4]。
4.6. 实际值
使用值原则上已准备好使用,但用户代理可能无法在给定环境中利用该值。例如,用户代理可能只能以整数像素宽度渲染边框,因此可能必须近似使用宽度。此外,元素的字体大小可能需要根据字体可用性或 font-size-adjust 属性的值进行调整。实际值是进行此类调整后的使用值。
注:通过探测元素的实际值,可以了解文档是如何布局的。然而,并非所有信息都记录在实际值中。例如,page-break-after 属性的实际值并不反映元素之后是否有分页符。类似地,orphans 的实际值并不反映特定元素中有多少孤行。参见下表中的示例 (j) 和 (k)。
4.7. 示例
| 属性 | 获胜声明 | 层叠值 | 指定值 | 计算值 | 使用值 | 实际值 | |
|---|---|---|---|---|---|---|---|
| (a) | text-align | text-align: left
| left | left | left | left | left |
| (b) | border-top-width, border-right-width, border-bottom-width, border-left-width | border-width: inherit
| inherit | 4.2px | 4.2px | 4.2px | 4px |
| (c) | width | (none) | (none) | auto (初始值) | auto | 120px | 120px |
| (d) | list-style-position | list-style-position: inherit
| inherit | inside (内侧) | inside (内侧) | inside (内侧) | inside (内侧) |
| (e) | list-style-position | list-style-position: initial
| 初始值 | outside (初始值) | outside (外侧) | outside (外侧) | outside (外侧) |
| (f) | font-size | font-size: 1.2em
| 1.2em | 1.2em | 14.1px | 14.1px | 14px |
| (g) | width | width: 80%
| 80% | 80% | 80% | 354.2px | 354px |
| (h) | width | width: auto
| auto | auto | auto | 134px | 134px |
| (i) | height | height: auto
| auto | auto | auto | 176px | 176px |
| (j) | page-break-after | (none) | (none) | auto (初始值) | auto | auto | auto |
| (k) | orphans (孀行) | orphans: 3
| 3 | 3 | 3 | 3 | 3 |
5. 过滤
为了找到声明值,实现必须首先识别应用于每个元素的所有声明。如果以下情况成立,则声明适用于该元素:
- 它属于当前适用于本文档的样式表。
- 它未被具有假条件的条件规则 [CSS-CONDITIONAL-3] 限定。
- 它属于一个选择器与该元素匹配的样式规则。[SELECT]
- 它是语法有效的:声明的属性是已知的属性名称,并且声明的值匹配该属性的语法。
对于每个元素上的每个属性,应用的声明值形成一个声明值列表。下一节,层叠,会对这些列表进行优先级排序。
6. 层叠
层叠获取给定元素上给定属性的声明值的无序列表,按下面确定的声明优先级对它们进行排序,并输出单个层叠值。
6.1. 层叠排序顺序
层叠根据以下标准对声明进行排序,优先级由高到低:
- 来源和重要性
- 声明的来源基于其来源,其重要性在于是否用 !important 声明(见下文)。各种来源的优先级,按降序排列:
此列表中排在前面的 来源 的声明优于排在后面的 来源 的声明。
- 特殊性
- 选择器模块 [SELECT] 描述了如何计算选择器的特指度(specificity)。每个声明都具有与其所在样式规则相同的特指度。为了本步骤的目的,不属于样式规则的声明(例如样式属性的内容)被视为具有高于任何选择器的特指度。具有最高特指度的声明胜出。
- 出现顺序
- 文档顺序中的最后一个声明胜出。为此
- 来自导入样式表的声明的排序,就像它们的样式表被替换在 @import 规则的位置一样。
- 由原始文档独立链接的样式表中的声明,被视为按链接顺序串联,具体顺序由宿主文档语言确定。
- 来自 style 属性的声明按照出现该 style 属性的元素的文档顺序排列,并且全部置于所有样式表之后。
层叠输出是每个元素上每个属性的(可能为空的)已排序的声明值列表。
6.2. 级联来源
每个样式规则都有一个层叠来源,它决定了它进入层叠的位置。CSS 定义了三个核心来源
- 作者来源
- 作者根据文档语言的约定为源文档指定样式表。例如,在 HTML 中,样式表可以包含在文档中或外部链接。
- 用户来源
- 用户可能能够为特定文档指定样式信息。例如,用户可以指定一个包含样式表的文件,或者用户代理可能提供一个生成用户样式表(或表现得好像它生成了一个)的界面。
- 用户代理来源
- 符合标准的用户代理必须应用一个默认样式表(或表现得好像它应用了一个)。用户代理的默认样式表应该以满足文档语言一般表现预期的方式来呈现文档语言的元素(例如,对于视觉浏览器,HTML 中的 EM 元素使用斜体字体呈现)。参见例如 HTML 用户代理样式表。 [HTML]
CSS 的扩展定义了以下额外的来源
- 动画来源
- CSS 动画 [css-animations-1] 在运行时生成表示其效果的“虚拟”规则。
- 过渡来源
- 与 CSS 动画一样,CSS 过渡 [css-transitions-1] 在运行时生成表示其效果的“虚拟”规则。
6.3. 重要声明:!important 注解
CSS 试图在作者样式表和用户样式表之间建立一种权力平衡。默认情况下,作者样式表中的规则会覆盖用户样式表中的规则,而用户样式表中的规则会覆盖用户代理默认样式表中的规则。为了平衡这一点,可以将声明标记为重要 (important),这会增加其在层叠中的权重并颠倒优先级顺序。
如果声明具有由 [css-syntax-3] 定义的 !important 注解,则该声明是重要的,即如果其值中的最后两个(非空格、非注释)标记是分隔符标记 ! 后跟标识符标记 important。所有其他声明都是正常的(非重要的)。
重要声明优先于正常声明。作者和用户样式表都可能包含重要声明,用户来源重要声明会覆盖作者来源重要声明。此 CSS 特性通过让有特殊需求的用户(大字体、颜色组合等)控制演示文稿,提高了文档的可访问性。
来自所有来源的重要声明优先于动画。这允许作者在重要情况下覆盖动画值。(动画值通常会覆盖所有其他规则。)[css-animations-1]
用户代理样式表也可能包含重要声明。这些声明会覆盖所有作者和用户声明。
/* From the user’s style sheet */ p{ text-indent : 1 em !important} p{ font-style : italic !important} p{ font-size : 18 pt } /* From the author’s style sheet */ p{ text-indent : 1.5 em !important} p{ font : normal12 pt sans-serif !important} p{ font-size : 24 pt }
| 属性 | 胜出的值 |
|---|---|
| text-indent | 1em |
| font-style | italic |
| font-size | 12pt |
| font-family | sans-serif |
6.4. 非 CSS 表现性提示的优先级
UA 可以选择尊重源文档标记中的表现性提示,例如 [HTML] 中的 bgcolor 属性或 s 元素。所有基于文档语言的样式都必须转换为相应的 CSS 规则,并作为 UA 来源规则进入层叠,或者作为特指度为零且放置在开头的作者来源规则来处理。文档语言可以定义此类表现性提示是作为 UA 来源还是作者来源进入层叠;如果定义了,UA 必须相应地运行。例如,[SVG11] 将其呈现属性映射到作者级别。
注意:作为 UA 来源规则进入层叠的表现性提示可以被作者来源或用户来源样式覆盖。作为规则进入层叠的表现性提示可以被样式覆盖,但不能被非重要的用户来源样式覆盖。宿主语言在考虑这些因素时,应为表现性提示选择适当的来源。
7. 默认值
当层叠没有产生值时,必须以其他方式找到指定值。继承属性通过继承从其父元素获取默认值;所有其他属性采用其初始值。作者可以通过 inherit 和 initial 关键字显式请求继承或初始化。
7.1. 初始值
每个属性都有一个初始值,定义在属性的定义表中。如果该属性不是继承属性,并且层叠没有产生值,则该属性的指定值为其初始值。
7.2. 继承
继承将属性值从父元素传播到其子元素。元素上属性的继承值是该属性在元素父元素上的计算值。对于没有父元素的根元素,其继承值是该属性的初始值。
伪元素根据为每个伪元素描述的虚构标签序列进行继承。[SELECT]
有些属性是继承属性,定义在它们的属性定义表中。这意味着,除非层叠产生了值,否则该值将由继承确定。
属性也可以显式继承。参见 inherit 关键字。
注意: 继承遵循文档树,不会被 匿名框 拦截,也不会受到框树操作的影响。
7.3. 显式默认值
下面定义了几个 CSS 全局属性值;将属性声明为具有这些值会显式指定特定的默认行为。正如 CSS 值和单位 Level 3 [css-values-3] 中所指定的,所有 CSS 属性都可以接受这些值。
7.3.1. 重置属性:initial 关键字
如果属性的层叠值是 initial 关键字,则该属性的指定值为其初始值。
7.3.2. 显式继承:inherit 关键字
如果属性的层叠值是 inherit 关键字,则该属性的指定值和计算值是其继承值。
7.3.3. 清除所有声明:unset 关键字
如果属性的层叠值是 unset 关键字,那么如果它是继承属性,则将其视为 inherit,如果不是,则将其视为 initial。此关键字有效地擦除了在层叠中较早出现的所有声明值,并根据属性(或简写的所有长手属性)的适当情况正确地继承或不继承。
8. 变更记录
8.1. 自 2020 年 12 月 22 日拟议推荐标准以来的变更
自 2020 年 12 月 22 日拟议推荐标准以来,本规范进行了以下变更:
- 修正了一个拼写错误
- W3C 推荐标准的状态和样式变更
8.2. 自 2018 年 8 月 28 日候选推荐标准以来的变更
自 2018 年 8 月 28 日候选推荐标准以来,本规范进行了以下变更:
8.3. 自 2016 年 5 月 19 日候选推荐标准以来的变更
自 2016 年 5 月 19 日候选推荐标准以来,本规范进行了以下非琐碎变更:
-
澄清了自定义属性不会被 all 简写重置。(2518)
all 属性是一个简写,用于重置所有 CSS 属性,除了 direction 和 unicode-bidi。… 它不会重置自定义属性 [css-variables-1]。
-
指出了两个例外情况,在这些情况下,导入样式表与仅仅插入其内容有所不同。
如果 @import 规则指向有效的样式表,用户代理必须将该样式表的内容视为在 @import 规则处编写的一样 ,但有两个例外:
- 如果某个功能(例如 @namespace 规则)明确定义为仅适用于特定样式表而不适用于任何导入的样式表,则它不适用于该导入的样式表。
- 如果某个特性依赖于样式表中两个或多个构造的相对顺序(例如 @charset 之前不得有任何其他内容),则该要求仅适用于同一样式表中的构造。
- 删除了任何关于范围样式表(scoped stylesheets)的提及,因为该特性已从 HTML 中移除。(Issue 637)
- 删除了任何关于过时的“覆盖 (override)”来源的提及,该来源最初由 DOM Level 2 Style 定义,后来被废弃。
提供了评论处理说明 (Disposition of Comments)。
8.4. 自 2013 年 10 月 3 日候选推荐标准以来的变更
自 2013 年 10 月 3 日候选推荐标准以来,本规范进行了以下变更:
- 定义了导入样式表的环境编码。
导入样式表的环境编码是导入它的样式表的编码。[css-syntax-3]
- 引用了 [css-syntax-3] 作为 !important 规则的语法。
如果声明具有 !important 注解,则该声明是重要的,正如 [css-syntax-3] 所定义的那样。
- 解释了仅重置子属性,并澄清了它们也会受到简写声明中 CSS 全局关键字值的影响。
在其他情况下,属性可能是简写的仅重置子属性:像其他子属性一样,当未指定时,它会被简写重置为其初始值,但简写可能不包含将其设置为其任何其他值的语法。例如,border 简写将 border-image 重置为其初始值 none,但没有将其设置为其他值的语法。[css-backgrounds-3]
如果将简写指定为 CSS 全局关键字 [css-values-3] 之一,它会将所有子属性设置为该关键字,包括任何仅重置子属性。(请注意,这些关键字不能在单个声明中与其他值组合,即便是简写也不行。)
提供了评论处理说明 (Disposition of Comments)。
8.5. 自 Level 2 以来的新增内容
自 Level 2 以来添加了以下功能
致谢
David Baron、Simon Sapin 和 Boris Zbarsky 为本规范做出了贡献。
隐私与安全考虑
-
级联过程不区分同源和跨源样式表,这使得跨源样式表的内容可以从它们应用于文档的计算样式中推断出来。
-
通过应用样式规则表示的用户偏好和 UA 默认值通过级联过程暴露,并且可以从它们应用于文档的计算样式中推断出来。
-
@import 规则假设没有
Content-Type元数据的资源(或如果宿主文档处于怪异模式下的任何同源文件)为text/css,这可能会允许任意文件被导入页面并被解释为 CSS,从而可能导致敏感数据从它们应用于文档的计算样式中被推断出来。