1. 简介
CSS 定义了一组有限的参数,称为属性,用于指导文档的渲染。每个属性都有一个名称(例如 color、font-size 或 border-style)、一个值空间(例如 <color>、<length-percentage>、[ solid | dashed | dotted | … ])以及对文档渲染定义的行为。属性值通过属性声明分配给文档的各个部分,这些声明为相关元素或盒子分配一个值(例如 red、12pt、dotted)。
CSS 的基本设计原则之一是层叠(cascading),它允许多个样式表影响文档的呈现。当不同的声明尝试为相同的元素/属性组合设置值时,必须以某种方式解决冲突。
当没有任何声明尝试为元素/属性组合设置值时,会出现相反的问题。在这种情况下,将通过继承或查看属性的初始值来找到一个值。
层叠和默认设定过程接收一组声明作为输入,并为每个元素上的每个属性输出一个指定值。
本规范描述了为文档中所有元素上的所有属性查找指定值的规则。页面上下文及其边距框中的指定值查找规则描述于 [css-page-3] 中。
1.1. 模块交互
本节是规范性的。
本模块替换并扩展了 [CSS2] 第 6 章中定义的分配属性值、层叠和继承的规则。
其他 CSS 模块可能会扩展此处定义的某些语法和功能。例如,媒体查询第 4 级规范在与本模块结合时,扩展了本规范中使用的 <media-query> 值类型的定义。
就本规范而言,文本节点被视为其关联元素的元素子节点,并拥有全套属性;由于它们不能被选择器定位,它们的所有计算值均通过默认设定分配。
2. 导入样式表:@import 规则
@import 规则允许用户从其他样式表导入样式规则。如果 @import 规则引用了有效的样式表,用户代理必须像将样式表内容写入 @import 规则所在位置一样对待其内容,但有两个例外:
-
如果某个功能(例如 @namespace 规则)明确定义为仅适用于特定样式表而不适用于任何导入的样式表,则它不适用于该导入的样式表。
-
如果某个功能依赖于样式表中两个或多个构造的相对顺序(例如要求 @namespace 规则在其前面不得有除了 @import 之外的任何规则),则它仅适用于同一样式表中的构造之间。
例如,来自导入样式表的样式规则中的声明与层叠的交互,就像它们字面上写在 @import 点处的样式表中一样。
任何 @import 规则必须位于样式表中所有其他有效 @规则和样式规则之前(忽略 @charset 和空的 @layer 定义),并且在其与前一个 @import 规则之间不得有任何其他有效的 @规则或样式规则,否则该 @import 规则无效。@import 的语法如下:
@import [ <url> | <string> ]
[ layer | layer(<layer-name>) ]?
[ supports( [ <supports-condition> | <declaration> ] ) ]?
<media-query-list>? ;
其中
-
可选的 layer 关键字或 layer() 函数将样式表的内容分配到其自己的匿名层叠层中,或分配到指定的层叠层中。
即使导入未能加载样式表,该层也会被添加到层顺序中,但须遵守任何导入条件(就像由包裹在适当条件组规则中的 @layer 规则声明一样)。
-
可选的 [<supports-condition>|<declaration>] 和 <media-query-list>(统称为导入条件)说明了它适用的条件。
@import url("narrow.css") supports(display: flex) handheld and (max-width: 400px);
@import url("tabs.css") layer(framework.component);
@import url("override.css") layer();
如果提供了 <string>,则必须将其解释为具有相同值的 <url>。
@import "mystyle.css" ; @import url ( "mystyle.css" );
2.1. 条件 @import 规则
导入条件允许导入依赖于媒体或功能支持。在没有任何导入条件的情况下,导入是无条件的。(为 <media-query-list> 指定 all 具有相同的效果。)如果导入条件不匹配,则导入样式表中的规则不适用,就像导入的样式表被包裹在具有给定条件的 @media 和/或 @supports 块中一样。
@import url ( "fineprint.css" ) print; @import url ( "bluish.css" ) projection, tv; @import url ( "narrow.css" ) handheld and( max-width:400 px );
因此,只要导入条件不匹配,用户代理就可以避免获取条件导入。此外,如果 <supports-condition> 阻止了导入样式表的应用,UA 不得获取该样式表(除非它通过其他链接加载),并必须为导入规则的 CSSImportRule.styleSheet 值返回 null(即使它通过其他链接加载)。
@import url ( "fallback-layout.css" ) supports ( not( display: flex)); @supports ( display: flex) { ...}
导入条件由 <media-query-list>(被解析并解释为媒体查询列表)和 <supports-condition>(被解析并解释为支持查询)提供。如果 <declaration> 代替了 <supports-condition>,它必须被解释为 <supports-decl>(即暗示额外的括号集),并被视为 <supports-condition>。
@import "mystyle.css" supports ( display: flex); @import "mystyle.css" supports (( display: flex));
导入条件的评估和完整语法由 媒体查询 [MEDIAQ] 和 CSS 条件规则 [CSS-CONDITIONAL-3] 规范定义。
2.2. 处理样式表导入
当同一个样式表在多个地方被导入或链接到文档时,用户代理必须处理(或表现得好像处理了)每个链接,就像该链接指向一个独立的样式表一样。
注:这不对资源获取提出任何要求,仅涉及样式表如何在 CSSOM 中反映以及在本规范等规范中如何使用。假设缓存得当,UA 只获取一次样式表是完全合适的,即使它被多次链接或导入。
导入样式表的层叠来源是导入它的样式表的层叠来源。
导入样式表的环境编码是导入它的样式表的编码。[css-syntax-3]
2.3. 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. 属性别名
属性在支持一段时间后有时会更改名称,例如带有供应商前缀的属性标准化。出于兼容性原因,仍需支持原始名称,但首选新名称。为实现此目的,CSS 定义了两种将旧语法“别名”到新语法的不同方式。
- 传统名称别名
- 当旧属性的值语法与新属性完全相同时,这两个名称将通过类似于大小写映射的操作进行别名处理:在解析时,旧属性被转换为新属性。这种转换也适用于 CSSOM,无论是对于字符串参数还是属性访问器:对旧属性名称的请求将透明地转移到新属性名称。例如,如果 old-name 是 new-name 的传统名称别名,
getComputedStyle将返回( el). oldNamenewName属性的计算样式,并且el会将 new-name 属性设置为. style. setPropertyValue( "old-name" , "value" ) 。"value" - 传统简写
- 当旧属性与新属性具有不同的语法时,这两个名称将使用简写机制进行别名处理。这些简写被定义为传统简写,其使用已被弃用。它们在其他方面表现得与常规简写完全相同,只是 CSSOM 在序列化声明时不会使用它们。[CSSOM]例如,page-break-* 属性是 break-* 属性的传统简写(参见 CSS 分页第 3 级 § 3.4 分页别名:page-break-before、page-break-after 和 page-break-inside 属性)。
设置 page-break-before: always 会像其他简写一样在解析时展开为 break-before: page。类似地,如果设置了 break-before: page,调用
getComputedStyle将返回( el). pageBreakBefore。然而,在序列化样式块时(参见 CSSOM 1 § 6.7.2 序列化 CSS 值),page-break-before 属性永远不会被选为序列化的简写,无论指定的是它还是 break-before;相反,将始终选择 break-before。"always"
3.2. 重置所有属性:all 属性
| 名称 | all |
|---|---|
| 值 | initial | inherit | unset | revert | revert-layer |
| 初始值 | 见各个属性 |
| 应用于 | 见各个属性 |
| 可继承 | 见各个属性 |
| 百分比 | 见各个属性 |
| 计算值 | 见各个属性 |
| 动画类型 | 见各个属性 |
| 规范顺序 | 按语法 |
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 属性的最终值是多步计算的结果:
- 首先,为每个元素上的每个属性收集应用于该元素的所有声明值。应用于该元素的声明值可能有零个或多个。
- 层叠产生层叠值。每个元素上的每个属性最多有一个层叠值。
- 默认设定产生指定值。每个元素上的每个属性恰好有一个指定值。
- 解决值依赖关系产生计算值。每个元素上的每个属性恰好有一个计算值。
- 格式化文档产生使用值。仅当给定属性适用于该元素时,该元素才具有该属性的使用值。
- 最后,使用值根据显示环境的约束转换为实际值。与使用值一样,元素上的给定属性可能存在也可能不存在实际值。
不连接或不是文档扁平元素树一部分的元素不参与 CSS 值处理,并且没有声明值、层叠值、指定值、计算值、使用值或实际值,即使它们可能被分配了样式声明(例如,通过 style 属性)。
4.1. 声明值
每个应用于元素的属性声明都会为该属性贡献一个与元素关联的声明值。有关详细信息,请参阅过滤声明。
这些值随后由层叠处理,以选择单个“获胜值”。
4.1.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,但通过从其第一个子元素传播获得 break-before 使用值 page。[css-break-3]
4.5.1. 适用属性
如果属性不适用于元素或盒子类型——如其“适用于”行中所述——这意味着它不会直接在该类型的盒子或元素上生效。
注:如果属性的计算值影响了其他适用的属性的计算,则不适用的属性仍然可能具有间接格式化效果;当然,其总是存在的计算值仍然可以继承给后代并对它们生效。
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 |
4.8. 片段级值处理
某些 CSS 功能会干扰基于片段的值处理。例如参见 CSS 伪元素第 4 级 § 2.1.3 继承与 ::first-line 伪元素,它改变了 ::first-line 伪元素内片段的继承。在这种情况下,当各个片段被赋予不同的指定值时,任何基于其他属性的计算值而解析的值(如 currentcolor 或 em 单位)都会按盒子片段进行解析。后续值处理在每个片段中正常进行。
假设每个盒子单一值(而不是每个盒子片段)的 API 必须忽略非树一致性伪元素的影响。(例如,::first-line 样式对 getComputedStyle() 返回的值没有影响。)
< div >< span > First line< br /> Second line</ span ></ div > < div >< span > First line</ span ></ div > < div > First line< br >< span > Second line</ span ></ div > < style > div { color : blue ; } div :: first-line { color : yellow ; } span { border : thin solid currentcolor ; } </ style >
在每个 div 中,“First line”文本为黄色,“Second line”文本为蓝色;包裹每一行的 span 的每个片段的边框与该颜色相匹配。
然而,在所有三个 span 上调用 getComputedStyle() 对于 border-color 将返回 "blue",因为 ::first-line 伪元素的影响对于不感知片段的 API 是被忽略的。
5. 过滤
为了找到声明值,实现必须首先识别应用于每个元素的所有声明。如果以下条件成立,则声明应用于元素:
- 它属于当前适用于本文档的样式表。
- 它未被具有假条件的条件规则 [CSS-CONDITIONAL-3] 限定。
- 它属于一个选择器与该元素匹配的样式规则。[SELECT](如果必要,考虑到作用域。)
- 它是语法有效的:声明的属性是已知的属性名称,并且声明的值匹配该属性的语法。
应用于该声明的值对于每个元素上的每个属性,形成一个声明值列表。下一节,层叠,将对这些列表进行优先级排序。
6. 层叠
层叠接收给定元素上给定属性的声明值的无序列表,根据下面确定的声明优先级对其进行排序,并输出单个层叠值。
6.1. 层叠排序顺序
层叠根据以下标准对声明进行排序,优先级由高到低:
- 来源和重要性
- 声明的来源基于其来源,其重要性在于是否用 !important 声明(见下文)。各种来源的优先级,按降序排列:
此列表中排在前面的 来源 的声明优于排在后面的 来源 的声明。
- 上下文
- 文档语言可以提供一种混合来自不同 封装上下文 的声明的方法,例如 [DOM] 中 影子树 的嵌套 树上下文。
当比较两个来自不同 封装上下文 的声明时,对于 普通 规则,外部上下文的声明胜出;对于 重要 规则,内部上下文的声明胜出。为此,[DOM] 树上下文 被视为按照 包含影子的树顺序 进行嵌套。
注意: 这实际上意味着属于某个 封装上下文 的 普通 声明可以设置很容易被外部上下文覆盖的默认值,而属于某个 封装上下文 的 重要 声明则可以强制执行无法被外部上下文覆盖的需求。
- 元素附加样式
- 对于 普通 和 重要 声明,直接附加到元素上的声明(例如 style 属性的内容)优先于通过样式规则选择器映射的、具有相同 重要性 的声明,而不是通过样式规则间接映射。
参见 [css-style-attr]。
注意: 非 CSS 的表现性提示(例如表现性标记)将单独处理,请参见 § 6.5 非 CSS 表现性提示的优先级。
- 层
- 每个 来源 和 上下文 内的声明都可以显式分配给一个 级联层。在此步骤中,任何未分配给显式层的声明都会被添加到隐式的最终层中。
级联层(与声明一样)按出现顺序排列。当比较属于不同层的声明时,对于 普通 规则,级联层 排在最后的声明胜出;对于 重要 规则,级联层 排在最先的声明胜出。
注意: 这遵循与分层 普通 和 重要 来源 相同的逻辑,以便 !important 标志在两种设置中保持相同的“覆盖”目的。
- 特殊性
- 选择器模块 [SELECT] 描述了如何计算选择器的特殊性。每个声明都与其所在样式规则具有相同的特殊性。特殊性最高的声明胜出。
- 出现顺序
- 文档顺序中的最后一个声明胜出。为此
- 样式表按照 最终 CSS 样式表 的顺序排列。
- 来自 导入样式表 的声明的顺序,就好像它们的样式表被替换在 @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 试图在作者样式表和用户样式表之间建立权力平衡。默认情况下,作者样式表中的规则会覆盖用户样式表中的规则,而后者会覆盖用户代理默认样式表中的规则。为了平衡这一点,声明可以被标记为 重要,这会增加其在级联中的权重并颠倒优先级顺序。
如果一个声明具有 [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. 级联层
正如 级联来源 在用户和作者样式之间提供权力平衡一样,级联层 提供了一种结构化的方式来组织和平衡单一来源内的关注点。单一 级联层 内的规则会一起级联,而不会与层外的样式规则交织。
作者可以创建层来表示元素默认值、第三方库、主题、组件、覆盖和其他样式关注点——并且能够以显式方式重新排序层的级联,而无需更改每一层内的选择器或特殊性,也不必依赖源顺序来解决层与层之间的冲突。
audio{ /* specificity of 0,0,1 - implicit (final) layer */ display: flex; } @layer reset{ audio[ controls] { /* specificity of 0,1,1 - explicit "reset" layer */ display: block; } }
audio 元素上未分层的声明优先于 audio[controls] 上显式分层的声明——即使未分层的样式具有较低的特殊性,并且在源顺序中排在前面。
定义名称的 at-规则(例如 @keyframes 或 @font-face)如果定义在 级联层 内部,在解决名称冲突时也会使用层顺序。
/* establish the layer order, so the "override" layer takes precedence */ @layer framework, override; @layer override{ @keyframes slide-left{ from{ translate : 0 ; } to{ translate : -100 % 0 ; } } } @layer framework{ @keyframes slide-left{ from{ margin-left : 0 ; } to{ margin-left : -100 % ; } } } .sidebar{ animation : slide-left300 ms ; }
在这种情况下,override 层比 framework 层具有更高的级联优先级,因此 slide-left 将使用 translate 属性而不是 margin-left 进行动画制作。
6.4.1. 声明级联层
级联层可以声明为
-
使用带有 layer 关键字或 layer() 函数的 @import 规则,将导入文件的内容分配到该层中。
-
使用 @layer 块 at-规则,将其子样式规则分配到该层中。
-
使用 @layer 语句 at-规则,声明一个命名层而不分配任何规则。
提供一个用于将 link 或 style 元素分配给级联层的属性? [Issue #w3c/csswg-drafts#5853]
6.4.2. 层命名与嵌套
级联层 具有 层名称,这是一个表示每一级层嵌套的有序列表,每一段都可以命名(作为 CSS 标识符)或匿名。(因此,当一个层嵌套在另一个层内时,这会连接它们的名称。)当一个层在另一个层的范围内声明时,它就嵌套在另一个层中,例如另一个 @layer 内的 @layer 规则、分层导入内的分层 @import,或分层导入内的 @layer 规则。
如果 层名称 包含相同的段且顺序相同,则它们代表相同的 级联层;但匿名段在每次出现时都有唯一的身份。注意,嵌套可能导致多个层共享相同的匿名段。
headings.css 和 links.css 的内容与 audio[controls] 规则在同一层内级联@import url ( headings.css ) layer ( default); @import url ( links.css ) layer ( default); @layer default{ audio[ controls] { display : block; } }
@layer base{ p{ max-width : 70 ch ; } } @layer framework{ @layer base{ p{ margin-block : 0.75 em ; } } @layer theme{ p{ color : #222; } } }
生成的层可以表示为树
-
base
-
framework
-
base
-
theme
-
或作为带有嵌套标识符的扁平列表
-
base
-
framework.base
-
framework.theme
从语法上讲,显式 层名称 由 @layer 和 @import 规则中的 <layer-name> 表示,这是一个以句点分隔的 <ident> 标记列表,中间没有空格
<layer-name> = <ident> [ '.' <ident> ]*
CSS 宽关键字 保留供将来使用,如果用作 <layer-name> 中的 <ident>,则会导致规则在解析时无效。当多个标识符用句点连接时,这是一种表示按顺序嵌套的层的速记法。
@layer framework{ @layer default{ p{ margin-block : 0.75 em ; } } @layer theme{ p{ color : #222; } } } @layer framework.theme{ /* These styles will be added to the theme layer inside the framework layer */ blockquote{ color : rebeccapurple; } }
注意: 嵌套层不能“逃离”其父层去引用其自身之外的层。
6.4.2.1. 匿名层
当 @layer 规则省略其 <layer-name>,或者 @import 规则使用 layer 关键字(该关键字不提供 <layer-name>)时,其 层名称 会获得一个唯一的匿名段;因此它不能从外部引用。
-
多个未命名的层规则将其样式放入单独的层中,因为每次出现都在引用不同的匿名层名称。
@layer { /* layer 1 */ } @layer { /* layer 2 */ } -
在单个未命名层内,同名的子层引用相同的级联层,因为它们共享相同的匿名父层。
@layer { @layer foo{ /* layer 1 */ } @layer foo{ /* also layer 1 */ } } -
而在单独的未命名层中,同名的子层引用不同的级联层,因为它们具有不同的匿名父层。
@layer { @layer foo{ /* layer 1 */ } } @layer { @layer foo{ /* layer 2 */ } }
虽然这仅仅是为了简洁的便利,但它也可以被团队用作强制执行组织约定的一种方式(该层中的所有代码必须定义在同一个地方),或者由想要合并并隐藏一组它们不想暴露给作者操作的内部“私有”层的库使用
/* bootstrap-base.css */ /* unnamed wrapper layers around each sub-file */ @import url ( base-forms.css ) layer; @import url ( base-links.css ) layer; @import url ( base-headings.css ) layer;
/* bootstrap.css */ /* the internal names are hidden from access, subsumed in "base" */ @import url ( bootstrap-base.css ) layer ( base);
/* author.css */ /* author has access to bootstrap.base layer, but not into unnamed layers */ @import url ( bootstrap.css ) layer ( bootstrap); /* Adds additional styles to the bootstrap layer: */ @layer bootstrap{ ...}
6.4.3. 层排序
级联层按其首次声明的顺序排序,嵌套层在任何未分层的规则之前分组在其父层内。
/* unlayered styles come last in the layer order */ h1{ color : darkslateblue; } @layer reset.type{ strong{ font-weight : bold; } } @layer framework{ .title{ font-weight : 100 ; } @layer theme{ h1, h2{ color : maroon; } } } @layer reset{ [ hidden] { display : none; } }
外部层首先排序,任何未分层的样式规则被添加到隐式的外层中,该外层的优先级高于(排在之后)显式层
-
重置
-
framework
-
(隐式外层)
在每一层内,嵌套层按出现顺序排序,没有进一步嵌套的样式规则类似地添加到显式嵌套层之后的隐式子层中
-
reset.type
-
reset (隐式子层)
-
framework.theme
-
framework (隐式子层)
-
(隐式外层)
定义在 条件组规则 内部的层,除非条件为真,或者 条件组规则 对于文档中的不同元素可以不同地评估,否则不会对层顺序做出贡献。
注意: 由于层顺序对整个文档是全局的,因此定义在对元素敏感的 条件组规则 内部的任何层,都需要在建立全局层顺序时予以考虑,无论规则的条件如何。然而,对文档全局的条件(例如 @media 和 @supports)可以有条件地适应此类 @layer 规则。
@media ( min-width:30 em ) { @layer layout{ .title{ font-size : x-large; } } } @media ( prefers-color-scheme: dark) { @layer theme{ .title{ color : white; } } } @layer theme, layout;
如果第一个媒体查询根据视口尺寸匹配,则 layout 层在层顺序中将排在第一位。如果配色方案偏好查询匹配,或者两个条件都不为真,则 theme 在层顺序中将排在第一位。
想要避免这种行为的作者可以提前建立层的显式顺序,并避免在条件规则内定义新层。
注意: 级联层 的范围仅限于其 来源 和 上下文,因此轻量 DOM 中层的顺序对影子 DOM 中同名层的顺序没有影响(反之亦然)。
允许作者在层顺序中显式放置未分层的样式 [Issue #6323]
6.4.4. 内联声明层:@layer 规则
6.4.4.1. 内联分配样式:@layer 块 at-规则
@layer 块 at-规则 将其子样式规则分配给特定的命名 级联层。此块层分配语法为
@layer <layer-name>? {
<stylesheet>
}
此类 @layer 块规则与带有真条件的 条件组规则 [CSS-CONDITIONAL-3] 具有相同的限制和处理方式。
@layer framework{ h1, h2{ color : maroon; background : white;} @media ( prefers-color-scheme: dark) { h1, h2{ color : red; background : black; } } }
注意: @layer 块 at-规则 不能与 @import 规则交织。
6.4.4.2. 无样式声明:@layer 语句 at-规则
@layer 规则也可以用于定义新层而不分配任何样式规则,方法是仅提供 层名称
@layer <layer-name>#;
此类空 @layer 规则允许在 @import 和 @namespace 规则之前(在 @charset 规则之后,如果有的话),以及允许 @layer 块 at-规则 的任何地方。
注意: @import 和 @namespace 规则之间不允许存在任何 @layer 规则。任何出现在 @import 或 @namespace 规则之后的 @layer 规则都会导致任何随后的 @import 或 @namespace 规则被忽略。
与 块语法 不同,在此语法中可以提供多个以逗号分隔的层名称,按指定的顺序声明每一层。
注意: 由于层排序由层名称的首次出现定义(参见 § 6.4.3 层排序),此规则允许页面预先声明其层顺序,这样无需阅读整个样式表即可明显看出其顺序。它还允许内联层与导入层交织,这在 块语法 中是不可能的。
theme.css 样式规则将覆盖随后在 default 块中添加的任何规则,因为层的顺序已经建立@layer default, theme, components; @import url ( theme.css ) layer ( theme); @layer default{ audio[ controls] { display : block; } }
也可以通过将 @import 规则放置在 @layer 规则之间来帮助建立顺序。此示例将产生相同的结果
@layer default; @import url ( theme.css ) layer ( theme); @layer components; @layer default{ audio[ controls] { display : block; } }
但是,@import 和 @namespace 规则必须是连续的,中间不能有任何规则。以下写法是无效的
@import url ( default.css ) layer ( default); @layer theme; @import url ( components.css ) layer ( components); @layer theme{ audio[ controls] { display : block; } }
6.5. 非 CSS 表现性提示的优先级
UA 可以选择尊重源文档标记中的表现性提示,例如 [HTML] 中的 bgcolor 属性或 s 元素。所有基于文档语言的样式都必须转换为相应的 CSS 规则,并作为规则进入级联,位于常规 用户来源 和 作者来源 之间的 UA 来源 或专门的 作者表现性提示来源 中。为了 级联 的目的,该 作者表现性提示来源 被视为一个独立的 来源,但为了 revert 关键字的目的,它被视为 的一部分。
文档语言可以定义此类表现性提示是以 UA 来源 还是 作者来源 进入 级联;如果是,UA 必须相应地表现。例如,[SVG11] 将其表现属性映射到 中。
注意: 以 UA 来源 规则进入 级联 的表现性提示可以被 作者来源 或 用户来源 样式覆盖。以 作者表现性提示来源 规则进入级联的表现性提示可以被 样式覆盖,但不能被非 重要 的 用户来源 样式覆盖。宿主语言在考虑这些因素时,应为表现性提示选择合适的来源。
7. 默认值
当 级联 没有产生值时,必须通过其他方式找到 指定值。继承属性 通过 继承 从其父元素获取默认值;所有其他属性采用其 初始值。作者可以通过 inherit 和 initial 关键字显式请求继承或初始化。
7.1. 初始值
每个属性都有一个 初始值,定义在属性的定义表中。如果该属性不是 继承属性,并且 级联 没有产生值,则该属性的 指定值 就是其 初始值。
7.2. 继承
继承 将属性值从父元素传播到其子元素。元素上属性的 继承值 是该元素父元素上该属性的 计算值。对于没有父元素的根元素,继承值 是该属性的 初始值。
对于带有影子的 [DOM] 树,继承在 扁平元素树 上运行。 这意味着槽位元素是从它们被分配到的 slot 继承,而不是直接从其 轻量树 父元素继承。 伪元素 根据为每个 伪元素 描述的虚构标签序列进行继承。 [CSS-PSEUDO-4]
一些属性是 继承属性,如在其属性定义表中定义的那样。这意味着,除非 级联 产生了值,否则该值将由 继承 决定。
属性也可以显式继承。参见 inherit 关键字。
注意: 继承遵循文档树,不会被 匿名框 拦截,也不会受到框树操作的影响。
7.3. 显式默认值
下面定义了几个 CSS 宽属性值;将属性声明为具有这些值可以显式指定特定的默认行为。正如 CSS 值与单位 [css-values-3] 中所指定,所有 CSS 属性都可以接受这些值。
7.3.1. 重置属性:initial 关键字
如果属性的 级联值 是 initial 关键字,则该属性的 指定值 是其 初始值。
7.3.2. 显式继承:inherit 关键字
如果属性的 级联值 是 inherit 关键字,则该属性的 指定值 和 计算值 是 继承值。
7.3.3. 清除所有声明:unset 关键字
如果属性的 级联值 是 unset 关键字,那么如果它是继承属性,则视为 inherit,如果不是,则视为 initial。此关键字有效地清除了 级联 中较早出现的所有 声明值,并根据属性(或 速记 属性的所有长手属性)的适用情况正确继承或不继承。
7.3.4. 回滚级联来源:revert 关键字
如果属性的 级联值 是 revert 关键字,其行为取决于该声明所属的 级联来源
- 用户代理原点
- 等同于 unset。
- 用户来源
- 将 级联值 回滚到用户代理级别,以便 指定值 的计算就好像在此元素上没有为此属性指定 作者来源 或 用户来源 规则一样。
- 作者来源
- 将 级联值 回滚到用户级别,以便 指定值 的计算就好像在此元素上没有为此属性指定 作者来源 规则一样。为了 revert 的目的,该来源包括动画 来源。
7.3.5. 回滚级联层:revert-layer 关键字
如果属性的 级联值 是 revert-layer 关键字,则 级联值 会回滚到下方的 层,以便 指定值 的计算就好像在当前 级联层 中——或在 级联 中的 普通 和 重要 级别之间——没有为此属性在此元素上指定规则一样。但是,对于 重要 元素附加样式 中的 revert-layer,它仅还原 元素附加样式 和中间的 动画来源,而不还原任何中间的 作者来源 重要 规则。
注意: 如果在与 revert-layer 值相同的 级联来源 中没有更低优先级的声明,则 级联值 将回滚到前一个来源。
注意: 出于此目的,动画来源 不会像 revert 那样与 作者来源 合并,因此有效地形成了其自己的 级联层。
8. 层 API
8.1. CSSImportRule 接口的扩展
CSSImportRule 接口扩展如下
partial interface CSSImportRule {readonly attribute CSSOMString ?layerName ; };
其 layerName 属性表示在 at-规则本身中声明的 层名称;如果层是匿名的,则为空字符串;如果 at-规则未声明层,则为 null。
8.2. CSSLayerBlockRule 接口
CSSLayerBlockRule 接口表示 @layer 块规则
[Exposed =Window ]interface :CSSLayerBlockRule CSSGroupingRule {readonly attribute CSSOMString name ; };
其 name 属性表示 at-规则本身声明的 层名称;如果层是匿名的,则为空字符串。
8.3. CSSLayerStatementRule 接口
CSSLayerStatementRule 接口表示 @layer 语句
[Exposed =Window ]interface :CSSLayerStatementRule CSSRule {readonly attribute FrozenArray <CSSOMString >nameList ; };
其 nameList 属性表示 at-规则声明的 层名称 列表,其规范化遵循与 CSSLayerBlockRule 的 name 属性相同的规则。
9. 更改
9.1. 2021 年 10 月 15 日工作草案以来的更改
自 2021 年 10 月 15 日工作草案 以来的重大更改
-
更新了 @import 媒体查询和 supports 条件的语法样式
-
允许函数式表示法解析时别名(Issue 6193)
-
使 CSSImportRule.layerName 可为空(Issue 6576)
-
澄清了样式属性中的 revert-layer 不会还原作者层(Issue 6743)
-
澄清了样式属性和关键帧上的 revert-layer(Issue 6743)
-
添加了 § 4.1.1 值别名 部分。(Issue 6193)
-
添加了 § 8 层 API 部分。(Issue 6576)
-
澄清了在样式属性或 @keyframes at-规则中使用时 revert-layer 关键字的行为。(Issue 6743)
-
澄清了 @import 规则上 layer 关键字和 layer() 函数的行为。(Issue 6776)
9.2. 2021 年 8 月 29 日工作草案以来的更改
自 2021 年 8 月 29 日工作草案 以来的更改包括
-
恢复未分层样式的排序。(参见 § 9.3 2021 年 6 月 8 日工作草案以来的更改 和 Issue 6284)
-
定义表现性提示使用 作者表现性提示来源 而不是层,这与对 [CSS-CASCADE-4] 的更新相匹配。(Issue 6659)
9.3. 2021 年 6 月 8 日工作草案以来的更改
自 8 June 2021 Working Draft 以来的重大更改包括
-
保留 CSS 宽关键字以供将来在层名称中使用。(Issue 6323)
-
澄清 @layer 规则尊重全局条件规则,但当在非全局条件(例如容器查询)中声明时,总是应用于层顺序。(Issue 6407)
-
定义名称的 at-规则遵循层顺序进行冲突解决,类似于特殊性解决。(Issue 6404)
-
禁止 @layer 与 @import 或 @namespace 规则交织。(Issue 6522)
9.4. 2021 年 3 月 19 日工作草案以来的更改
自 2021 年 3 月 19 日工作草案 以来的重大更改包括
-
将未分层样式的排序从普通来源中的最高优先级切换为最低优先级。(Issue 6284)
9.5. 2021 年 1 月 19 日工作草案以来的更改
自 2021 年 1 月 19 日首次公开工作草案 以来的重大更改包括
-
将 层 导入语法从使用 @layer 切换为使用 @import。(Issue 5681)
-
添加了 revert-layer 关键字。(Issue 5793)
9.6. Level 4 以来的新增功能
自 Level 4 以来添加了以下功能
-
引入了用于定义级联层的 @layer 规则。
-
将 layer/layer() 选项添加到 @import 定义中。
-
引入了用于将值回滚到先前层的 revert-layer 关键字。
9.7. Level 3 以来的新增功能
自 Level 3 以来添加了以下功能
-
引入了用于回滚级联的 revert 关键字。
-
引入了用于支持条件的 @import 规则的 supports() 语法。
-
定义了 CSS 用于支持遗留语法的两个属性别名机制。参见 § 3.1 属性别名。
9.8. Level 2 以来的新增功能
自 Level 2 以来添加了以下功能
致谢
David Baron、Tantek Çelik、Florian Rivoal、Simon Sapin、Jen Simmons 和 Boris Zbarsky 为本规范做出了贡献。
隐私与安全考虑
-
级联过程不区分同源和跨源样式表,这使得跨源样式表的内容可以从它们应用于文档的计算样式中推断出来。
-
通过应用样式规则表示的用户偏好和 UA 默认值通过级联过程暴露,并且可以从它们应用于文档的计算样式中推断出来。
-
@import 规则假定没有
Content-Type元数据(如果宿主文档处于怪异模式,则为任何同源文件)的资源为text/css,这可能允许任意文件被导入到页面中并被解释为 CSS,从而可能允许从它们应用于文档的计算样式中推断出敏感数据。