1. 简介
本节不具有规范性。
本模块定义了 CSS 样式表以及其他使用 CSS 语法的内容(例如 HTML style 属性)的抽象语法和解析方式。
它定义了将 Unicode 代码点流(即文本)转换为 CSS 词法单元流,并进一步转换为样式表、规则和声明等 CSS 对象的算法。
1.1. 模块交互
本模块定义了 CSS 样式表的语法和解析。它取代了 CSS 2.1 中定义的词法扫描器和语法。
2. CSS 语法描述
本节不具有规范性。
CSS 文档是一系列样式规则(即应用于文档中元素的限定规则)和@规则(定义 CSS 文档的特殊处理规则或值)。
一条限定规则以序言(prelude)开始,然后是一个包含一系列声明的 {} 包裹块。序言的含义取决于规则出现的上下文——对于样式规则,它是一个选择器,指定了声明将应用于哪些元素。每个声明都有一个名称,后跟一个冒号和声明值。声明之间用分号分隔。
一条典型的规则可能如下所示
p > a {
color: blue;
text-decoration: underline;
}
在上述规则中,“p > a”是选择器。如果源文档是 HTML,它会选择作为 a 元素子级的所有 p 元素。
“color: blue”是一个声明,指定对于匹配选择器的元素,其 color 属性应具有 blue 值。同样,其 text-decoration 属性应具有 underline 值。
@规则各不相同,但它们有一个共同的基本结构。它们以“@”代码点开始,后跟其作为 CSS 关键字的名称。一些 @规则是简单语句,其名称后跟更多 CSS 值以指定其行为,并最终以分号结束。另一些是块;它们可以在名称后带有 CSS 值,但以 {} 包裹的块结束,类似于限定规则。即使这些块的内容也特定于给定的 @规则:有时它们包含一系列声明,就像限定规则;其他时候,它们可能包含额外的块、@规则或其他结构。
以下是几个 @规则的示例,说明了它们可能包含的多样化语法。
@import "my-styles.css";
@import @规则是一个简单语句。在其名称之后,它接受单个字符串或 url() 函数来指示应导入的样式表。
@page :left {
margin-left: 4cm;
margin-right: 3cm;
}
@page @规则由一个可选的页面选择器(:left 伪类)组成,后跟打印页面时应用的属性块。这样,它与普通样式规则非常相似,不同之处在于其属性不应用于任何“元素”,而是应用于页面本身。
@media print {
body { font-size: 10pt }
}
@media @规则以媒体类型和可选的媒体查询列表开始。其块中包含整个规则,这些规则仅在满足 @media 条件时才应用。
属性名称和 @规则名称始终是 标识符序列,必须以 标识符起始代码点、两个连字符或一个连字符后跟一个标识符起始代码点开始,并且可以包含零个或多个 标识符代码点。你可以通过转义来包含任何代码点,即使是 CSS 在其语法中使用的那些。
选择器的语法定义在 Selectors 规范中。同样,各种 CSS 值的语法定义在 Values & Units 规范中。各个 @规则的特殊语法可以在定义它们的规范中找到。
2.1. 转义
本节不具有规范性。
任何 Unicode 代码点都可以通过转义包含在标识符序列或引号字符串中。CSS 转义序列以反斜杠 (\) 开始,并继续:
- 任何不是十六进制数字或换行符的 Unicode 代码点。转义序列被该 代码点替换。
- 或一到六个十六进制数字,后跟可选的空白。转义序列被其十六进制数字对应值的 Unicode 代码点替换。此可选空白允许十六进制转义序列后跟“真实”的十六进制数字。
一个值为 "&B" 的 标识符序列可以写为 \26 B 或 \000026B。
转义序列后的“真实”空格必须双写。
2.2. 错误处理
本节不具有规范性。
当 CSS 出现错误时,解析器会尝试优雅地恢复,仅丢弃最少量的内容后恢复正常解析。这是因为错误并不总是由于错误造成的——新语法对旧解析器来说看起来像是个错误,能够添加新语法到语言中而不必担心包含这些语法的样式表在旧用户代理(UA)中完全崩溃是非常有用的。
精确的错误恢复行为在解析器本身中进行了详细说明,但它足够简单,一个简短的描述就已经相当准确。
- 在样式表的“顶层”,<at-keyword-token> 开启一个 @规则。其他任何内容都会开启一个限定规则,并包含在规则的序言中。这可能会产生一个无效的选择器,但这不是 CSS 解析器所关心的——最坏的情况,意味着该选择器将匹配不到任何东西。
- 一旦 @规则开始,从解析器的角度来看,没有任何内容是无效的;它们都是 @规则序言的一部分。遇到 <semicolon-token> 会立即结束 @规则,而遇到开花括号 <{-token> 则开启 @规则的体。@规则会向前查找,匹配块(由 ()、{} 或 [] 包裹的内容),直到找到一个不被其他任何内容匹配,也不在另一个块内的闭花括号 <}-token>。然后根据 @规则自身的语法解释 @规则的内容。
- 限定规则的工作方式类似,只是分号不会结束它们;相反,它们只是被当作规则序言的一部分。当找到第一个 {} 块时,内容始终被解释为声明列表。
- 在解释声明列表时,任何地方出现的未知语法都会导致解析器丢弃当前正在构建的声明,并向前查找直到找到分号(或块的结尾)。然后它会重新开始,再次尝试解析声明。
- 如果样式表在任何规则、声明、函数、字符串等仍处于打开状态时结束,所有内容都会自动关闭。这并不会使它们无效,尽管它们可能不完整,因此在根据其语法验证时可能会被丢弃。
在解析每个结构(声明、样式规则、@规则)后,用户代理会根据其预期的语法对其进行检查。如果它不符合该语法,则它是 无效的,并会被 UA 忽略,UA 将其视为完全不存在。
3. CSS 的分词与解析
用户代理必须使用本规范中描述的解析规则,从 text/css 资源生成 [CSSOM] 树。这些规则共同定义了所谓的 CSS 解析器。
本规范定义了 CSS 文档的解析规则,无论它们在语法上是否正确。解析算法中的某些点被称为 解析错误。解析错误的错误处理定义明确:用户代理在遇到此类问题时,必须按照下述描述操作,或者在遇到它们不希望应用下述规则的第一个错误时中止处理。
一致性检查器必须在文档中存在一个或多个解析错误条件时,向用户报告至少一个解析错误条件;如果文档中不存在任何解析错误条件,则不得报告解析错误条件。如果文档中存在多个解析错误条件,一致性检查器可以报告多个解析错误条件。一致性检查器不需要从解析错误中恢复,但如果它们确实恢复,则必须以与用户代理相同的方式恢复。
3.1. 解析模型概述
CSS 解析过程的输入由一系列 Unicode 代码点组成,这些代码点经过分词阶段,随后是树构建阶段。输出是一个 CSSStyleSheet 对象。
注: 不支持脚本的实现不必实际创建 CSSOM CSSStyleSheet 对象,但在这种情况下,CSSOM 树仍然用作本规范其余部分的模型。
3.2. 输入字节流
解析样式表时,构成分词阶段输入的 Unicode 代码点流最初可能被用户代理视为字节流(通常来自网络或本地文件系统)。如果是这样,用户代理必须根据特定的字符编码将这些字节解码为 代码点。
- 如果 HTTP 或等效协议为 样式表 提供了 编码标签(例如通过 Content-Type 头部的 charset 参数),则从 编码标签 获取编码。如果未返回失败,则返回它。
- 否则,检查 样式表 的字节流。如果流的前 1024 个字节以十六进制序列开始:
40 63 68 61 72 73 65 74 20 22 XX* 22 3B
其中每个
XX字节是 016 到 2116(含)或 2316 到 7F16(含)之间的值,则从由XX字节序列构成的字符串(解释为ASCII)中 获取编码。该字节序列意味着什么?
上述字节序列,当作为 ASCII 解码时,是字符串“
@charset "…";”,其中“…”是对应于编码标签的字节序列。如果返回值是
utf-16be或utf-16le,则返回utf-8;如果是除失败之外的任何其他值,则返回它。为什么在声明说 utf-16 时使用 utf-8?
编码声明的字节在 ASCII 中拼写为“
@charset "…";”,但 UTF-16 不兼容 ASCII。要么你输入了完全乱码(如䁣桡牳整•utf-16be∻)以获得正确的字节,这是我们不鼓励的;要么你的文档实际上是 ASCII 兼容的编码,而你的编码声明在撒谎。无论哪种情况,默认使用 UTF-8 都是一个不错的答案。
此外,这模仿了 HTML 的
<meta charset>属性的行为。注: 注意编码声明的语法 看起来像 名为 @charset 的 @规则,但实际上并不存在这样的规则,编写它的规则比通常识别此类规则的限制要严格得多。在 CSS 中可以做的许多事情,如果 @charset 规则存在,它们会产生一个有效的 @charset 规则,例如使用多个空格、注释或单引号,都会导致编码声明无法被识别。这种行为使编码声明尽可能简单,从而最大程度地提高其被正确实现的可能性。
- 否则,如果引用文档提供了 环境编码,则返回它。
- 否则,返回
utf-8。
虽然 UTF-8 是 Web 的默认编码,许多较新的基于 Web 的文件格式假定或要求 UTF-8 编码,但 CSS 创建于尚不清楚哪种编码会胜出的时代,因此无法自动假设样式表是 UTF-8。
样式表作者 应该 以 UTF-8 编写样式表,并确保 HTTP 头部(或等效方法)声明样式表编码为 UTF-8,或者引用文档声明其编码为 UTF-8。(在 HTML 中,这是通过在文档头部添加 <meta charset=utf-8> 元素完成的。)
如果这两个选项都不可用,作者应该以 UTF-8 BOM 或确切字符开始样式表:
@charset "utf-8";
引用从字节解码的 CSS 样式表的文档语言可以为每个此类样式表定义 环境编码,当其他编码提示不可用或无法使用时,将其用作回退。
环境编码 的概念仅存在于与遗留内容的兼容性。新格式和新链接机制 不应 提供 环境编码,因此在缺乏更明确信息的情况下,样式表默认为 UTF-8。
注: [HTML] 定义了 <link rel=stylesheet> 的环境编码。
注: [CSSOM] 定义了 <xml-stylesheet?> 的环境编码。
注: [CSS-CASCADE-3] 定义了 @import 的环境编码。
3.3. 输入流预处理
输入流 由输入字节流解码时推入的 已过滤代码点 组成。
4. 分词(Tokenization)
要将一系列 代码点 input 分词 为 CSS 词法单元流,重复从 input 消费一个词法单元,直到到达 <EOF-token>,并将返回的每个词法单元推入流中。
注: 每次调用 消费一个词法单元 算法都会返回单个词法单元,因此如果需要,也可以在解析 期间 “按需”使用它来对一系列 代码点 进行分词。
分词步骤的输出是零个或多个以下词法单元的流:<ident-token>,<function-token>,<at-keyword-token>,<hash-token>,<string-token>,<bad-string-token>,<url-token>,<bad-url-token>,<delim-token>,<number-token>,<percentage-token>,<dimension-token>,<whitespace-token>,<CDO-token>,<CDC-token>,<colon-token>,<semicolon-token>,<comma-token>,<[-token>,<]-token>,<(-token>,<)-token>,<{-token> 和 <}-token>。
- <ident-token>, <function-token>, <at-keyword-token>, <hash-token>, <string-token>, 和 <url-token> 具有由零个或多个 代码点 组成的值。此外,哈希词法单元具有一个设置为 "id" 或 "unrestricted" 的类型标志。如果未另行设置,类型标志默认为 "unrestricted"。
- <delim-token> 具有由单个 代码点 组成的值。
- <number-token>, <percentage-token>, 和 <dimension-token> 具有数值。 <number-token> 和 <dimension-token> 此外具有设置为 "integer" 或 "number" 的类型标志。如果未另行设置,类型标志默认为 "integer"。 <dimension-token> 此外具有一个由一个或多个 代码点 组成的单位。
注: 哈希词法单元的类型标志用于选择器语法 [SELECT]。只有类型为 "id" 的哈希词法单元才是有效的 ID 选择器。
4.1. 词法铁路图
本节是非规范性的。
本节以铁路图的形式提供了分词器的非正式视图。铁路图比显式解析器更紧凑,但通常比正则表达式更容易阅读。
这些图是 非正式 且 不完整 的;它们描述了“正确”词法单元的语法,但根本没有描述错误处理。提供它们纯粹是为了让读者更容易对每个词法单元的语法获得直观理解。
名称为 <foo-token> 的图表示词法单元。其余是其他图引用的产品。
- 注释
-
- 换行符
-
- 空白
-
- 十六进制数字
-
- 转义
-
- <whitespace-token>
-
- ws*
-
- <ident-token>
-
- <function-token>
-
- <at-keyword-token>
-
- <hash-token>
-
- <string-token>
-
- <url-token>
-
- <number-token>
-
- <dimension-token>
-
- <percentage-token>
-
- <CDO-token>
-
- <CDC-token>
-
4.2. 定义
本节定义了分词阶段使用的几个术语。
- 下一个输入码位
- 输入流中尚未消费的第一个 代码点。
- 当前输入码位
- 刚刚消费的最后一个 代码点。
- 重新消费当前输入码位
- 将 当前输入代码点 推回 输入流 的前端,以便下次被指示消费 下一个输入代码点 时,将重新消费 当前输入代码点。
- EOF 代码点
- 表示 输入流 结尾的概念性 代码点。只要 输入流 为空,下一个输入代码点 就始终是 EOF 代码点。
- digit
- 介于 U+0030 数字 0 (0) 和 U+0039 数字 9 (9) 之间(含)的 代码点。
- 十六进制数字
- 一个 数字,或者介于 U+0041 拉丁大写字母 A (A) 和 U+0046 拉丁大写字母 F (F) 之间(含)的 代码点,或者是介于 U+0061 拉丁小写字母 a (a) 和 U+0066 拉丁小写字母 f (f) 之间(含)的 代码点。
- 大写字母
- 介于 U+0041 拉丁大写字母 A (A) 和 U+005A 拉丁大写字母 Z (Z) 之间(含)的 代码点。
- 小写字母
- 介于 U+0061 拉丁小写字母 a (a) 和 U+007A 拉丁小写字母 z (z) 之间(含)的 代码点。
- 字母
- 一个 大写字母 或 小写字母。
- 非 ASCII 代码点
- 值等于或大于 U+0080 <控制> 的 代码点。
- 标识符起始代码点
- 一个 字母、一个 非 ASCII 代码点 或 U+005F 下划线 (_)。
- 标识符代码点
- 一个 标识符起始代码点、一个 数字 或 U+002D 连字符-减号 (-)。
- 不可打印码位
- 介于 U+0000 NULL 和 U+0008 退格键之间(含)的 代码点,或者 U+000B 水平制表符,或者是介于 U+000E 移出字符和 U+001F 信息分隔符 1 之间(含)的 代码点,或者是 U+007F 删除。
- newline
- U+000A 换行符。 注意 U+000D 回车符和 U+000C 换页符不包含在此定义中,因为它们在 预处理 期间被转换为 U+000A 换行符。
- whitespace(空白字符)
- 一个 换行符、U+0009 水平制表符或 U+0020 空格。
- 最大允许码位
- Unicode 定义的最大 代码点:U+10FFFF。
- 标识符序列
- 具有与 <ident-token> 相同语法的一系列 代码点。
注: <at-keyword-token> 中 "@" 之后的部分,<hash-token>(带有 "id" 类型标志)中 "#" 之后的部分,<function-token> 中 "(" 之前的部分,以及 <dimension-token> 的单位都是 标识符序列。
- 表示
- 词法单元的 表示形式 是调用 消费一个词法单元 算法所消费的 输入流 的子序列。这被保留用于某些依赖输入文本细微细节的算法,而简单的词法单元“重新序列化”可能会破坏这些细节。
表示形式 仅被内部算法消费,绝不会直接暴露,因此实际上并不需要保留确切的文本;等效的方法,例如将每个词法单元与源文本中的偏移量相关联,也已足够。
注: 特别是,表示形式 保留了诸如 .009 是写作 .009 还是 9e-3,以及字符是按字面写作还是作为 CSS 转义写作等细节。前者对于正确解析 <urange> 产品是必要的;后者基本上是分词抽象的一个偶然泄露,但之所以允许,是因为它使实现更容易定义。
如果词法单元是由算法直接产生的,而不是通过本规范中的分词算法,其表示形式就是空字符串。
4.3. 分词器算法
本节定义的算法将一系列 代码点 转换为一系列词法单元。
4.3.1. 消费一个词法单元
本节描述如何从一系列 代码点 中 消费一个词法单元。它将返回任何类型的单个词法单元。
消费注释.
消费 下一个输入代码点。
- whitespace(空白字符)
- 尽可能多地消费 空白。返回一个 <whitespace-token>。
- U+0022 引号 (")
- 消费字符串词法单元并返回。
- U+0023 井号 (#)
- 如果 下一个输入代码点 是一个 标识符代码点,或者 接下来的两个输入代码点 是有效的转义,则:
- 创建一个 <hash-token>。
- 如果 接下来的 3 个输入代码点 将开启标识符序列,设置 <hash-token> 的类型标志为 "id"。
- 消费标识符序列,并将 <hash-token> 的值设置为返回的字符串。
- 返回 <hash-token>。
否则,返回一个值为 当前输入代码点 的 <delim-token>。
- U+0027 单引号 (')
- 消费字符串词法单元并返回。
- U+0028 左括号 (()
- 返回一个 <(-token>。
- U+0029 右括号 ())
- 返回一个 <)-token>。
- U+002B 加号 (+)
- 如果输入流 以数字开始,重新消费当前输入代码点,消费数值型词法单元,并返回它。
否则,返回一个值为 当前输入代码点 的 <delim-token>。
- U+002C 逗号 (,)
- 返回一个 <comma-token>。
- U+002D 连字符-减号 (-)
- 如果输入流 以数字开始,重新消费当前输入代码点,消费数值型词法单元,并返回它。
否则,如果 接下来的 2 个输入代码点 是 U+002D 连字符-减号 U+003E 大于号 (->),消费它们并返回一个 <CDC-token>。
否则,如果输入流 以标识符序列开始,重新消费当前输入代码点,消费标识符类词法单元,并返回它。
否则,返回一个值为 当前输入代码点 的 <delim-token>。
- U+002E 句点 (.)
- 如果输入流 以数字开始,重新消费当前输入代码点,消费数值型词法单元,并返回它。
否则,返回一个值为 当前输入代码点 的 <delim-token>。
- U+003A 冒号 (:)
- 返回一个 <colon-token>。
- U+003B 分号 (;)
- 返回一个 <semicolon-token>。
- U+003C 小于号 (<)
- 如果 接下来的 3 个输入代码点 是 U+0021 感叹号 U+002D 连字符-减号 U+002D 连字符-减号 (!--),消费它们并返回一个 <CDO-token>。
否则,返回一个值为 当前输入代码点 的 <delim-token>。
- U+0040 @符号 (@)
- 如果 接下来的 3 个输入代码点 将开启标识符序列,消费标识符序列,创建一个值设置为返回值的 <at-keyword-token>,并返回它。
否则,返回一个值为 当前输入代码点 的 <delim-token>。
- U+005B 左方括号 ([)
- 返回一个 <[-token>。
- U+005C 反斜杠 (\)
- 如果输入流 以有效的转义开始,重新消费当前输入代码点,消费标识符类词法单元,并返回它。
否则,这是一个 解析错误。返回一个值为 当前输入代码点 的 <delim-token>。
- U+005D 右方括号 (])
- 返回一个 <]-token>。
- U+007B 左花括号 ({)
- 返回一个 <{-token>。
- U+007D 右花括号 (})
- 返回一个 <}-token>。
- digit
- 重新消费当前输入代码点,消费数值型词法单元,并返回它。
- 标识符起始码位
- 重新消费当前输入代码点,消费标识符类词法单元,并返回它。
- EOF
- 返回一个 <EOF-token>。
- 其他任何情况
- 返回一个值为 当前输入代码点 的 <delim-token>。
4.3.2. 消费注释
本节描述如何从一系列 代码点 中 消费注释。它不返回任何内容。
如果 接下来的两个输入代码点 是 U+002F 斜杠 (/) 后跟 U+002A 星号 (*),消费它们以及随后所有 代码点,直到并包含第一个 U+002A 星号 (*) 后跟 U+002F 斜杠 (/),或者直到 EOF 代码点。返回此步骤的开头。
如果上一段以消费 EOF 代码点结束,这是一个 解析错误。
返回空值。
4.3.3. 消费数值型词法单元
本节描述如何从一系列 代码点 中 消费数值型词法单元。它返回 <number-token>、<percentage-token> 或 <dimension-token>。
消费数字,令 number 为结果。
如果 接下来的 3 个输入代码点 将开启标识符序列,则:
- 创建一个具有与 number 相同的值和类型标志、初始单位为空字符串的 <dimension-token>。
- 消费标识符序列。将 <dimension-token> 的单位设置为返回的值。
- 返回 <dimension-token>。
否则,如果 下一个输入代码点 是 U+0025 百分号 (%),消费它。创建一个具有与 number 相同值的 <percentage-token> 并返回它。
否则,创建一个具有与 number 相同值和类型标志的 <number-token> 并返回它。
4.3.4. 消费标识符类词法单元
本节描述如何从一系列 代码点 中 消费标识符类词法单元。它返回 <ident-token>、<function-token>、<url-token> 或 <bad-url-token>。
消费标识符序列,令 string 为结果。
如果 string 的值与 "url" ASCII 大小写不敏感 匹配,并且 下一个输入代码点 是 U+0028 左括号 ((),消费它。当 接下来的两个输入代码点 为 空白 时,消费 下一个输入代码点。如果 接下来的一个或两个输入代码点 是 U+0022 引号 (")、U+0027 单引号 ('),或者 空白 后跟 U+0022 引号 (") 或 U+0027 单引号 ('),则创建一个值设置为 string 的 <function-token> 并返回它。否则,消费 URL 词法单元并返回。
否则,如果 下一个输入代码点 是 U+0028 左括号 ((),消费它。创建一个值设置为 string 的 <function-token> 并返回它。
否则,创建一个值设置为 string 的 <ident-token> 并返回它。
4.3.5. 消费字符串词法单元
本节描述如何从一系列 代码点 中 消费字符串词法单元。它返回 <string-token> 或 <bad-string-token>。
此算法可以用 结束代码点 调用,该代码点表示结束字符串的 代码点。如果未指定 结束代码点,则使用 当前输入代码点。
初始创建一个值设置为字符串的 <string-token>。
重复消费 下一个输入代码点:
- 结束代码点
- 返回 <string-token>。
- EOF
- 这是一个 解析错误。返回 <string-token>。
- newline
- 这是一个 解析错误。重新消费当前输入代码点,创建一个 <bad-string-token> 并返回它。
- U+005C 反斜杠 (\)
- 如果 下一个输入代码点 是 EOF,则不执行任何操作。
否则,如果 下一个输入代码点 是换行符,消费它。
否则,(流 以有效的转义开始) 消费转义代码点 并将返回的 代码点 追加到 <string-token> 的值中。
- 其他任何情况
- 将 当前输入代码点 追加到 <string-token> 的值中。
4.3.6. 消费 URL 词法单元
本节描述如何从一系列 代码点 中 消费 URL 词法单元。它返回 <url-token> 或 <bad-url-token>。
注: 此算法假定初始的 "url(" 已经消费。此算法还假定它是为了消费“未加引号”的值(例如 url(foo))而被调用。加引号的值(例如 url("foo"))被解析为 <function-token>。消费标识符类词法单元 会自动处理此区别;否则不应直接调用此算法。
- 初始创建一个值设置为字符串的 <url-token>。
- 尽可能多地消费 空白。
- 重复消费 下一个输入代码点:
- U+0029 右括号 ())
- 返回 <url-token>。
- EOF
- 这是一个 解析错误。返回 <url-token>。
- whitespace(空白字符)
- 尽可能多地消费 空白。如果 下一个输入代码点 是 U+0029 右括号 ()) 或 EOF,消费它并返回 <url-token>(如果遇到 EOF,这是一个 解析错误);否则 消费错误 URL 的剩余部分,创建一个 <bad-url-token> 并返回它。
- U+0022 引号 (")
- U+0027 单引号 (')
- U+0028 左括号 (()
- 不可打印码位
- 这是一个 解析错误。消费错误 URL 的剩余部分,创建一个 <bad-url-token> 并返回它。
- U+005C 反斜杠 (\)
- 如果流 以有效的转义开始,消费转义代码点 并将返回的 代码点 追加到 <url-token> 的值中。
否则,这是一个 解析错误。消费错误 URL 的剩余部分,创建一个 <bad-url-token> 并返回它。
- 其他任何情况
- 将 当前输入代码点 追加到 <url-token> 的值中。
4.3.7. 消费转义代码点
本节描述如何 消费转义代码点。它假定 U+005C 反斜杠 (\) 已经消费,并且下一个输入代码点已经被验证为有效的转义的一部分。它将返回一个 代码点。
消费 下一个输入代码点。
- 十六进制数字
- 消耗尽可能多的十六进制数字,但最多不超过 5 个。注意,这意味着总共消耗了 1-6 个十六进制数字。如果下一个输入代码点是空白字符,则一并消耗。将这些十六进制数字解析为十六进制数值。如果该数值为零,或者是代理对(surrogate),或者大于最大允许代码点,则返回 U+FFFD 替换字符 ()。否则,返回具有该值的代码点。
- EOF
- 这是一个解析错误。返回 U+FFFD 替换字符 ()。
- 其他任何情况
- 返回当前输入代码点。
4.3.8. 检查两个代码点是否为有效的转义
本节描述如何检查两个代码点是否为有效的转义。此处描述的算法可以显式调用并传入两个代码点,也可以使用输入流本身进行调用。在后一种情况下,所涉及的两个代码点依次为当前输入代码点和下一个输入代码点。
注意:此算法不会消耗任何额外的代码点。
如果第一个代码点不是 U+005C 反斜杠 (\),则返回 false。
否则,返回 true。
4.3.9. 检查三个代码点是否会启动标识符序列
本节描述如何检查三个代码点是否会启动标识符序列。此处描述的算法可以显式调用并传入三个代码点,也可以使用输入流本身进行调用。在后一种情况下,所涉及的三个代码点依次为当前输入代码点和接下来的两个输入代码点。
注意:此算法不会消耗任何额外的代码点。
查看第一个代码点
- U+002D 连字符-减号 (-)
- 如果第二个代码点是标识符起始代码点或 U+002D 连字符 (-),或者第二个和第三个代码点是有效的转义,则返回 true。否则,返回 false。
- 标识符起始码位
- 返回 true。
- U+005C 反斜杠 (\)
- 如果第一个和第二个代码点是有效的转义,则返回 true。否则,返回 false。
- 其他任何情况
- 返回 false。
4.3.10. 检查三个代码点是否会启动数字
本节描述如何检查三个代码点是否会启动数字。此处描述的算法可以显式调用并传入三个代码点,也可以使用输入流本身进行调用。在后一种情况下,所涉及的三个代码点依次为当前输入代码点和接下来的两个输入代码点。
注意:此算法不会消耗任何额外的代码点。
查看第一个代码点
- U+002B 加号 (+)
- U+002D 连字符-减号 (-)
- 如果第二个代码点是数字,则返回 true。
否则,如果第二个代码点是 U+002E 句点 (.) 且第三个代码点是数字,则返回 true。
否则,返回 false。
- U+002E 句点 (.)
- 如果第二个代码点是数字,则返回 true。否则,返回 false。
- digit
- 返回 true。
- 其他任何情况
- 返回 false。
4.3.11. 消耗标识符序列
本节描述如何从代码点流中消耗标识符序列。它返回一个字符串,包含从流中第一个代码点开始、由相邻代码点组成的最长名称。
注意:此算法不执行确保返回的代码点构成<ident-token>所需的、对前几个代码点的验证。如果这是预期用途,请确保在调用此算法之前,流启动一个标识符序列。
将result初始化为空字符串。
重复从流中消耗下一个输入代码点
- 标识符码位
- 将该代码点附加到result。
- 该流启动一个有效的转义
- 消耗转义代码点。将返回的代码点附加到result。
- 其他任何情况
- 重新消耗当前输入代码点。返回result。
4.3.12. 消耗数字
本节描述如何从代码点流中消耗数字。它返回一个数值value,以及一个为“integer”(整数)或“number”(数字)的type。
注意:此算法不执行确保从流中可以获得数字所需的、对前几个代码点的验证。在调用此算法之前,请确保流启动一个数字。
按顺序执行以下步骤
- 最初将type设置为“integer”。让repr为空字符串。
- 如果下一个输入代码点是 U+002B 加号 (+) 或 U+002D 连字符 (-),则消耗它并将其附加到repr。
- 当下一个输入代码点是数字时,消耗它并将其附加到repr。
- 如果接下来的 2 个输入代码点是 U+002E 句点 (.) 后跟一个数字,则
- 如果接下来的 2 或 3 个输入代码点是 U+0045 拉丁大写字母 E (E) 或 U+0065 拉丁小写字母 E (e),且可选地后跟 U+002D 连字符 (-) 或 U+002B 加号 (+),再后跟一个数字,则
- 将 repr 转换为数字,并将value设置为返回的值。
- 返回value和type。
4.3.13. 将字符串转换为数字
本节描述如何将字符串转换为数字。它返回一个数字。
注意:此算法不执行任何验证以确保字符串仅包含数字。在调用此算法之前,请确保字符串仅包含有效的 CSS 数字。
将字符串从左到右依次分为七个部分
- 符号(sign):单个 U+002B 加号 (+) 或 U+002D 连字符 (-),或空字符串。如果符号是 U+002D 连字符 (-),则令s为数字 -1;否则,令s为数字 1。
- 整数部分(integer part):零个或多个数字。如果至少有一个数字,则令i为将数字解释为十进制整数所形成的数字;否则,令i为数字 0。
- 小数点(decimal point):单个 U+002E 句点 (.),或空字符串。
- 小数部分(fractional part):零个或多个数字。如果至少有一个数字,则令f为将数字解释为十进制整数所形成的数字,并令d为数字的个数;否则,令f和d为数字 0。
- 指数指示符(exponent indicator):单个 U+0045 拉丁大写字母 E (E) 或 U+0065 拉丁小写字母 E (e),或空字符串。
- 指数符号(exponent sign):单个 U+002B 加号 (+) 或 U+002D 连字符 (-),或空字符串。如果符号是 U+002D 连字符 (-),则令t为数字 -1;否则,令t为数字 1。
- 指数(exponent):零个或多个数字。如果至少有一个数字,则令e为将数字解释为十进制整数所形成的数字;否则,令e为数字 0。
返回数字 s·(i + f·10-d)·10te。
4.3.14. 消耗错误 URL 的剩余部分
本节描述如何从代码点流中消耗错误 URL 的剩余部分,在标记生成器意识到其处于<bad-url-token>中间而非<url-token>时进行“清理”。它不返回任何内容;其唯一用途是消耗足够多的输入流以达到一个可以恢复正常标记生成的恢复点。
重复从流中消耗下一个输入代码点
- U+0029 右括号 ())
- EOF
- 返回。
- 输入流启动一个有效的转义
- 消耗转义代码点。这允许遇到转义的右括号 ("\)") 而不会结束<bad-url-token>。这在其他方面与“其他任何内容”条款相同。
- 其他任何情况
- 不执行任何操作。
5. 解析
解析阶段的输入是来自标记生成阶段的标记流或标记列表。输出取决于解析器的调用方式,如本节后面列出的入口点所定义。解析器输出可由 at-规则、限定规则和/或声明组成。
解析器的输出是根据 CSS 的基本语法构建的,而不考虑任何特定项目的有效性。实现可以在解析器算法返回项目时检查其有效性,如果该项目根据实现的语法知识是无效的,则将算法视为未返回任何内容;或者可以构建指定的完整树,然后通过移除任何无效项目来进行“清理”。
可以在树中出现的项目是
- At-rule
- at-规则具有一个名称、一个由组件值列表组成的前奏(prelude),以及一个由简单 {} 块组成的可选块。
注意:本规范对 at-规则的块可以包含的内容不做限制。各个 at-规则必须定义它们是否接受块,如果接受,如何解析它(最好使用本规范定义的解析器算法或入口点之一)。
- 限定规则
- 限定规则具有一个由组件值列表组成的前奏,以及一个由简单 {} 块组成的块。
- 声明
- 从概念上讲,声明是将属性或描述符名称与值关联的一种特定实例。在语法上,声明具有一个名称、一个由组件值列表组成的值,以及一个最初未设置的 important 标志。
声明进一步归类为属性声明或描述符声明,前者设置 CSS 属性并最常出现在限定规则中,后者设置仅出现在at-规则中的 CSS 描述符。(这种分类不在语法级别发生;相反,它是声明出现位置的产物,由定义给定规则的各自规范定义。)
- 组件值
- 组件值是保留标记、函数或简单块之一。
- 保留标记
- 标记生成器产生的任何标记,除了<function-token>、<{-token>、<(-token>和<[-token>。
注意:上面列出的非保留标记总是被消耗到更高级别的对象(函数或简单块)中,因此它们本身永远不会出现在任何解析器输出中。
注意:<}-token>、<)-token>、<]-token>、<bad-string-token>和<bad-url-token>标记总是解析错误,但本规范将它们保留在标记流中,以允许其他规范(例如媒体查询)定义比仅仅丢弃整个声明或块更细粒度的错误处理。
- function
- 函数具有名称和值,值由组件值列表组成。
- simple block
- {}-块
- []-块
- ()-块
- 简单块具有关联的标记(<[-token>、<(-token>或<{-token>)和由组件值列表组成的值。
5.1. 解析器铁路图
本节是非规范性的。
本节以铁路图的形式提供了解析器的信息性视图。
这些图表是信息性且不完整的;它们描述了“正确”样式表的语法,但根本没有描述错误处理。提供它们仅仅是为了更容易直观地理解语法。
- 样式表
-
- 规则列表
-
- At-规则
-
- 限定规则
-
- 声明列表
-
- 声明
-
- !important
-
- 组件值
-
- {} 块
-
- () 块
-
- [] 块
-
- 函数块
-
5.2. 定义
- 当前输入标记
- 当前正在操作的标记或组件值,来自标记生成器产生的标记列表。
- 下一个输入标记
- 紧跟在当前输入标记之后的标记或组件值,在标记生成器产生的标记列表中。如果当前输入标记后面没有标记,则下一个输入标记为<EOF-token>。
- <EOF-token>
- 表示标记列表结束的概念性标记。只要标记列表为空,下一个输入标记始终为<EOF-token>。
- 消费下一个输入标记
- 令当前输入标记为当前的下一个输入标记,并相应地调整下一个输入标记。
- 重新消费当前输入标记
- 下次算法指示您消耗下一个输入标记时,改为不执行任何操作(保留当前输入标记不变)。
5.3. 解析器入口点
本节中定义的算法从 CSS 标记列表中产生高级 CSS 对象。
要将给定的input归一化为标记流
注意:其他规范可以出于自身目的定义额外的入口点。
- “解析样式表”旨在作为用于解析样式表的常规解析器入口点。
- “解析规则列表”旨在用于@media等 at-规则的内容。它在处理<CDO-token>和<CDC-token>方面与“解析样式表”不同。
- “解析规则”旨在供
CSSStyleSheet#insertRule方法及可能存在的类似函数使用,它们将文本解析为单个规则。 - “解析声明”用于@supports条件。[CSS3-CONDITIONAL]
- “解析声明列表”用于
style属性的内容,它将文本解析为单个样式规则的内容。 - “解析组件值”用于需要消耗单个值的内容,例如attr()的解析规则。
- “解析组件值列表”用于呈现属性的内容,它将文本解析为单个声明的值,或用于解析独立的选择器[SELECT]或媒体查询列表[MEDIAQ],如在选择器 API或
mediaHTML 属性中那样。
5.3.1. 根据 CSS 语法解析某些内容
通常需要解析字符串或标记列表以查看它是否符合某些 CSS 语法,如果符合,则根据语法对其进行解构。本节为这种类型的操作提供了一个通用钩子。它应该像这样调用“将 foo 解析为 CSS <color>”,或类似内容。
如果输入不符合提供的语法,此算法返回失败;或者如果符合,返回根据语法解析输入的结果,这是一个对应于提供的语法规范的未指定结构。返回值只能通过规范文档进行交互,其中表示歧义不成问题。如果它旨在在规范语言之外公开,则使用该结果的规范必须明确将其转换为格式良好的表示,例如,通过调用 CSS 序列化算法(如“序列化为 CSS <string> 值”)。
注意:此算法,以及“根据 CSS 语法解析逗号分隔列表”,通常是其他规范想要调用的仅有的两个解析算法。其余的解析算法主要用于[CSSOM]及相关的“显式构建 CSS 结构”的情况。如果您认为需要使用其他算法之一,请先咨询 CSSWG 获取指导。
5.3.2. 根据 CSS 语法解析逗号分隔列表
虽然一个人肯定可以根据其中带有逗号的语法解析值,但如果值的任何部分解析失败,则整个内容解析失败,并返回失败。
有时这是所期望的(例如在列表值的 CSS 属性中);其他时候,最好让值的每个逗号分隔的子部分分别解析,以一种方式处理成功解析的部分,并以另一种方式处理解析失败的部分(通常忽略它们,例如在 <img sizes> 中)。
此算法提供了一个简单的钩子来实现这一点。它返回由“顶层”逗号分隔的值列表,其中每个值要么是失败(如果解析失败),要么是解析的结果(如“解析”算法中所述的未指定结构)。
- 归一化input,并将input设置为结果。
- 如果input仅包含<whitespace-token>,则返回一个空列表。
- 从input解析组件值列表的逗号分隔列表,并令list为返回值。
- 对于list中的每个item,用使用grammar解析item的结果替换item。
- 返回 list。
5.3.3. 解析样式表
- 如果input是样式表的字节流,则从input中解码字节,并将input设置为结果。
- 归一化input,并将input设置为结果。
- 创建一个新的样式表,将其位置(location)设置为location(如果未传入location,则为 null)。
- 从input消耗规则列表,设置顶层标志(top-level flag),并将样式表的值设置为结果。
- 返回样式表。
5.3.4. 解析规则列表
5.3.5. 解析规则
- 归一化input,并将input设置为结果。
- 当来自input的下一个输入标记是<whitespace-token>时,从input消耗下一个输入标记。
- 如果来自input的下一个输入标记是<EOF-token>,则返回语法错误。
否则,如果来自input的下一个输入标记是<at-keyword-token>,则从input消耗 at-规则,并令rule为返回值。
否则,从input消耗限定规则并令rule为返回值。如果没有返回任何内容,则返回语法错误。
- 当来自input的下一个输入标记是<whitespace-token>时,从input消耗下一个输入标记。
- 如果来自input的下一个输入标记是<EOF-token>,则返回rule。否则,返回语法错误。
5.3.6. 解析声明
注意:与“解析声明列表”不同,此算法仅解析声明,而不解析 at-规则。
- 归一化input,并将input设置为结果。
- 当来自input的下一个输入标记是<whitespace-token>时,消耗下一个输入标记。
- 如果来自input的下一个输入标记不是<ident-token>,则返回语法错误。
- 从input消耗声明。如果返回了任何内容,则将其返回。否则,返回语法错误。
5.3.7. 解析样式块的内容
注意:此算法解析样式规则的内容,样式规则需要允许嵌套样式规则和其他at-规则。如果您不需要嵌套样式规则(例如在@page中或在@keyframes子规则中),请使用“解析声明列表”。
5.3.8. 解析声明列表
注意:尽管名称如此,但这实际上解析了声明和 at-规则的混合列表,正如 CSS 2.1 对@page所做的那样。意外的 at-规则(在给定上下文中可能是所有规则)是无效的,将被消费者忽略。
注意:此算法不处理嵌套的样式规则。如果您的使用需要,请使用“解析样式块的内容”。
5.3.9. 解析组件值
- 归一化input,并将input设置为结果。
- 当来自input的下一个输入标记是<whitespace-token>时,从input消耗下一个输入标记。
- 如果来自input的下一个输入标记是<EOF-token>,则返回语法错误。
- 从input消耗组件值并令value为返回值。
- 当来自input的下一个输入标记是<whitespace-token>时,消耗下一个输入标记。
- 如果来自input的下一个输入标记是<EOF-token>,则返回value。否则,返回语法错误。
5.3.10. 解析组件值列表
- 归一化input,并将input设置为结果。
- 重复从input消耗组件值,直到返回<EOF-token>,并将返回的值(除了最终的<EOF-token>)附加到列表中。返回该列表。
5.3.11. 解析组件值列表的逗号分隔列表
- 归一化input,并将input设置为结果。
- 令list of cvls为初始为空的组件值列表的列表。
- 重复从input消耗组件值,直到返回<EOF-token>或<comma-token>,并将返回的值(除了最终的<EOF-token>或<comma-token>)附加到列表中。将列表附加到list of cvls。
如果返回的是<comma-token>,则重复此步骤。
- 返回list of cvls。
5.4. 解析器算法
以下算法构成了解析器。它们由上面的解析器入口点调用。
这些算法可以使用标记列表或组件值列表进行调用。(区别在于在组件值列表中,一些标记被函数和简单块所取代。)类似于标记生成阶段在为空时返回 EOF 代码点来表示,此阶段中的列表在请求下一个标记但它们为空时必须返回<EOF-token>。
算法可以使用特定列表进行调用,在这种情况下它仅消耗该列表(当该列表耗尽时,它开始返回<EOF-token>)。否则,它会隐式使用与调用算法相同的列表进行调用。
5.4.1. 消耗规则列表
要消耗规则列表,给定一个顶层标志
创建一个初始为空的规则列表。
重复消耗下一个输入标记
- <whitespace-token>
- 不执行任何操作。
- <EOF-token>
- 返回规则列表。
- <CDO-token>
- <CDC-token>
- 如果设置了顶层标志,则不执行任何操作。
否则,重新消耗当前输入标记。消耗限定规则。如果返回了任何内容,则将其附加到规则列表中。
- <at-keyword-token>
- 重新消耗当前输入标记。消耗 at-规则,并将返回的值附加到规则列表中。
- 其他任何情况
- 重新消耗当前输入标记。消耗限定规则。如果返回了任何内容,则将其附加到规则列表中。
5.4.2. 消耗 at-规则
要消耗 at-规则
消耗下一个输入标记。创建一个新的 at-规则,将其名称设置为当前输入标记的值,其前奏最初设置为一个空列表,其值最初设置为无。
重复消耗下一个输入标记
- <semicolon-token>
- 返回 at-规则。
- <EOF-token>
- 这是一个解析错误。返回 at-规则。
- <{-token>
- 消耗简单块并将其分配给 at-规则的块。返回 at-规则。
- 简单块,其关联标记为<{-token>
- 将该块分配给 at-规则的块。返回 at-规则。
- 其他任何情况
- 重新消耗当前输入标记。消耗组件值。将返回的值附加到 at-规则的前奏中。
5.4.3. 消耗限定规则
要消耗限定规则
创建一个新的限定规则,其前奏最初设置为一个空列表,其值最初设置为无。
重复消耗下一个输入标记
- <EOF-token>
- 这是一个解析错误。返回无。
- <{-token>
- 消耗简单块并将其分配给限定规则的块。返回限定规则。
- 简单块,其关联标记为<{-token>
- 将该块分配给限定规则的块。返回限定规则。
- 其他任何情况
- 重新消耗当前输入标记。消耗组件值。将返回的值附加到限定规则的前奏中。
5.4.4. 消耗样式块的内容
要消耗样式块的内容
创建一个初始为空的声明列表 decls,以及一个初始为空的规则列表 rules。
重复消耗下一个输入标记
- <whitespace-token>
- <semicolon-token>
- 不执行任何操作。
- <EOF-token>
- 扩展decls,并包含rules,然后返回decls。
- <at-keyword-token>
- 重新消耗当前输入标记。消耗 at-规则,并将结果附加到rules。
- <ident-token>
- 初始化一个临时列表,最初填充有当前输入标记。只要下一个输入标记是<semicolon-token>或<EOF-token>以外的任何内容,消耗组件值并将其附加到临时列表中。从临时列表消耗声明。如果返回了任何内容,则将其附加到decls。
- <delim-token>,值为 "&" (U+0026 AMPERSAND)
- 重新消耗当前输入标记。消耗限定规则。如果返回了任何内容,则将其附加到rules。
- 其他任何情况
- 这是一个解析错误。重新消耗当前输入标记。只要下一个输入标记是<semicolon-token>或<EOF-token>以外的任何内容,消耗组件值并丢弃返回的值。
5.4.5. 消耗声明列表
要消耗声明列表
创建一个初始为空的声明列表。
重复消耗下一个输入标记
- <whitespace-token>
- <semicolon-token>
- 不执行任何操作。
- <EOF-token>
- 返回声明列表。
- <at-keyword-token>
- 重新消耗当前输入标记。消耗 at-规则。将返回的规则附加到声明列表中。
- <ident-token>
- 初始化一个临时列表,最初填充有当前输入标记。只要下一个输入标记是<semicolon-token>或<EOF-token>以外的任何内容,消耗组件值并将其附加到临时列表中。从临时列表消耗声明。如果返回了任何内容,则将其附加到声明列表中。
- 其他任何情况
- 这是一个解析错误。重新消耗当前输入标记。只要下一个输入标记是<semicolon-token>或<EOF-token>以外的任何内容,消耗组件值并丢弃返回的值。
5.4.6. 消耗声明
注意:此算法假设下一个输入标记已经被检查为<ident-token>。
要消耗声明
消耗下一个输入标记。创建一个新的声明,将其名称设置为当前输入标记的值,其值最初设置为一个空列表。
- 当下一个输入标记是<whitespace-token>时,消耗下一个输入标记。
- 如果下一个输入标记是<colon-token>以外的任何内容,则这是一个解析错误。返回无。
否则,消耗下一个输入标记。
- 当下一个输入标记是<whitespace-token>时,消耗下一个输入标记。
- 只要下一个输入标记是<EOF-token>以外的任何内容,消耗组件值并将其附加到声明的值中。
- 如果声明值中最后两个非<whitespace-token>标记是值为“!”的<delim-token>,后跟值为与“important”的ASCII 不区分大小写匹配的<ident-token>,则从声明的值中移除它们,并将声明的important标志设置为 true。
- 当声明值中的最后一个标记是<whitespace-token>时,移除该标记。
- 返回声明。
5.4.7. 消耗组件值
要消耗组件值
如果当前输入标记是<{-token>、<[-token>或<(-token>,则消耗简单块并返回它。
否则,如果当前输入标记是<function-token>,则消耗函数并返回它。
否则,返回当前输入标记。
5.4.8. 消耗简单块
注意:此算法假设当前输入标记已经被检查为<{-token>、<[-token>或<(-token>。
要消耗简单块
结束标记是当前输入标记的镜像变体。(例如,如果使用<[-token>调用,则结束标记为<]-token>。)
创建一个简单块,将其关联标记设置为当前输入标记,其值最初设置为一个空列表。
重复消耗下一个输入标记并对其进行如下处理
- 结束标记
- 返回该块。
- <EOF-token>
- 这是一个解析错误。返回该块。
- 其他任何情况
- 重新消耗当前输入标记。消耗组件值并将其附加到块的值中。
注意:CSS 在可以包含声明的块和可以包含限定规则的块之间存在不幸的语法歧义,因此任何处理规则的“消耗”算法最初都会使用这种更通用的算法,而不是更具体的“消耗声明列表”或“消耗规则列表”算法。这些更具体的算法是在应用语法时调用的,取决于它包含<declaration-list>还是<rule-list>/<stylesheet>。
5.4.9. 消耗函数
注意:此算法假设当前输入标记已经被检查为<function-token>。
要消耗函数
创建一个函数,其名称等于当前输入标记的值,其值最初设置为一个空列表。
重复消耗下一个输入标记并对其进行如下处理
- <)-token>
- 返回该函数。
- <EOF-token>
- 这是一个解析错误。返回该函数。
- 其他任何情况
- 重新消耗当前输入标记。消耗组件值并将返回的值附加到函数的值中。
6. An+B 微语法
CSS 中的许多事物,例如:nth-child()伪类,需要指示列表中的索引。An+B微语法对此很有用,允许作者轻松指示单个元素或列表中规则间隔的所有元素。
An+B符号定义了一个整数步长(A)和偏移量(B),并表示列表中每隔n个元素(对于n的每个非负整数值),其中列表中的第一个元素索引为 1(而非 0)。
对于大于 0 的A和B值,这有效地将列表分为每组A个元素(最后一组取余数),并选择每组的第B个元素。
An+B符号也接受even和odd关键字,它们分别与2n和2n+1具有相同的含义。
示例
2n+0 /* represents all of the even elements in the list */ even /* same */ 4n+1 /* represents the 1st, 5th, 9th, 13th, etc. elements in the list */
A和B的值可以是负数,但仅使用An+B对于n ≥ 0 的正结果。
示例
-1n+6 /* represents the first 6 elements of the list */ -4n+10 /* represents the 2nd, 6th, and 10th elements of the list */
如果A和B均为 0,则伪类表示列表中没有元素。
6.1. 非正式语法描述
本节是非规范性的。
当A为 0 时,可以省略An部分(除非已经省略了B部分)。当未包含An且B为非负数时,B之前的+符号(如果允许)也可以省略。在这种情况下,语法简化为仅B。
当A为 1 或 -1 时,可以从规则中省略 1。
如果B为 0,则选择每第A个元素。在这种情况下,可以省略+B(或-B)部分,除非已经省略了A部分。
当 B 为负数时,其减号替换+符号。
当An和B部分都存在时,允许在分隔它们的分隔符+或-两侧使用空白。
6.2. <an+b> 类型
An+B符号最初是使用与 CSS 其余部分略有不同的标记生成器定义的,导致在以 CSS 标记表示时定义有些奇怪。本节描述如何识别 CSS 标记方面的An+B符号(从而定义用于 CSS 语法目的的<an+b>类型),以及如何解释 CSS 标记以获得A和B的值。
<an+b>类型定义为(使用值与单位规范中的值定义语法)
<an+b> = odd | even | <integer> | <n-dimension> | '+'?† n | -n | <ndashdigit-dimension> | '+'?† <ndashdigit-ident> | <dashndashdigit-ident> | <n-dimension> <signed-integer> | '+'?† n <signed-integer> | -n <signed-integer> | <ndash-dimension> <signless-integer> | '+'?† n- <signless-integer> | -n- <signless-integer> | <n-dimension> ['+' | '-'] <signless-integer> '+'?† n ['+' | '-'] <signless-integer> | -n ['+' | '-'] <signless-integer>
其中
<n-dimension>是一个类型标志设置为“integer”的<dimension-token>,其单位是与“n”的ASCII 不区分大小写匹配。<ndash-dimension>是一个类型标志设置为“integer”的<dimension-token>,其单位是与“n-”的ASCII 不区分大小写匹配。<ndashdigit-dimension>是一个类型标志设置为“integer”的<dimension-token>,其单位是与“n-*”的ASCII 不区分大小写匹配,其中“*”是一个或多个数字序列<ndashdigit-ident>是一个<ident-token>,其值是与“n-*”的ASCII 不区分大小写匹配,其中“*”是一个或多个数字序列<dashndashdigit-ident>是一个 <ident-token>,其值在 ASCII 大小写不敏感匹配下与 "-n-*" 一致,其中 "*" 为一个或多个 数字 (digits)。<integer>是一个类型标志设置为 "integer" 的 <number-token>。<signed-integer>是一个类型标志设置为 "integer" 且 表示 (representation) 以 "+" 或 "-" 开头的 <number-token>。<signless-integer>是一个类型标志设置为 "integer" 且 表示 (representation) 以 数字 开头的 <number-token>。
†:当加号 (+) 位于以 "n" 开头的标识符之前时(如上述标记的情况),这两个标记之间不得有空格,否则它们将不符合上述语法。在任何其他两个标记之间,空格是有效的(且会被忽略)。
产生式的子句解释如下:
- odd
- A 为 2,B 为 1。
- even
- A 为 2,B 为 0。
<integer>(整数)- A 为 0,B 为该整数的值。
<n-dimension>'+'? n-n- A 分别为该维度的值、1 或 -1。B 为 0。
<ndashdigit-dimension>'+'? <ndashdigit-ident>- A 分别为该维度的值或 1。B 分别为该维度的单位或标识符的值,且移除第一个 码点 (code point),其余部分按十进制数字解释。B 为负数。
<dashndashdigit-ident>- A 为 -1。B 为该标识符的值,移除前两个 码点,其余部分按十进制数字解释。B 为负数。
<n-dimension> <signed-integer>'+'? n <signed-integer>-n <signed-integer>- A 分别为该维度的值、1 或 -1。B 为该整数的值。
<ndash-dimension> <signless-integer>'+'? n- <signless-integer>-n- <signless-integer>- A 分别为该维度的值、1 或 -1。B 为该整数值的负数。
<n-dimension> ['+' | '-'] <signless-integer>'+'? n ['+' | '-'] <signless-integer>-n ['+' | '-'] <signless-integer>- A 分别为该维度的值、1 或 -1。B 为该整数的值。如果在两者之间提供了
'-',则 B 为该整数值的负数。
7. Unicode 范围微语法 (The Unicode-Range microsyntax)
某些结构(例如 @font-face 规则的 unicode-range 描述符)需要一种方式来描述一个或多个 Unicode 码点。<urange> 产生式表示一个或多个 Unicode 码点的范围。
非正式地,<urange> 产生式有三种形式:
- U+0001
- 定义由单个码点组成的范围,本例中即码点 "1"。
- U+0001-00ff
- 定义包含第一个和第二个值在内的所有码点范围,本例中为 "1" 到 "ff"(十进制 255)之间的范围。
- U+00??
- 定义码点范围,其中 "?" 字符涵盖所有 十六进制数字,本例定义的范围与值 U+0000-00ff 相同。
在每种形式中,每个十六进制数最多允许 6 位数字(如果你将 "?" 视为十六进制数字)。
7.1. <urange> 类型
<urange> 记法最初定义为 CSS 中的原始标记,但它很少被使用,且常会与合法的 <ident-token> 发生混淆冲突。本节介绍了如何根据现有的 CSS 标记识别 <urange> 记法,以及如何将其解释为 Unicode 码点范围。
什么是混淆冲突?
例如,在 CSS u + a { color: green; } 中,其含义是跟随在 u 元素之后的 a 元素应当显示为绿色。通常组合符与周围的选择器之间不需要空格,因此压缩后它应该等价于
对于任何其他组合符,这两段 CSS 将是等价的,但由于先前存在特殊的 unicode-range 标记,压缩代码的选择器部分现在包含了一个 unicode-range,而不是两个标识符和一个组合符。因此,它无法匹配选择器语法,规则会被丢弃并标记为无效。
(此示例摘自向 Firefox 报告的真实错误。)
注:此处描述的语法故意设计得非常底层,面向实现者。作者应当阅读前一节的非正式语法描述,因为它包含了使用 <urange> 所需的所有信息,并且实际上是可读的。
<urange> 类型定义(使用 Values & Units 规范中的值定义语法)为:
<urange> = u '+' <ident-token> '?'* | u <dimension-token> '?'* | u <number-token> '?'* | u <number-token> <dimension-token> | u <number-token> <number-token> | u '+' '?'+
在此产生式中,任何标记之间不得有空格。
<urange> 产生式将一个或多个连续的 Unicode 码点范围表示为起始值和结束值,它们均为非负整数。若要将上述产生式解释为范围,请按顺序执行以下步骤:
-
跳过第一个 u 标记,将产生式中所有标记的表示 (representations) 拼接在一起。设此为 text。
-
如果 text 的第一个字符是 U+002B 加号 (+),则消费它。否则,这是一个无效的 <urange>,必须退出此算法。
-
从 text 中尽可能多地消费 十六进制数字,然后尽可能多地消费 U+003F 问号 (?) 码点。如果消费了零个或超过六个 码点,则这是一个无效的 <urange>,必须退出此算法。
如果消费了任何 U+003F 问号 (?) 码点,那么:
-
将消费的 码点解释为十六进制数,并将 U+003F 问号 (?) 码点替换为 U+0030 数字 0 (0) 码点。这就是起始值。
-
再次将消费的 码点解释为十六进制数,并将 U+003F 问号 (?) 码点替换为 U+0046 拉丁大写字母 F (F) 码点。这就是结束值。
-
退出此算法。
否则,将消费的 码点解释为十六进制数。这就是起始值。
-
如果 text 中没有剩余的 码点,则结束值与起始值相同。退出此算法。
-
如果 text 中的下一个 码点是 U+002D 连字符减号 (-),则消费它。否则,这是一个无效的 <urange>,必须退出此算法。
-
从 text 中尽可能多地消费 十六进制数字。
如果消费了零个或超过 6 个 十六进制数字,则这是一个无效的 <urange>,必须退出此算法。如果 text 中有任何剩余的 码点,则这是一个无效的 <urange>,必须退出此算法。
-
将消费的 码点解释为十六进制数。这就是结束值。
要确定 <urange> 表示哪些码点:
注:<urange> 的语法故意设计得相当宽松;其模式捕获了非正式语法可以生成的每一个可能的标记序列。然而,它要求其组成标记之间不得有空格,这使得它在实际使用中相当安全。即使是那些包含 <urange> 后跟 <number> 或 <dimension> 的语法(如果作者指定了带有 ''u <number>'' 子句的 <urange>,看起来可能存在歧义),实际上也是相当安全的,因为作者必须故意使用注释而不是空格将 <urange> 与 <number>/<dimension> 分隔开才会产生歧义。因此,尽管作者有可能写出会被以混淆方式解析的代码,但导致这种混淆所必须编写的代码本身就是混乱且罕见的。
8. 定义规则和其他值的语法
Values 规范定义了如何为属性指定语法。本节执行相同操作,但针对的是规则。
就像在属性语法中一样,记法 <foo> 指的是 "foo" 语法项,假定其定义在别处。用 <foo> 的定义替换它会得到一个语义上相同的语法。
几种类型的标记是按字面编写的,不需要引号:
- <ident-token>(如
auto,disc等),直接写出它们的值。 - <at-keyword-token>,写为 @ 字符后跟标记的值,如
@media。 - <function-token>,写为函数名后跟 ( 字符,如
translate(。 - <colon-token> (写为
:), <comma-token> (写为,), <semicolon-token> (写为;), <(-token>, <)-token>, <{-token>, 以及 <}-token>。
如果标记的值匹配语法中定义的值,则匹配成功。除非另有说明,所有匹配均为 ASCII 大小写不敏感的。
注:虽然通过 转义 (escaping) 可以构建一个值以 ( 结尾或以 @ 开头的 <ident-token>,但这样的标记不是 <function-token> 或 <at-keyword-token>,且不匹配对应的语法定义。
<delim-token> 的值需用单引号括起来。例如,包含 "+" 码点的 <delim-token> 写为 '+'。同样,<[-token> 和 <]-token> 必须用单引号括起来,因为它们被语法本身用来对子句进行分组。<whitespace-token> 在语法中永远不会被指出;<whitespace-token> 允许在任何两个标记之前、之后和之间出现,除非正文定义中明确指定否则。(例如,如果规则的前导部分是选择器,则空格是有意义的。)
在定义函数或块时,必须在语法中指定结束标记,但如果最终标记流中没有出现它,它仍然匹配。
translateX( <translation-value> )
然而,样式表可能会以未闭合的函数结束,如:
.foo { transform: translate(50px
CSS 解析器将其解析为一个包含一条声明的样式规则,其值是一个名为 "translate" 的函数。这匹配上述语法,即使结束标记没有出现在标记流中,因为当解析器完成时,已经无法确定结束标记是否存在;你所拥有的事实仅仅是存在一个块和一个函数。
8.1. 定义块内容:<declaration-list>、<rule-list> 和 <stylesheet> 产生式
CSS 解析器对于块的内容(例如在某些 @规则末尾出现的块)是不可知的。根据标记定义块的通用语法并非易事,但已有专门且明确的解析算法定义。
<style-block> 产生式表示样式规则块的内容。它只能在语法中作为块中的唯一值使用,表示块的内容必须使用消费样式块内容 (consume a style block’s contents) 算法进行解析。
<declaration-list> 产生式表示声明列表。它只能在语法中作为块中的唯一值使用,表示块的内容必须使用消费声明列表 (consume a list of declarations) 算法进行解析。
同样,<rule-list> 产生式表示规则列表,也只能在语法中作为块中的唯一值使用。它表示块的内容必须使用消费规则列表 (consume a list of rules) 算法进行解析。
最后,<stylesheet> 产生式表示规则列表。它与 <rule-list> 相同,不同之处在于使用它的块默认接受所有未被限定在特定上下文中的规则。
| 允许 声明 (declarations) | 允许 嵌套样式规则 | 允许任意 限定规则 (qualified rules) | 允许 @规则 (at-rules) | 示例 | |
|---|---|---|---|---|---|
| <style-block> | ✓ | ✓ | ✗ | ✓ | 样式规则, @nest, 嵌套条件组规则 |
| <declaration-list> | ✓ | ✗ | ✗ | ✓ | @font, @counter-style, @page, @keyframes 子规则 |
| <rule-list> | ✗ | ✗ | ✓ | ✓ | @keyframes, @font-feature-values |
| <stylesheet> | ✗ | ✗ | ✓ | ✓ | 样式表,非嵌套 条件组规则 |
如果给定的上下文仅打算接受 @规则(例如在 @font-features-values 中),实际上使用哪种产生式并不重要,但由于名称更直观,通常更推荐使用 <rule-list>。
@font-face { <declaration-list> }
这是该规则语法的完整且充分的定义。
作为另一个例子,@keyframes 规则更为复杂,将它们的前导部分解释为名称,并在其块中包含关键帧规则。它们的语法是:
@keyframes <keyframes-name> { <rule-list> }
对于使用 <style-block> 或 <declaration-list> 的规则,规则规范必须定义在规则内部哪些属性、描述符和/或 @规则是有效的;这可能简单到表述为 "该 @foo 规则接受本规范/章节中定义的属性/描述符",扩展规范可以简单地表述为 "该 @foo 规则额外接受以下属性/描述符"。块内发现的任何未定义为有效的声明或 @规则都必须从规则的值中移除。
在 <style-block> 或 <declaration-list> 内,!important 在任何描述符上自动无效。如果规则接受属性,规则规范必须定义这些属性是否与层叠(cascade)交互,以及具有何种特指度(specificity)。如果它们不与层叠交互,包含 !important 的属性自动无效;否则,使用 !important 是有效的,并使该声明在层叠目的下成为重要声明 (important)。参见 [CSS-CASCADE-3]。
对于使用 <rule-list> 的规则,规则规范必须定义在规则内部哪些类型的规则是有效的(同 <declaration-list>),未识别的规则必须同样从规则的值中移除。
<keyframe-rule> = <keyframe-selector> { <declaration-list> }
关键帧规则随后必须进一步定义,它们作为声明接受所有可动画化的 CSS 属性,以及 animation-timing-function 属性,但它们不与层叠交互。
对于使用 <stylesheet> 的规则,默认允许所有规则,但规则规范可以定义在该规则内部哪些类型的规则无效。
@media <media-query-list> { <stylesheet> }
它还额外定义了一个限制,即 <stylesheet> 不包含 @media 规则,这导致如果出现这些规则,它们会从外部规则的值中丢弃。
8.2. 定义任意内容:<declaration-value> 和 <any-value> 产生式
在某些语法中,接受任何合理的输入并手动对内容进行更具体的错误处理(而不是像语法不匹配通常做的那样简单地使构造失效)是非常有用的。
例如,自定义属性 (custom properties) 允许任何合理的值,因为它们可以包含其他 CSS 属性的任意片段,或者用于根本不是 CSS 一部分的内容。另一个例子是媒体查询中的 <general-enclosed> 产生式,它定义了未来媒体查询将允许的边界,并使用特殊逻辑处理 "未知" 值。
为了辅助这一点,定义了两个额外的产生式:
The <declaration-value> 产生式匹配任意一个或多个标记的序列,只要该序列不包含 <bad-string-token>、<bad-url-token>、不匹配的 <)-token>、<]-token> 或 <}-token>,或者顶层的 <semicolon-token> 标记,或是值为 "!" 的 <delim-token> 标记。它表示合法声明作为其值可以具有的全部内容。
<any-value> 产生式与 <declaration-value> 相同,但也允许顶层的 <semicolon-token> 标记和值为 "!" 的 <delim-token> 标记。它表示在任何上下文中合法 CSS 可以包含的全部内容。
9. CSS 样式表 (CSS stylesheets)
若要 解析 CSS 样式表 (parse a CSS stylesheet),首先执行 解析样式表。将所有产生的顶层 限定规则 解释为下文定义的 样式规则 (style rules)。
如果任何样式规则是 无效的,或者任何 @规则未被识别,或者根据其语法或上下文无效,则视为 解析错误。丢弃该规则。
9.1. 样式规则 (Style rules)
样式规则 (style rule) 是一个 限定规则,它将 选择器列表 与属性声明列表(可能还有嵌套规则列表)相关联。在 [CSS2] 中,它们也被称为 规则集 (rule sets)。CSS 层叠与继承 [CSS-CASCADE-3] 定义了样式规则内的声明如何参与层叠。
该限定规则的前导部分被 解析 为 <selector-list>。如果解析失败,整个样式规则即为 无效的。
限定规则块的内容被解析为 样式块内容。除非另有其他规范或本规范的未来版本定义,否则列表中的 @规则均为 无效的,且必须被忽略。
注:[CSS-NESTING-1] 定义了 @nest 和 条件组规则 在 样式规则 内是允许的。
对于未知 CSS 属性的声明,或者其值不匹配属性所定义语法的声明,均为 无效的,且必须被忽略。样式规则内容的有效性对样式规则本身的有效性没有影响。除非另有规定,属性名均为 ASCII 大小写不敏感。
注:自定义属性 [CSS-VARIABLES] 的名称是区分大小写的。
位于 CSS 样式表顶层的 限定规则 均为 样式规则。其他上下文中的限定规则可能是也可能不是样式规则,由具体上下文定义。
例如,@media 规则 [CSS3-CONDITIONAL] 内部的限定规则是样式规则,但 @keyframes 规则 [CSS3-ANIMATIONS] 内部的限定规则则不是。
9.2. @规则 (At-rules)
@规则 (at-rule) 是以 @ 关键字开始的规则,因此在同一上下文中可以与 样式规则 进行区分。
@规则 用于:
-
对样式规则和其他 @规则进行分组和结构化,例如条件组规则;
-
声明不与特定元素关联的样式信息,例如定义 计数器样式 (counter styles);
-
管理语法结构,例如 导入 (imports) 和 命名空间 (namespaces) 关键字映射;
-
以及服务于 样式规则 未提供的其他各种目的。
@规则有多种形式,取决于特定的规则及其目的,但大致上分为两类:以分号结尾的简单结构 语句 @规则 (statement at-rules),以及以 {}-块 结尾并可包含嵌套的 限定规则、@规则 或 声明 的 块 @规则 (block at-rules)。
块 @规则 通常包含一组(通用或 @规则专用的)@规则、限定规则 和/或受 @规则定义的限制的 描述符声明 (descriptor declarations)。描述符 (Descriptors) 类似于 属性 (properties)(并以相同的语法声明),但与特定类型的 @规则 关联,而不是与树中的元素和框关联。
9.3. @charset 规则
用于 确定样式表回退编码 的算法会在文件最开始的几个字节中查找特定的字节序列,该序列具有命名为 "@charset" 的 @规则 的句法形式。
然而,实际上并没有名为 @charset 的 @规则。当真正解析样式表时,任何 @charset 规则的出现都必须被视为未识别的规则,从而在样式表进行语法检查时作为无效项被丢弃。
注:在 CSS 2.1 中,@charset 是一条有效的规则。一些遗留规范可能仍会引用 @charset 规则,并明确讨论其在样式表中的存在。
10. 序列化 (Serialization)
本规范中描述的记号解析器 (tokenizer) 不会为注释产生标记,也不会以任何方式保留它们。实现可能会保留注释的内容及其在标记流中的位置。如果这样做,这些保留的信息不得对解析步骤产生影响。
本规范不定义如何序列化 CSS,而是将该任务留给 [CSSOM] 和各个特性规范。特别是,注释和空格的序列化未被定义。
序列化的唯一要求是它必须能够与解析进行 "往返" (round-trip),即解析样式表必须产生与解析、序列化后再解析相同的数据结构,连续的 <whitespace-token> 除外,它们可以被折叠成单个标记。
注:之所以可以存在此例外,是因为 CSS 语法总是将任意数量的空格解释为等同于单个空格。
- 包含 U+005C 反斜杠 (\) 的 <delim-token> 必须序列化为 U+005C 反斜杠后跟一个 换行符。(记号解析器只会发射此类标记,后面紧跟一个以换行符开头的 <whitespace-token>。)
- 带有 "unrestricted" 类型标志的 <hash-token> 可能不需要像带有 "id" 类型标志的相同标记那样多的转义。
- <dimension-token> 的单位可能需要转义,以消除与科学记数法的歧义。
- 对于任何连续的标记对,如果第一个标记出现在下表的行标题中,且第二个标记出现在列标题中,并且选定行和列的交汇单元格中有 ✗,则该标记对必须在序列化时在中间插入一个注释。
如果记号解析器保留注释,则应使用保留的注释;否则,必须插入一个空注释 (
/**/)。(即使后续表格不需要在两个标记之间插入注释,也可能重新插入保留的注释。)行和列标题中的单个字符表示具有该值的 <delim-token>,但 "
(" 除外,它表示 (-token。
| ident | function | url | 错误 URL (bad url) | - | number | 百分比 | dimension | CDC | ( | * | % | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ident | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ||
| At-关键字 | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | |||
| hash (哈希) | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | |||
| dimension | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | |||
| # | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | |||
| - | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | |||
| number | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | |||
| @ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ||||||
| . | ✗ | ✗ | ✗ | |||||||||
| + | ✗ | ✗ | ✗ | |||||||||
| / | ✗ |
10.1. 序列化 <an+b>
-
如果 A 为零,返回 B 的序列化结果。
-
否则,令 result 最初为空 字符串。
-
- A 为
1: -
向 result 追加 "n"。
- A 为
-1: -
向 result 追加 "-n"。
- A 为非零:
-
序列化 A 并将其追加到 result,然后向 result 追加 "n"。
- A 为
-
- B 大于零:
-
向 result 追加 "+",然后追加 B 的序列化结果。
- B 小于零:
-
向 result 追加 B 的序列化结果。
-
返回 result。
11. 隐私与安全考量 (Privacy and Security Considerations)
本规范不引入任何新的隐私问题。
本规范提高了安全性,因为 CSS 解析现在对于所有输入都有明确的定义。
就白名单/过滤器等旧解析器的解析方式与本规范不同而言,它们在某种程度上是不安全的,但先前的解析规范遗留了许多浏览器解释不同的歧义边缘情况,因此这些过滤器本身可能已经是潜在不安全的,且本规范并未恶化这一状况。
12. 变更 (Changes)
本节是非规范性的。
12.1. 2019 年 8 月 16 日候选推荐标准以来的变更
作出了以下实质性变更:
-
添加了一个新的 § 5.3.2 按照 CSS 语法解析逗号分隔列表 (Parse A Comma-Separated List According To A CSS Grammar) 算法。
-
添加了一个新的 § 5.3.7 解析样式块内容 (Parse a style block’s contents) 算法和相应的 <style-block> 产生式,并定义了 样式规则 使用它。
-
将 解析样式表 与 Fetch 相关的变动保持一致。(参见 commit。)
要从 input 在给定可选的 url location 的情况下 解析样式表:
- ...
- 创建一个新的样式表 ,将其 位置 (location) 设置为 location(如果未传入 location,则为 null)。
- ...
作出了以下编辑性变更:
-
添加了 § 9.2 @规则 (At-rules),为 @规则、语句 @规则、块 @规则 和 描述符 (descriptors) 提供了定义。(5633)
-
改进了 声明 (declaration) 的定义文本,并添加了 属性声明 和 描述符声明 的定义。
-
统一使用 ident 序列 (ident sequence),而不是有时使用术语 "name"。
-
明确命名了几个预记号解析过程,并在解析入口点中明确引用了它们(而不是依赖于 "在这些算法开始时执行 X" 的笼统表述)。
-
向 "在它们之间放置注释" 表中添加了更多条目,以正确处理 idents 现在可以以
--开头这一事实。(6874)
12.2. 2014 年 2 月 20 日候选推荐标准以来的变更
作出了以下实质性变更:
-
移除了 <unicode-range-token>,转而创建了一个 <urange> 产生式。
-
包含字符串的 url() 函数现在被解析为普通的 <function-token>。包含 "raw" URL 的 url() 函数仍被专门解析为 <url-token>。
-
修复了 "消费 URL 标记" 算法中的一个错误,该算法在尝试消费字符串之前没有消费开始字符串的引号字符。
-
修复了几个与当前/下一个输入标记以及过早/过晚消费相关的解析器算法中的错误。
-
修复了记号解析和解析算法中的几个错误。
-
更改 ident 类标记的定义,允许 "--" 开头。作为此更改的一部分,重排 消费标记 (consume a token) 的 "-" 步骤中的子句顺序,以便 <CDC-token> 被识别为 CDC 标记,而不是变成 -- <ident-token>。
-
当 A 为 1 或 -1 时,不序列化 <an+b> 中的数字。
-
定义所有标记都具有 表示 (representation)。
-
修复了 检查两个码点是否为有效转义 中的小错误——后跟 EOF 的
\现在正确报告为不是有效转义。样式表中的最后一个\现在只是作为 <delim-token> 发射自身。 -
@charset 不再是有效的 CSS 规则(只存在一个看起来像名为 @charset 的规则的编码声明)。
-
解析期间修剪了声明值开头/结尾的空格。
-
根据 WG 决议,移除了选择器特定的标记。
-
根据 WG 决议,从输入流中过滤了 代理 (surrogates)。现在整个规范仅在 标量值 (scalar values) 上操作。
作出了以下编辑性变更:
-
"消费字符串标记" 算法已更改,允许在不指定显式结束标记的情况下调用它,以便它改用当前的输入标记。该算法的三个调用点已更改为使用该形式。
-
对算法进行了微小的编辑性重构。
-
添加了 解析 和 解析逗号分隔的组件值列表 API 入口点。
-
添加了 <declaration-value> 和 <any-value> 产生式。
-
移除了 "code point" 和 "surrogate code point",改用 Infra 标准中的相同定义。
-
明确了每个范围都是包含性的。
-
向注释插入表中添加了一列,以处理紧邻 "%" 分隔标记出现的数字标记。
提供了一个注释处置 (Disposition of Comments) 说明。
12.3. 2013 年 11 月 5 日最后征求意见工作草案以来的变更
- 序列化章节已重写,仅使 "往返" 要求成为规范性的,并将如何实现它的细节移至注中。这些细节中的一些边缘情况已修复。
- [ENCODING] 已添加到规范引用列表中。它之前已经在规范性文本中被引用,只是未列出为规范性引用。
- 在确定样式表 回退编码 的算法中,将
@charset字节序列限制为 1024 字节。这与 HTML 对<meta charset>的处理方式一致,并确保序列的大小是有界的。这仅在编码标签中有前导或尾随空格时才会产生影响。@charset " (lots of whitespace) utf-8";
12.4. 2013 年 9 月 19 日工作草案以来的变更
- 添加了 环境编码 (environment encoding) 的概念。行为没有改变,但一些定义应当移至相关规范中。
12.5. CSS 2.1 和选择器 Level 3 以来的变更
注:本规范的意义在于匹配现实;与 CSS 2.1 的变更几乎总是因为 CSS 2.1 指定的内容与实际浏览器行为不符,或者留下了某些未定义的内容。如果某些细节与浏览器不符,请告知我,因为这几乎肯定是非故意的。
从字节流解码的变更:
- 仅在 ASCII 兼容的字节模式中检测 @charset 规则。
- 忽略指定非 ASCII 兼容编码的 @charset 规则,因为那会导致规则本身无法正确解码。
- 引用 [ENCODING] 而不是 IANA 字符编码注册表。
记号解析变更:
- CSS 源代码中的任何 U+0000 空 码点 都会替换为 U+FFFD 替换字符。
- 任何计算为零的十六进制转义序列(如 \0)产生 U+FFFD 替换字符,而不是 U+0000 空。
- 非 ASCII 码点 的定义已更改为与所有 ASCII 定义保持一致。这影响了码点 U+0080 到 U+009F,它们现在是 ident 码点,而不是像其他 非 ASCII 码点 那样是 <delim-token>。
- 记号解析不再发射 COMMENT 或 BAD_COMMENT 标记。BAD_COMMENT 现在被视为与普通标记相同(不是错误)。序列化负责根据需要在需要分隔的标记之间插入注释,例如两个连续的 <ident-token>。
- <unicode-range-token> 被移除,因为它价值较低且偶尔具有破坏性。(例如,u+a { font-weight: bold; } 是一个无效的选择器……)
相反,添加了基于标记模式的 <urange> 产生式。从技术上讲,它比 2.1 允许的(任意数量的数字和 ? 字符)更宽松,但这不应影响其实际使用。
- 在记号解析器中应用 EOF 错误处理规则,并在 EOF 时发射正常的 <string-token> 和 <url-token>,而不是 BAD_STRING 或 BAD_URI。
- BAD_URI 标记(现在是 <bad-url-token>)是 "自包含" 的。换句话说,一旦记号解析器意识到它处于 <bad-url-token> 而不是 <url-token> 中,它就只会向前寻找闭合的 ),而忽略其他所有内容。这种行为比将其视为 <function-token> 并关注已打开的块等要简单。只有 WebKit 表现出这种行为,但看起来我们没有收到任何因此产生的兼容性错误。
- 添加了 <comma-token>。
- <number-token>, <percentage-token> 和 <dimension-token> 已更改为包含前面的 +/- 符号作为其值的一部分(而不是作为每次在其他规范中提到该标记时都需要手动处理的单独 <delim-token>)。唯一的后果是无法再在符号和数字之间插入注释。
- 支持数字/百分比/维度的科学记数法以匹配 SVG,根据 WG 决议。
- 十六进制转义的 代理 (surrogate) 现在发射一个替换字符而不是代理本身。这允许实现在内部安全地使用 UTF-16。
解析变更:
- 任何声明列表现在也接受 @规则,如 @page,根据 WG 决议。即使尚未定义此类 @规则,这在错误处理方面也有所不同:@规则(无论是否有效)在 {} 块处结束,且没有 <semicolon-token>,允许下一个声明开始。
- 指定了在语法中各种位置出现的某些杂项 "特殊" 标记(如不匹配的 <}-token>)的合理处理行为(至少在一个浏览器中有所体现)。此前,在这些位置带有这些标记的样式表完全不匹配样式表语法,因此其处理方式完全未定义。具体如下:
- [] 块、() 块和函数现在可以包含 {} 块、<at-keyword-token> 或 <semicolon-token>。
- 限定规则前导部分现在可以包含分号。
- 限定规则和 @规则前导部分现在可以包含 <at-keyword-token>。
An+B 自选择器 Level 3 [SELECT] 变更:
- An+B 微语法现在已根据 CSS 标记正式定义,而不是使用单独的记号解析器。这导致了微小的差异:
- 在某些情况下,减号或数字可以被转义(当它们作为 <dimension-token> 或 <ident-token> 的单位的一部分出现时)。
致谢
感谢 Anne van Kesteren, David Baron, Elika J. Etemad (fantasai), Henri Sivonen, Johannes Koch, 呂康豪 (Kang-Hao Lu), Marc O’Morain, Raffaello Giulietti, Simon Pieter, Tyler Karaszewski 和 Zack Weinberg 的反馈与贡献。