1. 简介
每个 CSS 属性的值定义字段可以包含关键字、数据类型(出现在 < 和 > 之间)以及关于它们如何组合的信息。本规范描述了许多属性可以使用的通用数据类型(<length> 是使用最广泛的),而更具体的数据类型(例如 <spacing-limit>)则在相应的模块中描述。
1.1. 模块交互
本模块替换并扩展了 [CSS2] 第 1.4.2.1、4.3 和 A.2 节中的数据类型定义。
2. 值定义语法
此处描述的 值定义语法 用于定义 CSS 属性的有效值集合(以及 CSS 中许多其他部分的有效语法)。以此方式描述的值可以包含一个或多个组件。
2.1. 组件值类型
组件值类型通过多种方式指定:
-
基本数据类型,出现在 < 和 > 之间(例如 <length>、<percentage> 等)。对于 数值数据类型,此类型表示法可以使用下述 括号范围表示法 注释任何范围限制。
-
属性值范围,代表与同名属性相同的属性值模式。它们写为属性名称,用单引号括起来,并放在 < 和 > 之间,例如 <'border-width'>、<'background-attachment'> 等。
这些类型不包含 CSS 全局关键字(例如 inherit)。此外,如果属性的值语法是 逗号分隔的重复,则相应的类型不包含顶层的 逗号分隔列表乘数。(例如,如果名为 pairing 的属性定义为 [ <custom-ident> <integer>? ]#,则 <'pairing'> 等同于 [ <custom-ident> <integer>? ],而不是 [ <custom-ident> <integer>? ]#。)
为什么要移除乘数?
从这些值类型中剔除顶层乘数是因为顶层逗号分隔的重复主要用于 协调列表属性。当简写属性组合多个此类属性时,需要未乘数的语法来构造其自身的逗号分隔重复。
如果没有这种特殊处理,每个此类详写属性都必须用专为内部值定义的临时产生式来定义,这会使整体语法更难理解。
-
函数式符号及其参数。它们写为函数名称,后跟一对空圆括号,并置于 < 和 > 之间,例如 <calc()>,引用对应名称的 函数式符号。
-
其他非终结符。它们写为非终结符的名称,置于 < 和 > 之间,如 <spacing-limit>。注意 <border-width> 和 <'border-width'> 之间的区别:前者代表 border-width 属性的语法,后者需要在其他地方进行显式扩展。非终结符的定义通常位于其在规范中首次出现的位置附近。
一些属性值定义还将斜杠(/)、逗号(,)和/或括号作为字面量包含在内。它们代表相应的标记。其他可能出现在组件值中的非关键字字面字符(如“+”)必须写在单引号内。
语法中指定的逗号 在某些情况下可以隐式省略,即当用于分隔语法中的可选项时。在属性或其他 CSS 值中的顶级列表内,或函数的参数列表中,如果满足以下条件,则必须省略语法中指定的逗号:
- 逗号之前的所有项均已被省略
- 逗号之后的所有项均已被省略
- 由于逗号之间的项被省略,导致多个逗号相邻(忽略 空白符/注释)。
example ( first?, second?, third?)
根据此语法,编写 example(first, second, third) 是有效的,example(first, second)、example(first, third) 或 example(second) 也是如此。然而,example(first, , third) 是无效的,因为其中一个逗号不再分隔两个选项;同样地,example(,second) 和 example(first,) 也是无效的。example(first second) 也是无效的,因为实际上仍需要逗号来分隔选项。
如果逗号不能隐式省略,那么语法将不得不变得复杂得多,以正确表达参数被省略的各种方式,从而大大掩盖该功能的简洁性。
所有 CSS 属性也都接受 CSS 全局关键字值 作为其属性值的唯一组件。为了可读性,这些关键字未在属性值语法定义中明确列出。例如,根据 CSS Cascading and Inheritance Level 3,border-color 的完整值定义是 <color>(尽管它被列为 <color>)。
注意: 这意味着,通常情况下,将这些关键字与同一声明中的其他组件值组合会导致声明无效。例如,background: url(corner.png) no-repeat, inherit; 是无效的。
2.2. 组件值组合符
组件值可以按如下方式排列到属性值中:
- 并列组件意味着它们必须全部出现,且按给定的顺序。
- 双与号(&&)分隔两个或多个组件,所有组件必须以任意顺序出现。
- 双竖线(||)分隔两个或多个选项:其中一个或多个必须以任意顺序出现。
- 竖线(|)分隔两个或多个备选项:必须且仅能出现其中一个。
- 方括号 ([ ]) 用于分组。
相邻排列的优先级高于双与号,双与号高于双竖线,双竖线高于单竖线。因此,下列语句是等价的:
a b | c || d && e f[ a b] |[ c ||[ d &&[ e f]]]
对于可重排序组合符(||, &&),语法的顺序无关紧要:同一分组中的组件可以按任何顺序交替出现。因此,以下行是等效的:
a || b || c b || a || c
注意: 组合符不是结合性的,因此分组很重要。例如,a || b || c 和 a || [ b || c ] 是不同的语法:前者允许像 b a c 这样的值,但后者不允许。
2.3. 组件值乘数
每种类型、关键字或括号组后面都可以跟随以下修饰符之一:
- 星号(*)表示前述类型、单词或组出现零次或多次。
- 加号(+)表示前述类型、单词或组出现一次或多次。
- 问号(?)表示前述类型、单词或组是可选的(出现零次或一次)。
- 花括号中的单个数字({A})表示前述类型、单词或组出现 A 次。
- 花括号中逗号分隔的一对数字({A,B})表示前述类型、单词或组至少出现 A 次且至多出现 B 次。可以省略 B({A,})以表示必须至少出现 A 次,且对重复次数没有上限。
- 哈希标记(#)表示前述类型、单词或组出现一次或多次,并用逗号分隔(逗号周围可选择性地包含 空白符 和/或注释)。它可以选择性地后跟上述花括号形式,以精确指示重复发生的次数,如 <length>#{1,4}。
- 组后的感叹号(!)表示该组是必需的,且必须产生至少一个值;即使组内项的语法在其他情况下允许省略整个内容,也必须至少有一个组件值不被省略。
+ 和 # 乘数可以堆叠为 +#;类似地,# 和 ? 乘数可以堆叠为 #?。这些堆叠分别代表将后一个乘数应用于前一个乘数的结果。(这些堆叠也可以通过分组表示,但在复杂的语法中,这会使括号数量超出可读性范围。)
对于重复的组件值(由 *、+ 或 # 指示),UA 必须支持至少 20 次重复。如果属性值包含超过支持的重复次数,则必须像无效声明一样忽略该声明。
2.4. 组合符与乘数模式
有少量通用方法可以以特定的数量和顺序组合多个独立的 组件值。特别是,通常需要表达作者必须从一组组件值中选择零个或多个、一个或多个或所有组件,并且可以按语法中指定的顺序或按任意顺序选择。
| 有序: | 任意顺序: | |
|---|---|---|
| 零个或多个 | A? B? C?
| A? || B? || C?
|
| 一个或多个 |
| A || B || C
|
| all | A B C
| A && B && C
|
请注意,所有“任意顺序”的可能性都是使用组合符表达的,而“有序”的可能性都是并列的变体。
2.5. 组件值与空白符
除非另有说明,空白符和/或注释可以出现在使用上述 组合符 和 乘数 组合的组件之前、之后和/或之间。
注意: 在许多情况下,组件之间实际上需要空格,以便将它们彼此区分开来。例如,值 1em2em 将被解析为一个带有数字 1 和标识符 em2em 的单一 <dimension-token>,这是一个无效的单位。在这种情况下,2 之前需要一个空格,才能将其解析为 1em 和 2em 这两个长度。
2.6. 函数式符号定义
一个 函数式符号 的语法定义为一系列:
-
函数名称,写为一个标识符,后跟一个左括号(例如 example(),或者用于指示具有任意名称的函数的 <function-token> 产生式。
-
函数的参数(如果有),使用 值定义语法 表达。
-
字面上的右括号。
函数的参数被视为隐式分组,如同被括号([ ... ])包围一样。
<pseudo-class-selector> =':' <ident-token> |':' <function-token> <any-value>')'
这代表任何函数名称,并以 <any-value> 作为函数参数。
2.7. 属性值示例
以下是一些具有相应值定义字段的属性示例:
| 属性 | 值定义字段 | 示例值 |
|---|---|---|
| orphans (孀行) | <integer>(整数) | 3 |
| text-align | left | right | center | justify | center |
| padding-top | <length> | <percentage> | 5% |
| outline-color | <color> | invert | #fefefe |
| text-decoration | none | underline || overline || line-through || blink | overline underline |
| font-family | [ <family-name> | <generic-family> ]# | "Gill Sans", Futura, sans-serif |
| border-width | [ <length> | thick | medium | thin ]{1,4} | 2px medium 4px |
| box-shadow | [ inset? && <length>{2,4} && <color>? ]# | none | 3px 3px rgba(50%, 50%, 50%, 50%), lemonchiffon 0 0 4px inset |
2.8. 非终结符定义与语法产生式块
非终结符(如 <position> 或 <calc()>)的精确语法通常在 CSS 语法产生式块 中指定。这些通常在预格式化的定义块中表示,如下所示:
每个定义从新的一行开始,由待定义的非终结符组成,后跟 =,再后跟它展开的 值定义语法 片段。定义可以跨越多个行,并在开始新语法产生式的下一行之前或语法产生式块的末尾终止(以先到者为准)。
3. 组合值:插值、加法与累加
某些过程(例如 过渡 和 动画)会 组合 两个 CSS 属性值。定义了以下组合操作——在两个 计算值 VA 和 VB 上,产生 计算值 Vresult。对于非交换的操作(例如矩阵乘法或不匹配的转换列表的累加),VA 代表操作的第一个项,VB 代表第二个。
- interpolation (插值)
- 给定两个属性值 VA 和 VB,在 VA 和 VB 之间的区间内产生一个距离为 p 的中间值 Vresult,使得 p = 0 产生 VA,而 p = 1 产生 VB。
由于 缓动函数 的影响,p 的范围是 (−∞, ∞)。因此,该过程还必须定义 p 在 [0, 1] 之外的外推行为。
- 加法:
- 给定两个属性值 VA 和 VB,返回两个属性的和,即 Vresult。
注意: 虽然 加法 通常可以用定义 插值 时使用的相同加权求和函数来表示,但情况并非总是如此。例如,变换矩阵的插值涉及分解并插值矩阵组件,而加法则依赖于矩阵乘法。
如果一个值类型没有定义特定的 加法 过程,或者被定义为 不可加,其 加法 操作即为 Vresult = VB。
- 累加:
- 给定两个属性值 VA 和 VB,返回组合两个操作数的结果 Vresult,其中 VB 被视为相对于 VA 的增量。
这些操作仅定义在 计算值 上。(因此,不需要定义例如如何将 15pt 的 <length> 值与 5em 相加,因为此类值在传递给上述任何过程之前,会被解析为它们的 规范单位。)
3.1. 范围检查
插值可能导致值超出属性的有效范围,即使插值的所有输入都是有效的;这尤其发生在 p 超出 [0, 1] 范围时,但某些 缓动函数 可能导致这种情况甚至在 [0, 1] 范围内发生。如果插值、加法和累加之后的最终结果在目标上下文中超出范围,这不会导致声明无效。相反,该值必须被钳制(clamp)到目标上下文中允许的范围内,与 数学函数 完全一样(参见 § 10.12 范围检查)。
注意: 即使插值导致了超出范围的值,加法/累加也可能“纠正”结果并使其回到范围内。因此,钳制仅应用于应用所有插值相关操作后的最终结果。
4. 文本数据类型
文本数据类型 包括各种关键字和标识符,以及字符串(<string>)和 URL(<url>)。除了 预定义关键字 的大小写或给定属性明确定义的外,不执行任何规范化,甚至不执行 Unicode 规范化:属性的 指定值 和 计算值 正是解析后的 Unicode 值(包括字符集转换和 转义)。[UNICODE] [CSS-SYNTAX-3]
CSS 标识符(通用表示为 <ident>)由符合 <ident-token> 语法的字符序列组成。[CSS-SYNTAX-3] 标识符不能加引号,否则会被解释为字符串。CSS 属性接受两类 标识符:预定义关键字 和 作者自定义标识符。
注意: <ident> 产生式不用于属性值定义——而应使用 <custom-ident>。它是为了方便定义其他语法结构而提供的。
4.1. 预定义关键字
在值定义字段中,具有预定义含义的 关键字 字面出现。关键字是 标识符,并按 ASCII 大小写不敏感 方式解释(即 [a-z] 和 [A-Z] 是等效的)。
Value : collapse | separate
以下是它的使用示例:
table{ border-collapse : separate}
4.1.1. CSS 全局关键字:initial、inherit 和 unset
正如 上面 所定义,所有属性都接受 CSS 全局关键字,它们代表对所有 CSS 属性通用的值计算。这些关键字在 CSS 级联与继承模块 中规范定义。
其他 CSS 规范可以定义额外的 CSS 全局关键字。
4.2. 无前缀的作者自定义标识符:<custom-ident> 类型
某些属性接受任意的作者自定义标识符作为组件值。此通用数据类型表示为 <custom-ident>,代表任何在属性的值定义中不会被误解为预定义关键字的有效 CSS 标识符。此类标识符是完全大小写敏感的(这意味着它们使用“等同于”操作进行比较),甚至在 ASCII 范围内也是如此(例如 example 和 EXAMPLE 是两个不同的、不相关的用户定义标识符)。
CSS 全局关键字 不是有效的 <custom-ident>。default 关键字被保留,也不是有效的 <custom-ident>。使用 <custom-ident> 的规范必须清楚地说明哪些其他关键字从 <custom-ident> 中排除(如果有)——例如通过声明该属性值定义中的任何预定义关键字均被排除。被排除的关键字在所有 ASCII 大小写排列 中都被排除。
在解析属性值中位置模糊的关键字时,只有在没有其他未满足的产生式可以声明该关键字的情况下,<custom-ident> 产生式才能声明它。
注意: 在设计带有 <custom-ident> 的语法时,<custom-ident> 应该始终是“位置上无歧义的”,以便不可能与属性中的任何关键字值发生冲突。或者,通过使用 <dashed-ident> 可以避免此类冲突。
4.3. 带前缀的作者自定义标识符:<dashed-ident> 类型
某些上下文既接受作者自定义的标识符,也接受 CSS 定义的标识符。如果处理不当,这可能会在添加新的 CSS 定义值时造成困难;UA 必须研究现有的用法,并押注在使用中的作者自定义标识符中,与新的 CSS 定义标识符匹配的足够少,从而赋予新值特殊的 CSS 定义含义不会破坏现有页面。
虽然 CSS 中存在许多以这种充满风险的方式混合这两个值空间的遗留案例,但 <dashed-ident> 类型旨在成为区分作者自定义标识符与 CSS 定义标识符的一种简单方法。
<dashed-ident> 产生式是一个 <custom-ident>,具有其隐含的所有大小写敏感性,且附加了一个限制:它必须以两个破折号(U+002D HYPHEN-MINUS)开头。
<dashed-ident> 仅保留供作者自定义名称使用。CSS 永远不会定义 <dashed-ident> 供自己使用。
.foo{ --fg-color : blue; }
@color-profile --foo{ src : url ( https://example.com/foo.icc ); } .foo{ color : color ( --foo1 0 .5 /.2 ); }
例如,如果 CSS 预处理器添加了一个新的“自定义”at-规则,它不应该将其拼写为 @custom,因为这将与 CSS 未来添加的正式 @custom 规则冲突。相反,它应该使用 @--custom,这保证永远不会与 CSS 定义的任何内容发生冲突。
更好的是,它应该使用 @--library1-custom,这样如果 Library2 添加了他们自己的“自定义”at-规则(拼写为 @--library2-custom),就不会发生冲突的可能性。理想情况下,如果工具允许,这个前缀应该是可定制的,以便作者可以手动避免冲突。
4.4. 引号字符串:<string> 类型
字符串 由 <string> 表示。当字面书写时,它们由双引号或单引号定界的一系列字符组成,对应于 CSS 语法模块 [CSS-SYNTAX-3] 中的 <string-token> 产生式。
"\" " 或 "\22" )。单引号也类似(写为 '\' ' 或 '\27' )。content : "this is a 'string'." ; content : "this is a \" string\"." ; content : 'this is a "string".' ; content : 'this is a \' string\'.'
出于美观或其他原因,可以将字符串拆分到多行,但在这种情况下,换行符本身必须用反斜杠(\)进行转义。换行符随后会从字符串中移除。例如,以下两个选择器完全相同:
由于字符串不能直接表示换行符,要在字符串中包含换行符,请使用转义符“\A”。(十六进制 A 是 Unicode 中的换行字符 (U+000A),但在 CSS 中代表“换行符”这一通用概念。)
4.5. 资源定位符:<url> 类型
<url> 类型,通过 url() 和 src() 函数书写,表示一个 URL,即指向资源的指针。
<url> 的语法是:
<url> = <url () > | <src () > <url () > =url ( <string> <url-modifier> * ) | <url-token> <src () > =src ( <string> <url-modifier>*)
由于遗留原因,url() 可以不带引号书写,在这种情况下,它被 特殊解析 为 <url-token> [CSS-SYNTAX-3]。由于这种特殊解析,url() 只能字面指定其 URL;src() 缺少此特殊解析规则,因此其 URL 可以由函数(例如 var())提供。
background : url ( "http://www.example.com/pinkish.gif" ); background : url ( http://www.example.com/pinkish.gif );
这些也具有相同的含义:
background : src ( "http://www.example.com/pinkish.gif" ); --foo : "http://www.example.com/pinkish.gif" ; background : src ( var ( --foo));
但这不起作用:
--foo : "http://www.example.com/pinkish.gif" ; background : url ( var(--foo ));
……因为值中未转义的“(”导致了解析错误,所以整个声明被作为无效声明丢弃。
解析不带引号的 url() 语法的精确要求在 [CSS-SYNTAX-3] 中规范定义。
某些 CSS 上下文(如 @import)也允许 <url> 由裸 <string> 表示,无需函数包装器。在此类情况下,字符串的行为与包含该字符串的 url() 函数的行为相同。
4.5.1. 相对 URL
为了创建不依赖资源绝对位置的模块化样式表,作者应使用相对 URL。相对 URL(如 [URL] 中定义)使用基本 URL 解析为完整 URL。RFC 3986 第 3 节定义了此过程的规范算法。对于 CSS 样式表,基本 URL 是样式表本身,而不是被设置样式的源文档。嵌入文档中的样式表具有与其容器关联的基本 URL。
注意: 对于 HTML 文档,基本 URL 是可变的。
当 <url> 出现在属性的计算值中时,它会解析为绝对 URL,如上一段所述。UA 无法解析为绝对 URL 的 URL,其计算值为指定值。
body{ background : url ( "tile.png" ) }
位于由以下 URL 指定的样式表中:
http : //www.example.org/style/basic.css
源文档 <body> 的背景将平铺由该 URL 指定的资源所描述的任何图像:
http : //www.example.org/style/tile.png
无论包含该 <body> 的源文档的 URL 如何,都将使用相同的图像。
4.5.1.1. 片段 URL
为了使元素 ID 引用在 CSS 中工作,无论基本 URL 更改或 shadow DOM 如何,<url> 在仅包含片段时都有特殊行为。
如果 <url> 的值以 U+0023 数字标志(#)字符开头,则该 URL 还会设置其 本地 URL 标志,并且是该 URL 片段 的 树作用域引用。
-
如果 URL 的片段是元素 ID 引用(而不是媒体片段等),请将其解析为 树作用域引用,并以该树的 ID 作为相关联的 树作用域名称:具体而言,解析为 树顺序 中相关联的 节点树 后代中,ID 为 URL 片段 的第一个元素。(并且,按照 树作用域引用 的惯例,如有必要,继续向上到达宿主的树。)
如果没有找到这样的元素,则 URL 解析失败。
-
否则,相对于当前文档解析该片段。
可能引用 查找潜在的指示元素,但这是专门为 Document 定义的,而不是 ShadowRoot。
注意: 这意味着此类片段将相对于当前文档的内容进行解析(或者如果涉及 shadow DOM,则相对于样式表所在处的 节点树),而不管此类相对 URL 在其他地方将如何解析(例如,忽略更改基本 URL 的 base 元素,或链接样式表中的相对 URL 解析为样式表的 URL)。
#anchor 将相对于 http : //example.com/ 进行解析,而 #image 将相对于 HTML 文档本身中的元素进行解析:<!DOCTYPE html> < base href = "http://example.com/" > ...< a href = "#anchor" style = "background-image: url(#image)" > link</ a >
当 序列化 设置了 本地 URL 标志 的 url() 时,它必须仅序列化为片段。
4.5.2. 空 URL
如果 <url> 的值为空字符串(例如 url("") 或 url()),则 URL 必须解析为一个无效资源(类似于 about:invalid URL 的作用)。
其计算值为 url("") 或 src("")(以指定为准),并且必须按原样序列化。
注意: 这与 Web 平台上其他地方嵌入资源的空 URL 行为相匹配,并避免了因编辑错误导致 url() 值为空而重新请求样式表或宿主文档导致的过度流量,这在 url() 出现的任何地方几乎肯定都是无效资源。Web 平台上的链接确实允许空 URL,因此如果/当 CSS 获得控制超链接的某些功能时,这些限制可以在这些上下文中放宽。
4.5.3. URL 修饰符
<url> 支持指定额外的 <url-modifier>,这会改变 URL 的含义或解释方式。<url-modifier> 要么是 <ident>,要么是 函数式符号。
本规范未定义任何 <url-modifier>,但其他规范可能会这样做。
注意: 既未加引号也未包装在 url() 符号中的 <url> 不能接受任何 <url-modifier>。
4.5.4. URL 处理模型
CSSStyleSheet sheet、一个匹配 RequestDestination 的字符串 destination、“no-cors”或“cors” corsMode,以及一个接受 响应 和 null、失败或字节流的算法 processResponse:-
令 environmentSettings 为 sheet 的 相关设置对象。
-
令 base 为 sheet 的 样式表基本 URL(如果非 null),否则为 environmentSettings 的 API 基本 URL。[CSSOM]
-
令 parsedUrl 为 URL 解析器 步骤对 urlValue 的 url 和 base 执行的结果。如果算法返回错误,则返回。
-
令 req 为一个新的 请求,其 url 为 parsedUrl,其 destination 为 destination,mode 为 corsMode,origin 为 environmentSettings 的 origin,credentials mode 为 "same-origin",use-url-credentials 标志 被设置,client 为 environmentSettings,其 referrer 为 environmentSettings 的 API 基本 URL。
-
应用适用于此请求的任何 URL 请求修改器步骤。
注意: 本规范未定义任何 URL 请求修改步骤,但其他规范可能会这样做。
-
如果 req 的 mode 为 "cors",则将 req 的 referrer 设置为 sheet 的 location。[CSSOM]
-
如果设置了 sheet 的 origin-clean 标志,则将 req 的 initiator type 设置为 "css"。 [CSSOM]
-
获取 req,并将 processresponseconsumebody 设置为 processResponse。
在解释 CSS 中表达的 URL 时,必须省略 URL 解析器 的 encoding 参数(即使用默认值 UTF-8),而不管样式表编码如何。
注意: 换句话说,CSS 中编写的 URL 将始终在 URL 对象中使用 UTF-8 对非 ASCII 码点进行 百分比编码(因此无论何时使用 URL 值进行网络请求时都是如此),而不管样式表自身的编码如何。请注意,这发生在 将样式表解码 为 Unicode 码点 之后。
5. 数值数据类型
数值数据类型用于表示数量、索引、位置以及其他此类值。虽然在表达给定数值中的数量(数值方面)时可以存在许多句法变体,但 指定值 和 计算值 不区分这些变体:它们代表值的抽象数量,而不是其句法表示。
数值数据类型 包括 <integer>、<number>、<percentage> 以及包括 <length>、<angle>、<time>、<frequency> 和 <resolution> 在内的各种 维度。
注意: 虽然此处定义了通用 维度,但其他一些模块定义了额外的数据类型(例如 [css-grid-1] 引入了 fr 单位),其使用更加局部化。
CSS 中数值的精度和支持范围是 实现定义 的,并且可能根据属性或使用值的其他上下文而变化。然而,在 CSS 规范中,假设精度和范围是无限的。当由于范围/精度限制而无法明确支持值时,必须将其转换为实现支持的最接近的值,但实现如何定义“最接近”也是 实现定义 的。
如果 <angle> 由于超出实现支持的范围而必须转换,则必须将其钳制到 360deg 的最近支持倍数。
5.1. 范围限制与范围定义符号
属性可以将数值限制在一定范围内。如果数值超出允许范围,除非另有说明,否则该声明无效且必须被忽略。范围限制可以使用CSS 方括号范围表示法在数值类型记法中进行标注————即在尖括号内,标识关键字之后,指示一个包含 min 和 max 的闭区间。例如,<integer [0,10]> 表示一个 0 到 10(含)之间的整数,而 <angle [0,180deg]> 表示一个 0deg 到 180deg(以任何单位表示)之间的角度。
注意:CSS 值通常不允许开区间;因此仅使用方括号表示法。
从理论上讲,CSS 支持所有值类型的无限精度和无限范围;但实际上,实现方案具有有限的容量。用户代理 (UA) 应支持足够实用的范围和精度。理想情况下无限制的范围极值使用 ∞ 或 −∞ 表示。例如,<length [0,∞]> 表示非负长度。
如果没有通过方括号范围表示法或在属性描述中指明范围,则默认为 。
−∞ 或 ∞ 的值必须在书写时不带单位,即使该值类型使用单位。值为 0 时可以不带单位,即使该值类型不允许“无单位的零”(例如 <time>)。
注意:在撰写本文时,方括号范围表示法尚属新特性;因此在大多数 CSS 规范中,任何范围限制仅以文字形式描述。(例如,“不允许负值”或“负值无效”表示 范围。)但这同样具有约束力。
5.2. 整数:<integer> 类型
整数值由 <integer> 表示。
从字面上书写时,整数是一个或多个十进制数字 0 到 9,对应于 CSS 语法模块 [CSS-SYNTAX-3] 中 <number-token> 生产规则的一个子集。整数的第一个数字前可紧跟 - 或 + 以指示整数的正负号。
除非另有规定,在 CSS 规范中,四舍五入到最近的整数要求当小数部分恰好为 0.5 时,向 +∞ 方向舍入。(例如,1.5 舍入为 2,而 -1.5 舍入为 -1。)
5.2.1. <integer> 的计算与组合
除非另有说明,指定的 <integer> 的计算值即为指定的抽象整数。
<integer> 的插值定义为 Vresult = round((1 - p) × VA + p × VB);也就是说,插值发生在实数空间中,如同 <number> 一样,结果通过四舍五入到最近的整数转换为 <integer>。
<integer> 的加法定义为 Vresult = VA + VB
5.3. 实数:<number> 类型
数值由 <number> 表示,代表实数,可能包含小数部分。
从字面上书写时,数字是一个整数,或者是零个或多个十进制数字后跟一个点 (.) 再后跟一个或多个十进制数字;可选地,它可以以字母“e”或“E”结尾,后跟一个整数,表示科学记数法中的以十为底的指数。它对应于CSS 语法模块 [CSS-SYNTAX-3] 中的 <number-token> 生产规则。与整数一样,数字的第一个字符前可紧跟 - 或 + 以指示数字的正负号。
<zero> 的值表示字面上的值为 0 的数字。仅仅求值为 0 的 <number> 的表达式(例如 calc(0))不匹配 <zero>;只有字面的 <number-token> 才匹配。
5.3.1. <number> 的计算与组合
除非另有说明,指定的 <number> 的计算值即为指定的抽象数字。
<number> 的插值定义为 Vresult = (1 - p) × VA + p × VB
<number> 的加法定义为 Vresult = VA + VB
5.4. 带单位的数字:维度值
通用术语维度 (dimension)指代一个附加了单位的数字;并由 <dimension> 表示。
从字面上书写时,维度是一个后跟单位标识符的数字,单位标识符是一个标识符。它对应于CSS 语法模块 [CSS-SYNTAX-3] 中的 <dimension-token> 生产规则。与关键字一样,单位标识符是ASCII 不区分大小写的。
CSS 使用 <dimension> 指定距离(<length>)、时长(<time>)、频率(<frequency>)、分辨率(<resolution>)以及其他量。
5.4.1. 兼容单位
当序列化计算值 [CSSOM] 时,兼容单位(通过静态乘法因子相关的单位,例如 px 和 in 之间 96:1 的因子,或 em 和 px 之间计算出的 font-size 因子)被转换为单一的规范单位 (canonical unit)。每组兼容单位都定义了其中哪一个是用于序列化的规范单位。
在序列化作为使用值的解析值时,所有代表长度的值类型(百分比、数字、关键字等)均被视为与长度兼容。同样,任何返回使用值的未来 API 必须将任何代表距离/时长/频率等的值视为与相关维度类别兼容,并相应地进行规范化。
5.4.2. 维度的组合
兼容维度(例如,两个 <length> 值)的插值定义为 Vresult = (1 - p) × VA + p × VB
5.5. 百分比:<percentage> 类型
百分比值由 <percentage> 表示,指示某个参考值的一部分。
从字面上书写时,百分比由一个数字后跟百分号 % 组成。它对应于CSS 语法模块 [CSS-SYNTAX-3] 中的 <percentage-token> 生产规则。
百分比值始终相对于另一个量(例如长度)。每个允许百分比的属性也定义了该百分比所引用的量。该量可以是同一元素另一个属性的值、祖先元素属性的值、格式化上下文的度量(例如,包含块的宽度),或其他事物。
5.5.1. <percentage> 的计算与组合
除非另有说明(例如 font-size,它将 <percentage> 值计算为 <length>),否则百分比的计算值即为指定的百分比。
<percentage> 的插值定义为 Vresult = (1 - p) × VA + p × VB
<percentage> 的加法定义为 Vresult = VA + VB
5.6. 百分比与维度的混合
在 <percentage> 可以表示与同一组件值位置的维度相同的量,并因此可以在 calc() 表达式中与它们组合的情况下,属性语法中可以使用以下便捷记法
- <length-percentage>
-
等同于
,其中 <percentage> 将解析为 <length>。[ <length> | <percentage>] - <frequency-percentage>
-
等同于
,其中 <percentage> 将解析为 <frequency>。[ <frequency> | <percentage>] - <angle-percentage>
-
等同于
,其中 <percentage> 将解析为 <angle>。[ <angle> | <percentage>] - <time-percentage>
-
等同于
,其中 <percentage> 将解析为 <time>。[ <time> | <percentage>]
另一方面,hsl() 函数的第二个和第三个参数只能表示为 <percentage>。虽然允许在它们的位置使用 calc() 产生式,但它们只能将百分比与自身组合,如 calc(10% + 20%)。
注意:除非 兼容,否则规范不应在语法中交替使用 <percentage> 来替代维度。
注意:未来可以根据需要添加更多的 <type-percentage> 产生式。永远不会添加 <number-percentage>,因为 <number> 和 <percentage> 不能在 calc() 中组合。
5.6.1. 百分比与维度混合的计算与组合
百分比-维度混合的计算值定义为
-
如果百分比分量为零或被专门定义为计算为维度值,则为计算后的维度
-
如果维度分量为零,则为计算后的百分比
百分比-维度值组合(例如 <length-percentage>、<frequency-percentage>、<angle-percentage>、<time-percentage> 或等效记法)的插值定义为
- 如果 VA 和 VB 均为纯 <length> 值,则等同于 <length> 的插值
- 如果 VA 和 VB 均为纯 <percentage> 值,则等同于 <percentage> 的插值
- 等同于将两个值转换为代表维度类型与百分比(可能均为零)之和的 calc() 表达式,并分别插值每个分量(分别作为 <length>/<frequency>/<angle>/<time> 和 <percentage>)
<percentage> 的加法的定义与插值相同,只是通过相加每个分量而不是插值它。
5.7. 比率:<ratio> 类型
比率值由 <ratio> 表示,代表两个数值的比率。它通常代表纵横比,将宽度(第一个)与高度(第二个)相关联。
从字面上书写时,比率的语法为
<ratio> = <number[ 0 , ∞] >[ / <number[ 0 , ∞] >] ?
第二个 <number> 是可选的,默认为 1。但是,<ratio> 在序列化时总是包含两个分量。
<ratio> 的计算值是所提供的两个数字对。
如果 <ratio> 中的任何一个数字为 0 或无限,它代表一个退化比率 (degenerate ratio)(且通常不会产生任何效果)。
如果需要比较两个 <ratio>,则将第一个数字除以第二个,并比较结果。例如,3/2 小于 2/1,因为前者解析为 1.5,而后者解析为 2。(换句话说,“高”纵横比小于“宽”纵横比。)
5.7.1. <ratio> 的组合
<ratio> 的插值定义为:将每个 <ratio> 通过将第一个值除以第二个值转换为数字(因此 3 / 2 的比率将变为 1.5),取该结果的对数(因此 1.5 将变为约 0.176),然后对这些值进行插值。插值过程中的结果通过求对数逆运算转换回 <ratio>,然后将结果解释为以该结果作为第一个值,1 作为第二个值的 <ratio>。
start =log ( 5 ); // ≈0.69897 end =log ( 1.5 ); // ≈0.17609 interp =0.69897 *.5 +0.17609 *.5 ; // ≈0.43753 final =10 ^interp; // ≈2.73
注意:在比率的对数上进行插值意味着结果与比例无关(5 / 1 到 300 / 200 将给出与上述相同的结果),它们在“宽”和“高”变体上是对称的(从 1 / 5 到 2 / 3 的插值将在中间点给出一个大致等于 1 / 2.73 的比率),并且无论宽度是固定的且高度基于比率,还是反之,它们都是对称的。许多其他可能的插值策略并不具备这些属性。
注意:由于对数的属性,可以使用任何对数;此处的示例使用以 10 为底的对数,但如果使用自然对数和 e,中间结果会不同,但最终结果将相同。
无法进行 <ratio> 的加法。
6. 距离单位:<length> 类型
长度指距离测量,在属性定义中由 <length> 表示。长度是一个维度。
对于零长度,单位标识符是可选的(即在语法上可以表示为 <number> 0)。但是,如果 0 在属性(如 line-height)中既可被解析为 <number> 又可被解析为 <length>,则必须将其解析为 <number>。
属性可以将长度值限制在一定范围内。如果数值超出允许范围,则该声明无效且必须被忽略。
虽然有些属性允许负长度值,但这可能会使格式化复杂化,并且可能存在特定于实现的限制。如果允许使用负长度值但无法支持,则必须将其转换为可支持的最近值。
在使用长度无法支持的情况下,用户代理必须在其实际值中对其进行近似处理。
长度单位有两种类型:相对和绝对。长度的指定值(指定长度)由其量和单位表示。长度的计算值(计算长度)是解析为绝对长度的指定长度,其单位不作区分:它可以由任何绝对长度单位表示(但将使用其规范单位 px 进行序列化)。
虽然数值的精确支持精度以及如何对其进行舍入以匹配该精度通常是由实现定义的,但 border-width 以及其他一些属性中的 <length> 会以特定方式进行舍入,以确保合理的视觉显示。(此算法由各个属性显式调用。)
6.1. 相对长度
相对长度单位指定相对于另一个长度的长度。使用相对单位的样式表可以更轻松地从一个输出环境扩展到另一个输出环境。
相对单位为
| unit | 相对于 |
|---|---|
| em | 元素的字体大小 |
| ex | 元素字体的 x-height |
| ∩(符号) | 元素字体的上限高度(大写字母的名义高度) |
| ch | 元素字体中窄字形的典型字符推进宽度,由“0”(ZERO,U+0030)字形表示 |
| ic | 元素字体中全角字形的典型字符推进宽度,由“水”(CJK 水字,U+6C34)字形表示 |
| 取余 (rem) | 根元素的字体大小 |
| lh | 元素的行高 |
| rlh | 根元素的行高 |
| vw | 视口宽度的 1% |
| vh | 视口高度的 1% |
| vi | 根元素内联轴上视口尺寸的 1% |
| vb | 根元素块轴上视口尺寸的 1% |
| vmin | 视口较小维度的 1% |
| vmax | 视口较大维度的 1% |
子元素不会继承为其父元素指定的相对值;它们继承计算值。
6.1.1. 字体相对长度:em、rem、ex、rex、cap、rcap、ch、rch、ic、ric、lh、rlh 单位
字体相对长度指代使用它们的元素(对于本地字体相对长度)或根元素(对于根字体相对长度)的字体度量。
- em
- 等于其所应用元素的 font-size 属性的计算值。
- 取余 (rem)
- 等于根元素上 em 单位的计算值。
- ex
- 等于第一个可用字体 [CSS3-FONTS] 的已用 x-height。x-height 之所以如此命名,是因为它通常等于小写字母“x”的高度。然而,即使对于不包含“x”的字体,ex 也是有定义的。字体的 x-height 可以通过多种方式确定。有些字体包含可靠的 x-height 度量。如果可靠的字体度量不可用,UA 可以根据小写字形的高度来确定 x-height。一种可能的启发式方法是查看小写“o”的字形从基线下方延伸的距离,并将其从其边界框的顶部减去。在无法或不切实际确定 x-height 的情况下,必须假设其值为 0.5em。
- rex
- 等于根元素上 ex 单位的值。
- ∩(符号)
- 等于第一个可用字体 [CSS3-FONTS] 的已用上限高度 (cap-height)。上限高度之所以如此命名,是因为它大致等于大写拉丁字母的高度。然而,即使对于不包含拉丁字母的字体,cap 也是有定义的。字体的上限高度可以通过多种方式确定。有些字体包含可靠的上限高度度量。如果可靠的字体度量不可用,UA 可以根据大写字形的高度来确定上限高度。一种可能的启发式方法是查看大写“O”的字形从基线下方延伸的距离,并将其从其边界框的顶部减去。在无法或不切实际确定上限高度的情况下,必须使用字体的上升 (ascent) 高度。
- rcap
- 等于根元素上 cap 单位的值。
- ch
- 代表欧洲字母数字字符的典型推进宽度,并测量为用于渲染它的字体中“0”(ZERO,U+0030)字形的已用推进宽度。(字形的推进宽度 (advance measure)是指其推进宽度或高度,以元素内联轴方向为准。)
注意:此度量是单个窄字形推进宽度的近似值(在等宽字体中为精确值),从而允许基于预期的字形数量进行度量。
注意:字形的推进宽度取决于书写模式和文本方向,以及字体设置、文本转换和任何其他影响字形选择或方向的属性。
在无法或不切实际确定“0”字形度量的情况下,必须假设其宽为 0.5em,高为 1em。因此,ch 单位在一般情况下回退为 0.5em,当它被直排显示时(即 writing-mode 为 vertical-rl 或 vertical-lr 且 text-orientation 为 upright)回退为 1em。
- rch
- 等于根元素上 ch 单位的值。
- ic
- 代表 CJK 字符的典型推进宽度,测量为用于渲染它的字体中发现的“水”(CJK 水字,U+6C34)字形的已用推进宽度。
注意:此度量通常是单个全角字形推进宽度的精确度量(在极少数具有比例全角字形的字体中为近似值),从而允许基于预期的字形数量进行度量。
在无法或不切实际确定表意文字推进宽度的情况下,必须假设其为 1em。
- ric
- 等于根元素上 ic 单位的值。
- lh
- 等于其所应用元素的 line-height 属性的计算值,仅使用第一个可用字体的度量将 normal 转换为绝对长度。
- rlh
- 等于根元素上 lh 单位的值。
注意:使用 lh 或 rlh 单位设置元素的 height 并不允许作者控制该元素中实际的行数。这些单位仅允许基于理想空行理论大小进行长度计算;实际行框的大小可能会根据其内容而有所不同。在作者想要限制元素中实际行数的情况下,可以使用 max-lines 属性。
当用于它们所指代元素的任何 font-* 属性的值时,字体相对长度根据父元素的计算度量进行解析——如果元素没有父元素,则根据 font 和 line-height 属性的初始值对应的计算度量进行解析。同样,当 lh 或 rlh 单位用于它们所指代元素的 line-height 属性或 font-* 属性的值时,它们根据父元素的计算 line-height 和字体度量进行解析——如果元素没有父元素,则根据 font 和 line-height 属性的初始值对应的计算度量进行解析。(在 line-height 中使用时,其他字体相对长度继续根据元素自身的度量进行解析。)
当在元素上下文之外使用(例如在 媒体查询 中)时,字体相对长度单位指代 font 和 line-height 属性初始值对应的度量。同样,当在没有根元素的文档中指定时,根字体相对长度是在假设 font 和 line-height 属性采用初始值的情况下进行解析的。
注意:字体相对单位(如 ch 和 ic)如果所需字体尚未加载,可能会触发字体下载。
字体相对长度是在没有整形 (shaping) 的情况下计算的。
一些用户代理允许用户对文档中的字体大小应用额外限制,例如设置最小字体大小以确保可读性。此类限制必须仅应用于受影响属性的使用值;它们绝不影响属性中使用的字体相对长度的解析。然而,在其他上下文中(例如在 媒体查询 中),在它们会影响已用字体度量的范围内,此类限制确实会影响字体相对长度的解析。
注意:通常,尊重用户的偏好(如最小字体大小)是可取的;对于像 (min-width: 40em) 这样的媒体查询,使用文档将要显示的实际字体大小是很有用的。然而,让这些偏好影响元素属性上的字体相对长度被发现是不符合 Web 兼容性的;太多的页面预期这些单位是指定的 font-size 的整数倍,而不是应用用户偏好后的实际字体大小。
一些用户代理对表单控件上的 line-height 值应用了限制。这些限制必须对 lh 和 rlh 单位没有影响。然而,对它们的后代产生的影响是由实现定义的。
6.1.2. 视口百分比长度:*vw、*vh、*vi、*vb、*vmin、*vmax 单位
视口百分比长度相对于初始包含块的大小——其本身基于(连续媒体的)视口大小或(分页媒体的)页面区域大小。当初始包含块的高度或宽度发生变化时,它们会相应缩放。
6.1.2.1. 大、小和动态视口尺寸
视口百分比长度单位有四种变体,对应于三种(可能相同)视口尺寸概念。
- 大视口
- 大视口百分比单位 (lv*) 和 默认视口百分比单位 (v*) 是相对于大视口尺寸 (large viewport size)定义的:即假设动态展开和收缩的任何 UA 界面均处于收缩状态时的视口大小。这允许作者设置内容大小以确保填满视口,但需注意当界面展开时,此类内容可能会被隐藏在这些界面之后。
大视口百分比单位的大小是固定的(因此是稳定的),除非视口本身被调整大小。
例如,在屏幕空间寸土寸金的手机上,浏览器通常会在用户开始滚动页面时隐藏标题栏和地址栏的一部分或全部。大视口百分比单位的大小是相对于这个所有元素均收缩的较大空间设置的,因此使用这些单位的内容在这些 UI 元素隐藏时将填满整个可见页面。然而,当这些可收缩元素显示时,它们可能会遮挡使用这些单位设置大小或定位的内容。 - 小视口
- 小视口百分比单位 (sv*) 是相对于小视口尺寸 (small viewport size)定义的:即假设动态展开和收缩的任何 UA 界面均处于展开状态时的视口大小。这允许作者设置内容大小以使其即使在这些界面存在时也能适应视口,但需注意当界面收缩时,此类内容可能无法填满视口。
小视口百分比单位的大小是固定的(因此是稳定的),除非视口本身被调整大小。
例如,一个设置为 height: 100svh 的元素,在显示 UA 的所有动态 UI 元素时,将完美填充屏幕而不会遮挡任何内容。一旦那些 UI 元素开始隐藏,元素周围就会出现额外的空间。小视口百分比单位通常更“安全”,但一旦用户开始与页面交互,可能无法产生最具吸引力的布局。
- 动态视口
- 动态视口百分比单位 (dv*) 是相对于动态视口尺寸 (dynamic viewport size)定义的:即对动态展开和收缩的任何 UA 界面进行动态考量后的视口大小。这允许作者设置内容大小以使其无论这些界面是否存在,都能精确地适应视口。
动态视口百分比单位的大小是不稳定的,即使视口本身没有改变。使用这些单位可能会导致内容在用户滚动页面时调整大小。根据用法,这可能会给用户带来干扰和/或在性能方面代价高昂。
UA 不需要在此类界面展开和收缩时对动态视口百分比单位进行动画处理,而是可以在 UI 动画期间将这些单位计算为仿佛相关界面已完全展开或收缩。(建议 UA 在此期间采用完全收缩后的尺寸。)
特定界面 (A) 的展开/收缩是否同时改变所有视口百分比长度(以及初始包含块)的大小,还是 (B) 导致大视口尺寸与小视口尺寸之间的差异,这在很大程度上取决于 UA。然而
-
由于滚动或其他频繁页面交互而导致的界面变化,如果会导致实质性的布局改变并干扰用户,则必须分类为后者 (B)。
-
界面变化如果具有足够稳定的状态,以至于将文档重新布局到调整后的空间对用户有利,则必须分类为前者 (A)。
-
此外,UA 可能拥有一些有意覆盖内容且不会导致布局偏移的动态显示界面——因此对任何视口百分比长度都没有影响。(通常屏幕键盘属于此类。)
在所有情况下,如果根元素在任一轴上的 overflow 或 scrollbar-gutter 的值会导致滚动条无条件出现(或为它们预留空间)(例如 overflow: scroll,而不是 overflow: auto),则该轴上视口百分比长度的计算值会根据初始包含块相应减小。否则,在媒体查询的情况下,视口百分比长度总是假设滚动条不存在(即使这偏离了初始包含块)。
注意:body 元素上的 overflow 值有时会影响根元素上滚动条的出现。然而,这不会影响视口单位的大小。
6.1.2.2. 各种视口相关单位
视口百分比长度单位为
- vw
- svw
- lvw
- dvw
- 分别等于大视口尺寸、小视口尺寸、大视口尺寸和动态视口尺寸宽度的 1%。
- vh
- svh
- lvh
- dvh
- 分别等于大视口尺寸、小视口尺寸、大视口尺寸和动态视口尺寸高度的 1%。
- vi
- svi
- lvi
- dvi
- 分别等于大视口尺寸、小视口尺寸、大视口尺寸和动态视口尺寸在框的内联轴上的尺寸的 1%。
- vb
- svb
- lvb
- dvb
- 分别等于初始包含块的大视口尺寸、小视口尺寸、大视口尺寸和动态视口尺寸在框的块轴上的尺寸的 1%。
- vmin
- svmin
- lvmin
- dvmin
- 等于 *vw 或 *vh 中的较小值。
- vmax
- svmax
- lvmax
- dvmax
- 等于 *vw 或 *vh 中的较大值。
注意:原始(无前缀的)视口单位被定义为相对于初始包含块,在连续媒体中,这始终与(单一的)视口大小匹配。滚动过程中浏览器界面移入移出的动态性是后来发明的,追随 Safari 的做法,大多数 UA 将这些单位映射到较大的尺寸。这样定义在许多情况下更美观,但在其他情况下可能会阻挡关键内容(如工具栏、页眉和页脚)。因此,尚不完全清楚这是否是最佳映射,因此该规范的早期版本允许 UA 选择这些默认单位的映射。但此时,为了 Web 兼容性,假定必须映射到大视口百分比单位。
在没有元素或尚未设置样式的情况下(例如评估媒体查询时),*vi 和 *vb 单位使用 writing-mode 属性的初始值来确定它们对应的轴。
6.2. 绝对长度:cm、mm、Q、in、pt、pc、px 单位
绝对长度单位彼此固定,并锚定于某种物理测量。它们主要在已知输出环境时才有用。绝对单位包括物理单位(in、cm、mm、pt、pc、Q)和视觉角度单位(像素单位)(px)
| unit | name | 等价性 |
|---|---|---|
| cm(厘米) | 厘米 | 1cm = 96px/2.54 |
| mm(毫米) | 毫米 | 1mm = 1cm 的 1/10 |
| 变量 A | 四分之一毫米 | 1Q = 1cm 的 1/40 |
| 属于 (in) | 英寸 | 1in = 2.54cm = 96px |
| pc(派卡) | 派卡 (picas) | 1pc = 1in 的 1/6 |
| pt(磅) | points | 1pt = 1in 的 1/72 |
| px(像素) | 像素 | 1px = 1in 的 1/96 |
h1{ margin : 0.5 in } /* inches */ h2{ line-height : 3 cm } /* centimeters */ h3{ word-spacing : 4 mm } /* millimeters */ h3{ letter-spacing : 1 Q } /* quarter-millimeters */ h4{ font-size : 12 pt } /* points */ h4{ font-size : 1 pc } /* picas */ p{ font-size : 12 px } /* px */
注意:出版环境中的长度有时写为 ,表示 2 派卡和 3 点的长度。这些可以在 CSS 中写为 calc(2pc + 3pt)(参见 § 10.1 基本算术:calc())。
对于 CSS 设备,这些维度是锚定的
对于正常观看距离下的打印媒体,锚定单位应为物理单位(英寸、厘米等)之一。对于屏幕媒体(包括高分辨率设备)、低分辨率设备以及观看距离不寻常的设备,建议改为使用像素单位作为锚定单位。对于此类设备,建议像素单位指代最接近参考像素的设备像素的整数。
注意:如果锚定单位是像素单位,物理单位可能与它们的物理测量不匹配。或者,如果锚定单位是物理单位,像素单位可能映射不到设备像素的整数。
注意:这种对像素单位和物理单位的定义与 CSS1 和 CSS2 的早期版本不同。特别是,在 CSS 的旧版本中,像素单位和物理单位之间并非通过固定比率相关联:物理单位始终绑定于其物理测量,而像素单位则会发生变化以尽可能匹配参考像素。(之所以做出这种不幸的改变,是因为太多现有内容依赖于 96dpi 的假设,打破该假设会破坏这些内容。)
注意:单位是ASCII 不区分大小写的,并以小写序列化,例如 1Q 序列化为 1q。
参考像素是设备像素密度为 96dpi 且距离读者一臂之长时,一个像素的视角。对于 28 英寸的名义臂长,其视角约为 0.0213 度。在臂长距离阅读时,1px 因此对应约 0.26 毫米(1/96 英寸)。
下图说明了观看距离对参考像素大小的影响:71 厘米(28 英寸)的阅读距离导致参考像素为 0.26 毫米,而 3.5 米(12 英尺)的阅读距离导致参考像素为 1.3 毫米。
第二张图说明了设备分辨率对像素单位的影响:在低分辨率设备(例如典型的计算机显示器)上,1px 乘 1px 的区域被单个点覆盖,而在较高分辨率的设备(例如打印机)上,相同的区域被 16 个点覆盖。
设备像素 (device pixel)是设备输出上能够显示其全范围色彩的最小面积单位。对于典型的彩色屏幕,它是一个包含红色、绿色和蓝色子像素的方形或略呈矩形的区域。存在许多非传统输出可以模糊此定义,例如通过以更高的分辨率显示某些颜色。然而,此类设备仍然暴露某种等效的“设备像素”概念。
7. 其他量
7.1. 角度单位:<angle> 类型和 deg、grad、rad、turn 单位
角度值是<dimension>,由 <angle> 表示。角度单位标识符为
- 度(deg)
- 度。一个完整的圆有 360 度。
- grad
- 百分度,也称为“gons”或“grades”。一个完整的圆有 400 百分度。
- rad
- 弧度。一个完整的圆有 2π 弧度。
- turn
- 圈。一个完整的圆有 1 圈。
例如,直角是 90deg 或 100grad 或 0.25turn 或约 1.57rad。
所有 <angle> 单位都是兼容的,且 deg 是它们的规范单位。
例如,在 linear-gradient() 函数中,决定渐变方向的 <angle> 被解释为方位角。
注意:由于遗留原因,<angle> 的某些用法允许用单纯的 0 表示 0deg。然而,这并不是普遍情况,也不会在未来 <angle> 类型的用法中出现。
7.2. 时长单位:<time> 类型和 s、ms 单位
时长值是维度,由 <time> 表示。时长单位标识符为
- s
- 秒。
- ms
- 毫秒。一秒有 1000 毫秒。
所有 <time> 单位均是兼容的,而 s 是它们的规范单位。
属性可能会将时间值限制在某个范围内。如果数值超出允许的范围,则该声明无效,必须被忽略。
7.3. 频率单位:<frequency> 类型以及 Hz、kHz 单位
频率值是维度,记作 <frequency>。频率单位标识符为
- Hz
- 赫兹。它代表每秒发生的次数。
- kHz
- 千赫兹。一千赫兹等于 1000 赫兹。
例如,在表示声音音高时,200Hz(或 200hz)是低音,6kHz(或 6khz)是高音。
所有 <frequency> 单位均是兼容的,而 hz 是它们的规范单位。
注意: 单位是ASCII 不区分大小写的,并序列化为小写,例如 1Hz 序列化为 1hz。
7.4. 分辨率单位:<resolution> 类型以及 dpi、dpcm、dppx 单位
分辨率单位是维度,记作 <resolution>。分辨率单位标识符为
- dpi
- 每英寸点数。
- dpcm
- 每厘米点数。
- dppx
- x
- 每 px 单位的点数。
<resolution> 单位通过指示有多少个“点”适合一个 CSS in、cm 或 px 来表示图形表示中单个“点”的大小。关于其用法,请参阅 [MEDIAQ] 中的 resolution 媒体查询,或 [CSS3-IMAGES] 中定义的 image-resolution 属性。
所有 <resolution> 单位均是兼容的,而 dppx 是它们的规范单位。
<resolution> 值的允许范围总是排除负值,此外还包括可能指定的任何明确范围。
请注意,由于 CSS in 到 CSS px 存在 1:96 的固定比例,1dppx 等同于 96dpi。这对应于 CSS 中显示的图像的默认分辨率:参见 image-resolution。
@media ( min-resolution:2 dppx ) { ...}
8. 其他地方定义的数据类型
某些数据类型定义在其各自的模块中。此示例讨论了跨多个规范使用的一些最常见的数据类型。
8.1. 颜色:<color> 类型
<color> 数据类型定义在 [CSS-COLOR-4] 中。UA 必须按照其中定义的方式解释 <color>。
8.1.1. <color> 的组合
<color> 的插值定义在 CSS Color 4 § 12. 颜色插值 中。插值是在预乘颜色之间进行的,正如 CSS Color 4 § 12.3 带 Alpha 的插值 中所定义的那样。
注意: CSS 工作组有兴趣听取有关 <color> 加法的用例,并可能在未来考虑使 <color> 成为可加的。
8.2. 图像:<image> 类型
<image> 数据类型定义在 [CSS3-IMAGES] 中。支持 CSS Images Level 3 或其后续版本的 UA 必须按照其中定义的方式解释 <image>。尚未支持 CSS Images Level 3 的 UA 必须将 <image> 解释为 <url>。
8.2.1. <image> 的组合
注意: <image> 的插值定义在 CSS Images 3 § 6 插值 中。
图像是不可加的。
8.3. 2D 定位:<position> 类型
<position> 值指定了定位区域(例如背景定位区域)内对象区域(例如背景图像)的位置。它的计算和解释方式与 background-position 的规定一致。 [CSS3-BACKGROUND]
<position> =[ [ left | center | right | top | bottom | <length-percentage>] |[ left | center | right] &&[ top | center | bottom] |[ left | center | right | <length-percentage>] [ top | center | bottom | <length-percentage>] |[ [ left | right] <length-percentage>] &&[ [ top | bottom] <length-percentage>] ]
注意: background-position 属性也接受三值语法。由于在属性值中与其他长度或百分比组件结合时会产生解析歧义,此语法已被普遍禁用。
8.3.1. 解析 <position>
当在语法中与其他关键字、<length> 或 <percentage> 一起指定时,<position> 是贪婪解析的;它会尽可能多地消耗组件。
8.3.2. 序列化 <position>
当序列化 <position> 的指定值时
- 如果只指定了一个组件
-
-
添加隐含的 center 关键字,并序列化为双组件值。
-
- 如果指定了两个组件
-
-
关键字序列化为关键字。
-
<length-percentage> 序列化为 <length-percentage>。
-
组件先序列化水平部分,然后是垂直部分。
-
- 如果指定了四个组件
-
-
关键字和偏移量都会被序列化。
-
组件先序列化水平部分,然后是垂直部分。
-
注意: <position> 值永远不会被序列化为单个值,即使在单个值会产生相同行为的情况下也是如此,以避免在某些将 <position> 放在 <length> 旁边的语法(例如 transform-origin)中引起解析歧义。
注意: 计算值总是序列化为两个偏移量(没有关键字),因为计算值不保留句法上的区别。
8.3.3. <position> 的组合
<position> 的插值被定义为每个组件(x, y)的独立插值,该组件被标准化为从左上角开始的偏移量,作为 <length-percentage>。
<position> 的加法同样被定义为每个组件(x, y)的独立加法,该组件被标准化为从左上角开始的偏移量,作为 <length-percentage>。
9. 功能符号
功能符号是一种组件值类型,可以表示更复杂的类型或调用特殊处理。语法以函数名称开始,紧随其后的是左括号(即 <function-token>),接着是符号的参数,最后是右括号。与关键字一样,函数名称是ASCII 不区分大小写的。空格是被允许的,但不是必须的,紧接在括号内。函数可以接受多个参数,这些参数的格式与 CSS 属性值相似。请参阅 § 2.6 功能符号定义。
注意: 一些遗留的功能符号(例如 rgba())不必要地使用了逗号,但通常逗号仅用于分隔列表中的项目,或分隔语法中如果不加逗号会有歧义的部分。如果使用逗号来分隔参数,则逗号前后允许有可选的空格。
background : url ( http://www.example.org/image ); color : rgb ( 100 , 200 , 50 ); content : counter ( list-item) ". " ; width : calc ( 50 % -2 em );
数学函数定义如下。其他功能符号定义在其各自的模块中;例如 <color> 函数定义在 [CSS-COLOR-4] 和 [CSS-COLOR-5] 中。
10. 数学表达式
数学函数(calc()、clamp()、sin() 以及本章定义的其他函数)允许将数值 CSS 值写为数学表达式。
数学函数表示一个数值,以下之一
...或者是 <length-percentage>/等混合类型,并且可以在此类值有效的任何地方使用。
10.1. 基本算术:calc()
calc() 函数是一个数学函数,允许对数值执行基本算术运算,包括加法(+)、减法(-)、乘法(*)、除法(/)和括号。
calc() 函数包含一个计算,它是一系列由运算符分隔的值,可能由括号分组(符合 <calc-sum> 语法),代表使用标准运算符优先级规则评估表达式的结果(* 和 / 的优先级高于 + 和 -,运算符其余部分从左到右评估)。calc() 函数表示其所包含计算的结果。
计算的组件可以是字面值(例如 5px)、其他数学函数或其他评估为有效参数类型(如 <length>)的表达式,例如 var()。
数学函数可用于组合使用不同单位的值。在此示例中,作者希望每个部分的外边距盒子占据 1/3 的空间,因此他们从 100%/3 开始,然后减去元素的边框和外边距。(box-sizing 可以自动实现边框和内边距的此效果,但如果您想包括外边距,则需要一个数学函数。)
section{ float : left; margin : 1 em ; border : solid1 px ; width : calc ( 100 % /3 -2 *1 em -2 *1 px ); }
类似地,在此示例中,渐变将仅在元素的第一个和最后一个 20px 中显示颜色过渡。
.fade{ background-image : linear-gradient ( silver0 % , white20 px , whitecalc ( 100 % -20 px ), silver100 % ); }
数学函数也可以仅用于以更自然、可读的方式表达值,而不是作为晦涩的十进制。例如,以下设置 font-size,使得视口内恰好能容纳 35em,从而确保无论屏幕尺寸如何,屏幕上填充的文字量大致相同。
:root{ font-size : calc ( 100 vw /35 ); }
就功能而言,这与直接写 font-size: 2.857vw 没有区别,但意图(即 35em 填满视口)对于阅读代码的人来说就不那么清晰了;后来的阅读者将不得不自己反推数学计算,才能发现 2.857 是为了近似 100/35。
适用运算符的标准数学优先级规则:calc(2 + 3 * 4) 等于 14,而不是 20。
括号可用于控制优先级:calc((2 + 3) * 4) 反而等于 20。
括号和嵌套额外的 calc() 函数是等价的;前面的表达式也可以写成 calc(calc(2 + 3) * 4)。当通过 var() 逐步构建值时,这很有用,例如在以下示例中。
.aspect-ratio-box{ --ar : calc ( 16 /9 ); --w : calc ( 100 % /3 ); --h : calc ( var ( --w) /var ( --ar)); width : var ( --w); height : var ( --h); }
虽然 --ar 本来可以简单地写成 --ar: (16 / 9);,但 --w 既单独使用(在 width 中),也作为 calc() 的组件使用(在 --h 中),因此它本身必须写成一个完整的 calc() 函数。
10.2. 比较函数:min()、max() 和 clamp()
min()、max() 和 clamp() 的比较函数比较多个计算并表示其中一个的值。
min() 或 max() 函数包含一个或多个以逗号分隔的计算,并分别表示其中的最小值(最负)或最大值(最正)。
clamp() 函数接受三个计算——最小值、中间值和最大值——并表示其中心计算结果,根据其最小值和最大值计算进行截断,如果与最大值冲突,则优先考虑最小值。(也就是说,给定 clamp(MIN, VAL, MAX),它表示的值与 max(MIN, min(VAL, MAX)) 完全相同)。
最小值或最大值计算(甚至两者)都可以是关键字 none,这表示该值不受该侧的限制。(也就是说,clamp(MIN, VAL, none) 等同于 max(MIN, VAL),clamp(none, VAL, MAX) 等同于 min(VAL, MAX),而 clamp(none, VAL, none) 等同于 calc(VAL)。)
对于所有三个函数,参数计算可以解析为任何 <number>、<dimension> 或 <percentage>,但必须具有一致的类型,否则函数无效;结果的类型将是一致的类型。
min()、max() 和 clamp() 可用于确保值不超过“安全”限制:例如,设置了 font-size 且使用了视口单位的“响应式排版”可能仍需要最小尺寸以确保可读性。
.type{ /* Set font-size to 10x the average of vw and vh, but don’t let it go below 12px. */ font-size:max ( 10 *( 1 vw +1 vh ) /2 , 12 px ); }
注意: 每个参数都允许使用完整的数学表达式;无需在内部嵌套 calc()!如果你有多个约束要应用,也可以提供两个以上的参数。
.type{ /* Force the font-size to stay between 12px and 100px */ font-size:clamp ( 12 px , 10 *( 1 vw +1 vh ) /2 , 100 px ); }
或者,如果你只想强加一个最小尺寸,但允许字号增长到任意大小
.type{ /* Force the font-size to be at least 12px */ font-size:clamp ( 12 px , 10 *( 1 vw +1 vh ) /2 , none); }
如果需要其他解析机制,可以通过将 clamp() 与 min() 或 max() 组合来实现。
- 要让 MAX 胜过 MIN
-
clamp(min(MIN, MAX), VAL, MAX)。如果你想避免重复 MAX 计算,你只需反转 clamp() 定义所依据的函数嵌套顺序——min(MAX, max(MIN, VAL))。
- 要让 MAX 和 MIN 在顺序错误时“交换”
-
clamp(min(MIN, MAX), VAL, max(MIN, MAX))。不幸的是,如果不重复 MIN 和 MAX 项,没有简单的方法可以做到这一点。
10.3. 阶梯值函数:round()、mod() 和 rem()
阶梯值函数 round()、mod() 和 rem() 都会以不同的方式根据另一个“步长值”变换给定值。
round(<rounding-strategy>?, A, B?) 函数包含一个可选的舍入策略以及两个计算 A 和 B,并返回 A 的值,根据舍入策略舍入到 A 上方或下方的最接近 B 的整数倍。参数计算可以解析为任何 <number>、<dimension> 或 <percentage>,但必须具有一致的类型,否则函数无效;结果的类型将是一致的类型。
如果 A 正好等于 B 的整数倍,round() 解析为 A 本身(如果相关,保留 A 是 0⁻ 还是 0⁺)。否则,有两个 B 的整数倍可能“最接近” A,一个是更接近 −∞ 的下 B (lower B),一个是更接近 +∞ 的上 B (upper B)。以下 <rounding-strategy> 决定了如何在两者之间进行选择
- nearest
-
选择 lower B 和 upper B 中与 A 绝对差值最小的一个。如果两者差值相等(A 正好位于两个值之间),则选择 upper B。
- up
-
选择 upper B。
- down
-
选择 lower B。
- to-zero
-
选择 lower B 和 upper B 中与 0 的绝对差值最小的一个。
如果 lower B 为零,它特指 0⁺;如果 upper B 为零,它特指 0⁻。
如果省略 <rounding-strategy>,则默认为 nearest。(即舍入到最接近的整数。)如果 A 的类型与 <number> 匹配,则 B 可以省略,默认为 1;否则省略 B 是无效的。
CSSOM 需要指定其如何进行舍入,对于 CSS 函数来说,默认采用相同的舍入方式可能更好。应该使用什么行为? [Issue #5689]
注意: JavaScript 和其他编程语言有时会将舍入策略拆分为单独的舍入函数。JS 的 Math.floor() 等同于 CSS 的 round(down, ...);JS 的 Math.ceil() 等同于 CSS 的 round(up, ...);JS 的 Math.trunc() 等同于 CSS 的 round(to-zero, ...);而 JS 的 Math.round() 等同于 CSS 的 round(nearest, ...),或者直接简写为 round(...)。
注意: <rounding-strategy> 关键字与 block-step-size 中的关键字相同,且行为也相同。(block-step-size 只是缺少 to-zero;因为块大小总是非负的,to-zero 和 down 将是完全相同的。)
模运算函数 mod(A, B) 和 rem(A, B) 同样包含两个计算 A 和 B,并返回 A 与 A 上方或下方最接近 B 的整数倍之间的差值。参数计算可以解析为任何 <number>、<dimension> 或 <percentage>,但必须具有相同的类型,否则函数无效;结果将与参数具有相同的类型。
这两个函数非常相似,实际上,如果两个参数都为正或都为负,它们返回的结果是完全相同的:函数的值等于 A 被偏移 B 的整数倍后的值,使值位于零和 B 之间。(具体来说,该范围包括零但不包括 B。更具体地说,如果 B 为正,范围从 0⁺ 开始;如果 B 为负,范围从 0⁻ 开始。)
类似地,mod(-140deg, -90deg) 解析为值 -50deg,因为向 -140deg 添加 -90deg * 1 得到 -50deg,这是唯一位于 0deg 和 -90deg 之间的此类值。
使用 rem() 评估这两个示例中的任何一个都会得到完全相同的结果。
如果 A 值和 B 步长位于零的两侧,它们的行为就会分歧:mod()(“模数”的缩写)继续选择 B 的整数倍,使值位于零和 B 之间,如上所述(保证结果要么为零,要么与 B 共享符号,而不是 A);而 rem()(“余数”的缩写)选择 B 的整数倍,使值位于零和 -B 之间,避免改变值的符号。
另一方面,rem(-18px, 5px) 解析为值 -3px:向 -18px 添加 5px * 3 得到 -3px,它的符号与 -18px 相同,但位于 0px 和 -5px 之间。
类似地,mod(140deg, -90deg) 解析为值 -40deg(向 140deg 添加 -90deg * 2,使其位于 0deg 和 -90deg 之间),但 rem(140deg, -90deg) 解析为值 50deg。
什么时候应该选择 mod() 与 rem()?
通常,此操作的用户可以控制步长值 (B),并且正在修改一个未知的 A 值。因此,无论 A 的符号如何,结果在 0 和 B 之间通常更符合预期,这意味着应该选择 mod()。
例如,如果作者想知道一个长度是偶数还是奇数像素,mod(A, 2px) 将返回 0px 或 1px(假设该值一开始就是整数像素),无论 a 的值是多少。另一方面,rem(A, 2px) 如果 A 是偶数像素将返回 0px,但如果它是奇数像素,则会根据 A 是正数还是负数返回 1px 或 -1px。
然而,相反的情况确实有时会发生,因此提供了 rem() 来满足该需求。同样,rem() 是 JavaScript 的 % 运算符的行为,因此如果希望 CSS 代码和 JS 代码完全匹配,rem() 会很有用。
注意: mod() 和 rem() 也可以直接根据其他函数来定义:mod(A, B) 等同于 calc(A - sign(B)*round(down, A*sign(B), B))(这是一种当 B 为正时使用 round(down),当 B 为负时使用 round(up) 的取巧方法),而 rem(A, B) 等同于 calc(A - round(to-zero, A, B))。(不过,这些表达式并不总是能正确处理 0⁺ 和 0⁻,因为 0⁻ 的语义在加法上不满足交换律。)
10.3.1. 参数范围
在 round(A, B) 中,如果 B 为 0,则结果为 NaN。如果 A 和 B 均为无穷大,则结果为 NaN。
如果 A 是无穷大但 B 是有限的,结果就是同样的无穷大。
如果 A 是有限的但 B 是无穷大,结果取决于 <rounding-strategy> 和 A 的符号。
- nearest
- to-zero
-
如果 A 为正或 0⁺,则返回 0⁺。否则,返回 0⁻。
- up
-
如果 A 为正(非零),则返回 +∞。如果 A 为 0⁺,则返回 0⁺。否则,返回 0⁻。
- down
-
如果 A 为负(非零),则返回 −∞。如果 A 为 0⁻,则返回 0⁻。否则,返回 0⁺。
在 mod(A, B) 或 rem(A, B) 中,如果 B 为 0,结果为 NaN。如果 A 为无穷大,结果为 NaN。
仅在 mod(A, B) 中,如果 B 为无穷大且 A 的符号与 B 相反(包括符号相反的零),则结果为 NaN。
注意: 所有其他“无穷大 B”的情况都是有效的,并且立即返回 A。
10.4. 三角函数:sin()、cos()、tan()、asin()、acos()、atan() 和 atan2()
三角函数——sin()、cos()、tan()、asin()、acos()、atan() 和 atan2()——计算各种基本的三角关系。
sin(A)、cos(A) 和 tan(A) 函数都包含一个计算,该计算必须解析为 <number> 或 <angle>,并通过将参数的结果解释为弧度来计算其对应函数。(也就是说,sin(45deg)、sin(.125turn) 和 sin(3.14159 / 4) 都表示相同的值,约为 .707。)它们都表示一个 <number>,返回类型与输入计算的类型一致。sin() 和 cos() 将始终返回 -1 到 1 之间的数字,而 tan() 可以返回 -∞ 到 +∞ 之间的任何数字。(有关数学函数如何处理 ∞ 的详细信息,请参阅 § 10.9 类型检查。)
asin(A)、acos(A) 和 atan(A) 函数是“反正”三角函数,表示其对应“正常”三角函数的反函数。它们都包含一个计算,该计算必须解析为 <number>,计算其对应函数,将结果解释为弧度数,表示一个返回类型与输入计算的类型一致的 <angle>。asin() 返回的角度必须归一化到 [-90deg, 90deg] 范围内;acos() 返回的角度归一化到 [0deg, 180deg] 范围内;atan() 返回的角度归一化到 [-90deg, 90deg] 范围内。
atan2(A, B) 函数包含两个以逗号分隔的计算 A 和 B。A 和 B 可以解析为任何 <number>、<dimension> 或 <percentage>,但必须具有一致的类型,否则函数无效。该函数返回正 X 轴与点 (B,A) 之间的 <angle>,其返回类型与输入计算的类型一致。返回的角度必须归一化到 (-180deg, 180deg] 区间内(即大于 -180deg 且小于或等于 180deg)。
注意: atan2(Y, X) 通常等同于 atan(Y / X),但在涉及负数组件的点时,它能提供更好的答案。atan2(1, -1) 对应于点 (-1, 1),返回 135deg,这与对应于点 (1, -1) 的 atan2(-1, 1) 返回的 -45deg 不同。相比之下,atan(1 / -1) 和 atan(-1 / 1) 都返回 -45deg,因为内部计算对两者都解析为 -1。
10.4.1. 参数范围
在 sin(A)、cos(A) 或 tan(A) 中,如果 A 是无穷大,则结果为 NaN。(有关数学函数如何处理 NaN 的详细信息,请参阅 § 10.9 类型检查。)
在 sin(A) 或 tan(A) 中,如果 A 是 0⁻,则结果为 0⁻。
在 tan(A) 中,如果 A 是渐近线值之一(例如 90deg, 270deg 等),则数值结果是实现定义的。如果实现能够精确表示这些输入,它应该对 的渐近线返回 +∞,对 的渐近线返回 -∞,但实现并不要求能够精确表示这些输入(如果不能,将返回其能够表示的最接近输入的正确数值答案)。作者不得依赖 tan() 为这些输入返回任何特定值。
为什么这些是实现定义的?
正切函数在其渐近线处是不连续的:它从一侧趋向无穷大,从另一侧趋向负无穷大,并且在渐近线的确切值处没有定义。
此外,渐近值在实现中是否可精确表示,取决于它们内部存储和处理角度的方式;以度数书写时,这些值很简单(90deg 等),但以弧度表示时,这些值是超越数(pi / 2 等),无法精确表示。因此,即使定义这些值的特定行为也很困难;如果实现内部使用弧度,当输入足够接近渐近线时,它将不得不执行一些模糊匹配来返回定义的值。
Web 的另一种主要语言 JavaScript 仅公开接受弧度的这些函数,因此它也无法触及确切的渐近线(大多数其他计算机语言也是如此)。因此,在 JS 中编写代码的作者也无法依赖这些值的任何特定行为,并且他们在 CSS 中的需求与此显著不同的可能性很小。
对于能够精确表示渐近值的实现,建议的行为是保留与 atan() 函数的往返转换:给定此定义,tan(atan(X)) 和 atan(tan(X)) 对于所有可能的 X 值都将(大约)返回 X。这也意味着在 atan() 支持的输出范围内,该函数是连续的。
在 asin(A) 或 acos(A) 中,如果 A 小于 -1 或大于 1,结果为 NaN。
在 acos(A) 中,如果 A 正好为 1,结果为 0。
在 asin(A) 或 atan(A) 中,如果 A 为 0⁻,结果为 0⁻。
在 atan(A) 中,如果 A 为 +∞,结果为 90deg;如果 A 为 −∞,结果为 -90deg。
在 atan2(Y, X) 中,下表给出了所有特殊参数组合的结果。
| X | |||||||
|---|---|---|---|---|---|---|---|
| −∞ | -有限值 | 0⁻ | 0⁺ | +有限值 | +∞ | ||
| Y | −∞ | -135deg | -90deg | -90deg | -90deg | -90deg | -45deg |
| -有限值 | -180deg | (正常) | -90deg | -90deg | (正常) | 0⁻deg | |
| 0⁻ | -180deg | -180deg | -180deg | 0⁻deg | 0⁻deg | 0⁻deg | |
| 0⁺ | 180deg | 180deg | 180deg | 0⁺deg | 0⁺deg | 0⁺deg | |
| +有限值 | 180deg | (正常) | 90deg | 90deg | (正常) | 0⁺deg | |
| +∞ | 135deg | 90deg | 90deg | 90deg | 90deg | 45deg | |
注意: 所有这些行为都旨在匹配大多数编程语言(特别是 JS)所实现的这些函数的“标准”定义。
10.5. 指数函数:pow()、sqrt()、hypot()、log()、exp()
指数函数——pow()、sqrt()、hypot()、log() 和 exp()——利用它们的参数计算各种指数函数。
pow(A, B) 函数包含两个以逗号分隔的计算 A 和 B,两者都必须解析为 <number>,并返回将 A 提高到 B 次幂的结果,以 <number> 的形式返回该值。输入计算必须具有一致的类型,否则函数无效;结果的类型将是一致的类型。
sqrt(A) 函数包含一个计算,该计算必须解析为 <number>,并以 <number> 的形式返回该值的平方根,返回类型与输入计算的类型一致。(sqrt(X) 和 pow(X, .5) 基本等效,仅在某些错误处理上有所不同;sqrt() 是一个相当常用的函数,作为便利功能提供。)
hypot(A, …) 函数包含一个或多个以逗号分隔的计算,并返回一个 N 维向量的长度,该向量的分量等于每个计算。(也就是说,各参数平方和的平方根。)参数计算可以解析为任何 <number>、<dimension> 或 <percentage>,但必须具有一致的类型,否则函数无效;结果的类型将是一致的类型。
为什么 hypot() 允许维度(带有单位的值),而 pow() 和 sqrt() 仅适用于数字?
允许编写像 hypot(30px, 40px) 这样的表达式(解析为 50px),但不允许编写表达式 sqrt(pow(30px, 2) + pow(40px, 2)),尽管在大多数数学系统中这两者是等价的。
原因有两个:指数中的数值精度,以及作者相互冲突的期望。
首先是数值精度。为了使类型匹配像 <length> 这样的 CSS 生产规则,它需要有一个单位,其指数必须精确设置为 1。从理论上讲,像 pow(pow(30px, 3), 1/3) 这样的表达式应该正好得到这个结果:内部的 pow(30px, 3) 将解析为一个值为 27000 且类型为 «[ "length" → 3 ]»(又称 <length>³)的值,然后 pow(X, 1/3) 会将该值进行立方根运算并把指数乘以 1/3,得到 «[ "length" → 1 ]»,这与 <length> 匹配。
在纯数学领域,这肯定行得通;但在使用二进制浮点算术的现实计算机世界中,在某些情况下幂次可能无法完全抵消,从而由于令人困惑且难以追踪的原因留下一个无效的数学函数。(对于 JS 示例,计算 Math.pow(Math.pow(30, 10/3), .1+.1+.1);结果并不完全等于 30,因为 .1+.1+.1 并不完全等于 3/10。相反,(10/3) * (.1 + .1 + .1) 略大于 1。)
要求作者将值转换为数字,对原始数字进行所有数学运算,最后将其传回所需的单位,虽然不方便,但确保了数值精度不会困扰任何人:calc(pow(pow(30px / 1px, 3), 1/3) * 1px) 保证解析为 <length>,即使由于数值精度实际阻止了幂次完全抵消,其值如果不是精确的 30,至少也非常接近 30。
其次是相互冲突的期望。作者期望 pow(30px, 2) 产生 900px(例如在 此 Sass 问题 中)并不罕见;也就是说,只对数值进行平方运算,而保留单位不变。然而,这意味着结果取决于你用什么单位来表示参数;如果 1em 是 16px,那么 pow(1em, 2) 将得到 1em,而 pow(16px, 2) 将得到 256px 或 16em,对于本应相同的输入参数,它们是截然不同的值!这种输入依赖性对 CSS 来说是个麻烦,因为 CSS 通常允许值被自由地规范化;这也使得更复杂的表达式(如 pow(2em + 10px, 2))难以解释。
同样,要求作者将值转换为数字,然后再转回所需的单位避开了这些问题;pow(30, 2) 确实是 900,作者可以随心所欲地解释它。
另一方面,hypot() 不存在这些问题。单位的数值精度不是一个问题,因为输入和输出具有相同的类型。由于该操作的性质,结果也不依赖于单位;当 1em 等于 16px 时,hypot(3em, 4em) 和 hypot(48px, 64px) 都会产生相同的长度:5em 或 80px。因此,直接允许作者在 hypot() 中使用维度是可以的。
log(A, B?) 函数包含一个或两个计算(表示要取对数的值以及对数的底,底默认为 e),这些计算必须解析为 <number>,并返回值 A 以 B 为底的对数,作为 <number>,其返回类型与输入计算的类型一致。
exp(A) 函数包含一个计算,该计算必须解析为 <number>,并返回与 pow(e, A) 相同的值,作为 <number>,其返回类型与输入计算的类型一致。
这些大小可以轻松写入自定义属性,如
:root{ --h6 : calc ( 1 rem *pow ( 1.5 , -1 )); --h5 : calc ( 1 rem *pow ( 1.5 , 0 )); --h4 : calc ( 1 rem *pow ( 1.5 , 1 )); --h3 : calc ( 1 rem *pow ( 1.5 , 2 )); --h2 : calc ( 1 rem *pow ( 1.5 , 3 )); --h1 : calc ( 1 rem *pow ( 1.5 , 4 )); }
...而不是写出像 5.0625rem(calc(1rem * pow(1.5, 4)) 所解析的结果)这样预先计算好的数值,当在样式表中遇到它们时,这些数值的来源较不清晰。
使用更多参数时,它给出以参数为边长的盒子的主对角线长度。这对于与变换相关的事情很有用,给出了元素通过特定 X、Y 和 Z 量平移时实际行进的距离。
例如,hypot(30px, 40px) 解析为 50px,这确实是元素在被 translate(30px, 40px) 变换平移时其起始位置和结束位置之间的距离。如果作者希望元素在远离起始点时变小(例如绘制某种文字云),他们可以在缩放因子计算中使用这个距离。
如果改为需要以 10 为底的对数(例如,计算数值中的数字位数)或以 2 为底的对数(计算数值中的位数),log(X, 10) 或 log(X, 2) 提供这些值。
10.5.1. 参数范围
在 pow(A, B) 中,如果 A 为负且有限,且 B 为有限值,则 B 必须是整数,否则结果为 NaN。
如果 A 或 B 为无穷大或 0,下表给出了结果。
| A 为 −∞ | A 为 0⁻ | A 为 0⁺ | A 为 +∞ | |
|---|---|---|---|---|
| B 为 −有限值 | 如果 B 是奇整数则为 0⁻,否则为 0⁺ | 如果 B 是奇整数则为 −∞,否则为 +∞ | +∞ | 0⁺ |
| B 为 0 | 总是 1 | |||
| B 为 +有限值 | 如果 B 是奇整数则为 −∞,否则为 +∞ | 如果 B 是奇整数则为 0⁻,否则为 0⁺ | 0⁺ | +∞ |
| A < -1 | A 为 -1 | -1 < A < 1 | A 为 1 | A > 1 | |
|---|---|---|---|---|---|
| B 为 +∞ | 结果为 +∞ | 结果为 NaN | 结果为 0⁺ | 结果为 NaN | 结果为 +∞ |
| B 为 −∞ | 结果为 0⁺ | 结果为 NaN | 结果为 +∞ | 结果为 NaN | 结果为 0⁺ |
在 sqrt(A) 中,如果 A 为 +∞,结果为 +∞。如果 A 为 0⁻,结果为 0⁻。如果 A 小于 0,结果为 NaN。
在 hypot(A, …) 中,如果任何输入为无穷大,结果为 +∞。
在 log(A, B) 中,如果 B 为 1 或负数( 介于 0 和 1 之间或大于 1 的 B 值是有效的。 ),则结果为 NaN。如果 A 为负数,结果为 NaN。如果 A 为 0⁺ 或 0⁻,结果为 −∞。如果 A 为 1,结果为 0⁺。如果 A 为 +∞,结果为 +∞。
在 exp(A) 中,如果 A 为 +∞,结果为 +∞。如果 A 为 −∞,结果为 0⁺。
(有关数学函数如何处理 NaN 和无穷大的详细信息,请参阅 § 10.9 类型检查。)
与等效 JS 函数行为的唯一分歧在于 NaN 在每个函数中都具有“传染性”,如果任何参数计算为 NaN,则强制函数返回 NaN。
JS 行为细节
在 JS 中有两个 NaN 不会对其所属数学函数产生“传染”的情况
-
Math.hypot(Infinity, NaN)将返回Infinity。 -
Math.pow(NaN, 0)将返回1。
逻辑似乎是,如果你用任何数字替换 NaN,返回值将是相同的。然而,此逻辑并没有一致地应用于 Math 函数:Math.max(Infinity, NaN) 返回 NaN,而不是 Infinity;Math.min(-Infinity, NaN) 也是如此。
由于这是一个错误的边缘情况,JS 在此问题上并不一致,而且 NaN 的识别/处理可能是在 CSS 较高层级完成的,而不是在内部数学函数中完成的,因此选择了 CSS 的一致性,即所有函数都被定义为具有“传染性”的 NaN。
10.6. 符号相关函数:abs()、sign()
符号相关函数——abs() 和 sign()——计算与参数符号相关的各种函数。
abs(A) 函数包含一个计算 A,并返回 A 的绝对值,类型与输入相同:如果 A 的数值为正或 0⁺,则仍为 A;否则为 -1 * A。
sign(A) 函数包含一个计算 A,如果 A 的数值为负,则返回 -1;如果 A 的数值为正,则返回 +1;如果 A 的数值为 0⁺,则返回 0⁺;如果 A 的数值为 0⁻,则返回 0⁻。返回类型为 <number>,与输入计算的类型一致。
注意: 这两个函数都作用于其参数完全简化/解析后的形式,这乍一看可能会产生违反直觉的结果。特别是,像 10% 这样的表达式一旦解析,可能是正的或负的,具体取决于它所针对解析的值。例如,在 background-position 中,如果背景图像大于背景区域,则正百分比解析为负长度,反之亦然。因此 sign(10%) 可能会返回 1 或 -1,具体取决于百分比是如何解析的!(如果针对零长度进行解析,甚至可能返回 0。)
10.7. 数值关键字
计算中的关键字提供了对作为字面值难以或无法表示的值的访问。每个关键字都定义了它的值、它的类型,以及何时可以对其进行解析。
10.7.1. 数值常量:e、pi
虽然三角函数和指数函数处理了许多复杂的数值运算,但一些合理的计算必须更手动地组合在一起,很多时候这些计算包含众所周知的常数,例如 e 和 π。
与其要求作者手动键入这些常数的几位数字,不如直接提供其中的几个。
- e
-
自然对数的底,约等于 2.7182818284590452354。
- pi
-
圆的周长与直径之比,约等于 3.1415926535897932。
这两个关键字都是 <number>,并在解析时解析。
注意: 这些关键字只能在计算中使用,例如 calc(pow(e, pi) - pi) 或 min(pi, 5, e)。如果用在计算之外,它们被视为任何其他关键字:animation-name: pi; 指的是名为“pi”的动画;line-height: e; 是无效的(不类似于 line-height: 2.7,但 line-height: calc(e); 是有效的)。
10.7.2. 退化数值常量:infinity、-infinity、NaN
当一个 计算 或 计算 的子树变为 无限大 或 NaN 时,就不可能再用数值来表示它了。为了辅助这些退化值的序列化,定义了以下额外的数学常量:
- infinity
-
正无穷大值 (+∞)
- -infinity
-
负无穷大值 (−∞)
- NaN
-
NaN 值
所有这些关键字都是 <number>,并在解析时解析。
按照 CSS 关键字的惯例,这些关键字是 ASCII 大小写不敏感的。 因此,calc(InFiNiTy) 是完全有效的。 但是,NaN 必须使用此规范中的大小写形式进行序列化。
注意:由于这些关键字是 <number>,例如要获得无限长度,需要类似 calc(infinity * 1px) 的表达式。
注意:定义这些常量主要是为了使无限/NaN 值的序列化更简单、更直观,但它们可以用来表示“最大可能值”,因为无限值会被截断到允许的范围内。这种情况很少合理,但如果确实需要,使用 infinity 比在样式表中仅仅输入一个巨大的数字意图更清晰。
10.7.3. 数值变量
其他规范可以定义在特定上下文中可用于 计算 的附加关键字。例如,相对颜色语法定义了许多颜色通道关键字,这些关键字将每个颜色通道的值表示为 <number>。
每个定义此类关键字的规范必须为每个关键字定义:
10.8. 语法
数学函数的语法为:
<calc () > =calc ( <calc-sum>) <min () > =min ( <calc-sum>#) <max () > =max ( <calc-sum>#) <clamp () > =clamp ( [ <calc-sum> | none] , <calc-sum>, [ <calc-sum> | none] ) <round () > =round ( <rounding-strategy>?, <calc-sum>, <calc-sum>?) <mod () > =mod ( <calc-sum>, <calc-sum>) <rem () > =rem ( <calc-sum>, <calc-sum>) <sin () > =sin ( <calc-sum>) <cos () > =cos ( <calc-sum>) <tan () > =tan ( <calc-sum>) <asin () > =asin ( <calc-sum>) <acos () > =acos ( <calc-sum>) <atan () > =atan ( <calc-sum>) <atan2 () > =atan2 ( <calc-sum>, <calc-sum>) <pow () > =pow ( <calc-sum>, <calc-sum>) <sqrt () > =sqrt ( <calc-sum>) <hypot () > =hypot ( <calc-sum>#) <log () > =log ( <calc-sum>, <calc-sum>?) <exp () > =exp ( <calc-sum>) <abs () > =abs ( <calc-sum>) <sign () > =sign ( <calc-sum>) <calc-sum> = <calc-product>[ [ '+' |'-' ] <calc-product>] * <calc-product> = <calc-value>[ [ '*' |'/' ] <calc-value>] * <calc-value> = <number> | <dimension> | <percentage> | <calc-keyword> |( <calc-sum>) <calc-keyword> = e | pi | infinity | -infinity | NaN <rounding-strategy> = nearest | up | down | to-zero
在某些上下文中,可以定义附加的 <calc-keyword> 值作为有效值。(例如,在 相对颜色语法中,允许使用适当的通道关键字。)
此外,空格是必需的,位于 + 和 - 运算符的两侧。(* 和 / 运算符周围可以使用空格,也可以不使用。)
上述几个数学函数对其 <calc-sum> 参数所包含的内容有额外的限制。详情请查看各函数的定义。
用户代理(UA)必须支持至少 32 个 <calc-value> 项和至少 32 层嵌套(括号和/或函数)的 计算。对于支持任意数量参数的函数(例如 min()),也必须支持至少 32 个参数。如果一个 计算 包含的项、参数或嵌套数量超过支持的上限,则必须将其视为无效。
10.9. 类型检查
数学函数可以有多种可能的类型,如 <length>、<number> 等,具体取决于其包含的 计算(定义如下)。它可以用于任何允许该类型值的地方。
此外,解析为 <number> 的 数学函数可以在任何只接受 <integer> 的地方使用;该值在解析时会被 四舍五入到最接近的整数。
运算符构成子表达式,这些子表达式根据其参数获得类型。
注意:在本规范的先前版本中,乘法和除法对其参数有限制,以避免产生更复杂的中间结果(例如 1px * 1em,即 <length>²)并使除以零在解析时可检测。此版本现已放宽这些限制。
-
在 + 或 - 子表达式处,尝试 将左参数和右参数的类型相加。如果返回失败,则整个 计算 的类型为失败。否则,子表达式的 类型 为返回的类型。
-
在 * 子表达式处,将左参数和右参数的类型相乘。子表达式的 类型 为返回的结果。
-
在 / 子表达式处,令 左类型 为查找其左参数 类型 的结果,令 右类型 为查找其右参数的 类型 结果,然后进行 求逆。
-
其他任何情况都是终点值,其 类型 根据其 CSS 类型确定。(除非另有说明,否则该类型关联的 百分比提示 为空。)
- <number>(数字)
- <integer>(整数)
-
类型 为 «[ ]»(空映射)
- <length>(长度)
-
类型 为 «[ "length" → 1 ]»
- <angle>(角度)
-
类型 为 «[ "angle" → 1 ]»
- <time>(时间)
-
类型 为 «[ "time" → 1 ]»
- <frequency>(频率)
-
类型 为 «[ "frequency" → 1 ]»
- <resolution>
-
类型 为 «[ "resolution" → 1 ]»
- <flex>
-
类型 为 «[ "flex" → 1 ]»
- <calc-keyword>
-
类型 由关键字定义
- <percentage>(百分比)
-
如果包含此 计算 的 数学函数 所处的上下文中,<percentage> 是相对于另一种类型的值进行解析的(例如在 width 中,<percentage> 是相对于 <length> 解析的),且该其他类型不是 <number>,则 类型 被确定为该其他类型,但设置了一个指向该其他类型的 百分比提示。
否则,类型 为 «[ "percent" → 1 ]»。
- 其他任何情况
-
计算 的类型为失败。
- calc()
- abs()
- min()
- max()
- clamp()
- hypot()
- round()
- mod()
- rem()
- asin()
- acos()
- atan()
- atan2()
-
«[ "angle" → 1 ]»。
- sign()
- sin()
- cos()
- tan()
- pow()
- sqrt()
- log()
- exp()
-
«[ ]»(空映射)。
一个 数学函数 根据其 类型 匹配 的产生式,解析为 <number>、<length>、<angle>、<time>、<frequency>、<resolution>、<flex> 或 <percentage>。(这些类别是互斥的。)如果它无法 匹配 其中任何一个,则该 数学函数 无效。
注意:代数简化不会影响 数学函数 的有效性或其解析后的类型。例如,calc(5px - 5px + 10s) 和 calc(0 * 5px + 10s) 均因尝试将长度和时间相加而无效。
注意:请注意,<percentage> 相对于 <number>(例如在 opacity 中)是不可结合的——opacity: calc(.25 + 25%) 是无效的。允许这样做会导致“单位代数”(允许 <dimension> 的乘法/除法)出现严重问题,而且到目前为止,在任何情况下都无法提供任何新的功能。(例如,opacity: 25% 与 opacity: .25 相同;这只是一个微不足道的语法转换。)您仍然可以对它们执行其他操作,例如 opacity: calc(100% / 3);,这是有效的。
注意:由于 <number-token> 总是被解释为 <number> 或 <integer>,因此在 数学函数 中不支持“无单位 0”的 <length>。也就是说,width: calc(0 + 5px); 是无效的,因为它试图将 <number> 加到 <length> 上,即使 width: 0; 和 width: 5px; 都是有效的。
注意:虽然有少数属性在“使用值时间”将裸 <number> 变为 <length>(具体而言是 line-height 和 tab-size),但在 calc() 中 <number> 永远不会变成“类似长度的”。它们始终保持为 <number>。
注意:在怪异模式 [QUIRKS] 中,某些通常只接受 <length> 的属性也被定义为接受 <number>,并将它们解释为 px 长度。与无单位零一样,这对比 数学函数 的解析或行为没有影响,尽管解析为 <number> 值的 数学函数 在怪异模式下可能变得有效(并将其结果解释为 px 长度)。
10.9.1. 无穷大、NaN 和带符号的零
数学函数遵循 IEEE-754 语义,这意味着它们识别正零和负零、正无穷大和负无穷大以及 NaN(非数字)的概念。
然而,这些概念仅在 计算树 内保留;如果一个 顶层计算(不是直接嵌套在另一个 数学函数 内部的 数学函数)会导致这些特殊值中的一个,它们将被“审查”为标准的、可表示的值,定义如下。
带符号的零(此处表示为 0⁺ 或 0⁻)不能直接在 CSS 中书写;0、+0 和 -0 都会产生标准的“无符号”零,对于这些规则而言,它被认为是正数(0⁺)。
带符号的零通过以下方式产生:
-
负零 (0⁻) 可以由一个恰好有一个负参数的乘法或除法产生(例如 -5 * 0 或 1 / -infinity)。
-
0⁻ + 0⁻ 或 0⁻ - 0⁺ 产生 0⁻。所有其他可能产生零的加法或减法都会产生 0⁺。
-
将 0⁻ 与正数(包括 0⁺)相乘或相除会产生负结果(0⁻ 或 −∞),而将 0⁻ 与负数相乘或相除会产生正结果。
(换句话说,与 0⁻ 进行乘法或除法遵循标准的符号规则。)
-
当比较 0⁺ 和 0⁻ 时,0⁻ 小于 0⁺。例如,min(0⁺, 0⁻) 必须产生 0⁻,max(0⁺, 0⁻) 必须产生 0⁺,clamp(0⁺, 0⁻, 1) 必须产生 0⁺。
-
数学函数中的某些参数组合被定义为产生 0⁻(例如 round(-1, infinity))。所有其他产生零的操作都会产生正零 (0⁺)。
无穷大(此处表示为 +∞ 或 −∞)可以直接使用 数学常量 infinity 和 -infinity 书写,或作为某些计算的结果产生:
-
根据标准符号规则,将一个值除以零产生 +∞ 或 −∞。
-
将 ±∞ 加到任何值或从中减去任何值都会产生相应的无穷大。
-
将任何值与 ±∞ 相乘都会产生相应的无穷大。
-
将任何值除以 ±∞ 都会产生零。
注意:下面关于产生 NaN 的规则优于上述产生 无穷大 的规则。
无穷大不会逃脱 顶层计算;它们会被截断到目标上下文中允许的最小值或最大值,定义见 § 10.12 范围检查。
NaN(“not a number”的缩写)是某些没有明确定义值的操作的结果。它可以直接使用 数学常量 NaN 书写,或作为某些计算的结果产生:
-
零除以零、±∞ 除以 ±∞、0 乘以 ±∞、+∞ 加 −∞,或两个相同符号的无穷大相减,都会产生 NaN。
如果存在冲突,这些规则将覆盖任何其他结果。例如,0 / 0 是 NaN,而不是 +∞。
-
任何包含至少一个 NaN 参数的操作都会产生 NaN。
另一方面,calc(1 / calc(-5 * 0)) 产生 −∞,与 calc(1 / (-5 * 0)) 相同——内部计算解析为 0⁻,由于它不是 顶层计算,它将原样传递给外部计算以产生 −∞。如果它被审查为无符号零,它反而会产生 +∞。
10.10. 内部表示
数学函数的 内部表示 是一个 计算树:一个树状结构,其分支节点是对应于 数学函数(如 Min、Cos、Sqrt 等)或 计算(Sum、Product、Negate 和 Invert,即 计算运算符节点)中运算符的 运算符节点;叶子节点是数值(如数字、维度和百分比)或解析为数值类型的非 数学函数。
-
从 值 中丢弃所有 <whitespace-token>。
-
如果 值 中的项是值为 "+", "-", "*" 或 "/" 的 <delim-token>,则它是一个“运算符”。否则,它是一个“值”。
-
将子项收集到 Product 和 Invert 节点中。
对于 值 中被 "*" 或 "/" 运算符分隔的每一段连续值项:
-
对于该段中的每个 "/" 运算符,将其右侧的值项 rhs 替换为一个包含 rhs 作为其子项的 Invert 节点。
-
将整段替换为一个 Product 节点,包含该段的值项作为其子项。
-
-
将子项收集到 Sum 和 Negate 节点中。
-
对于 值 中的每个 "-" 运算符项,将其右侧的值项 rhs 替换为一个包含 rhs 作为其子项的 Negate 节点。
-
如果 值 只有一个项,且它是一个 Product 节点或带括号的 简单块,则将 值 替换为该项。
否则,将 值 替换为一个 Sum 节点,包含 值 的值项作为其子项。
-
-
此时,值 是一棵由 Sum、Product、Negate 和 Invert 节点组成的树,其他类型的值在叶子节点处。处理叶子节点。
对于 值 中的每个叶子节点 leaf:
-
返回从 值 简化计算树 的结果。
10.10.1. 简化
数学函数的 内部表示 会使用标准的代数简化(将乘法分配到加法上、组合相似单位等)尽可能地进行预简化。
当在非属性上下文(例如 @font-face 描述符中)使用时,数学函数 被视为 指定值 进行简化。
-
如果 根节点 是数值:
-
如果 根节点 是一个将相对于另一个值解析的百分比,并且有足够的信息来解析它,则执行解析,并将结果数值以适当的 规范单位 表示。返回该值。
-
如果 根节点 是一个未以其 规范单位 表示的维度,且有足够的信息将其转换为 规范单位,则执行转换并返回该值。
-
如果 根节点 是一个可以解析的 <calc-keyword>,则返回其解析后的 简化 值。
-
否则,返回 根节点。
-
-
如果 根节点 是任何其他叶子节点(非运算符节点):
-
如果有足够的信息确定其数值,则返回该值,并以其 规范单位 表示。
-
否则,返回 根节点。
-
-
如果 根节点 是一个非 计算运算符节点 的 运算符节点,且其所有 计算 子项都是带有足够信息来计算 根节点 所代表运算的数值,则返回使用其子项运行 根节点 运算的结果,并以结果的 规范单位 表示。
如果此时剩余一个百分比,它通常会阻碍节点的简化,因为它需要使用当前不可用的信息相对于另一个值进行解析。(否则,它会在更早的步骤中转换为其他值。)这包括“min”等运算,因为百分比可能会相对于负基数进行解析,从而导致与原始百分比值所暗示的比较关系相反。
然而,“原始”百分比——即不相对于另一个值解析的百分比,例如在 opacity 中——可能不会阻碍简化。
-
如果 根节点 是一个 Min 或 Max 节点,尝试部分简化它:
-
对于每个 子节点(根节点 的子项):
如果 子节点 是一个具有足够信息来与相同单位的另一个子项比较大小的数值,且 根节点 有其他单位相同的数值子项,则使用适当的运算符按照 根节点 的逻辑组合所有这些子项,并用结果替换 子节点,移除所有其他相关的子节点。
-
如果 根节点 只有一个子项,则返回该子项。
否则,返回 根节点。
-
-
如果 根节点 是一个 Negate 节点:
-
如果 根节点 的子项是数值,返回一个等效的数值,但值取反(0 - value)。
-
如果 根节点 的子项是 Negate 节点,则返回该子项的子项。
-
返回 根节点。
-
-
如果 根节点 是一个 Invert 节点:
-
如果 根节点 的子项是数字(而非百分比或维度),则返回其子项值的倒数。
-
如果 根节点 的子项是 Invert 节点,则返回该子项的子项。
-
返回 根节点。
-
-
如果 根节点 是一个 Sum 节点:
-
对于 根节点 中每一个是 Sum 节点的子项,用其子项替换它们。
-
对于 根节点 中单位相同的每一组数值子项,移除这些子项,并用一个包含这些被移除节点之和、且具有相同单位的单一数值替换它们。
(例如:组合数字、组合百分比、组合 px 值等。)
-
如果此时 根节点 只有一个子项,则返回该子项。否则,返回 根节点。
注意:零值项不能简单地从 Sum 中移除;它们只能与具有相同单位的其他值组合。(这是因为单位的存在,即使值是零,有时也暗示着行为的改变。)
-
-
如果 根节点 是一个 Product 节点:
-
对于 根节点 中每一个是 Product 节点的子项,用其子项替换它们。
-
如果 根节点 有多个数字(而非百分比或维度)子项,移除它们并用一个包含这些被移除节点乘积的单一数字替换。
-
如果 根节点 仅包含两个子项,其中一个是数字(而非百分比或维度),另一个是一个其子项均为数值的 Sum,则将 Sum 的所有子项乘以该数字,然后返回该 Sum。
-
如果 根节点 仅包含数值和/或包含数值的 Invert 节点,且将所有子项的 类型相乘(注意 Invert 节点的类型是其子项类型的 逆)的结果类型 匹配 数学函数 可解析的任何类型,则返回所有子项相乘的结果(注意 Invert 节点的值是其子项值的倒数),并以结果的 规范单位 表示。
-
返回 根节点。
-
10.11. 计算值
数学函数的 计算值 是其使用 计算值 时间可用的所有信息(如 em 到 px 的比率、如何在某些属性中解析百分比等)简化 后的 计算树。
在计算值时间不解析百分比的地方,它们在 数学函数 中也不会被解析,例如 calc(100% - 100% + 1px) 解析为 calc(0% + 1px),而不是 1px。如果某值中存在计算百分比的特殊规则(例如 height 属性),只要 数学函数 包含百分比,它们就会适用。
计算树会在 使用值 时间再次简化;利用 使用值 时间的信息,数学函数 总是简化为一个单一的数值。
因此,background-position 的计算在 calc() 中保留百分比,而 font-size 会直接将此类表达式计算为长度。
考虑到表格单元格和表格元素在宽度和高度计算上的复杂性,对于同时包含百分比和非零长度的表格列、表格列组、表格行、表格行组以及自动和固定布局表格中的表格单元格的宽度和高度的数学表达式,必须视为如同指定了 auto。
10.12. 范围检查
数学函数内部不执行解析时的范围检查,因此超出范围的值不会导致声明无效。但是,来自 顶层计算 的结果值必须被截断到目标上下文中允许的范围内。截断是在 计算值 上尽可能执行,如果计算无法充分简化表达式以允许范围检查,则也会在 使用值 上执行。(截断不在 指定值 上执行。)
注意:这要求所有接受 calc() 的上下文将其允许的值定义为闭区间(而非开区间)。
注意:根据定义,±∞ 超出了任何属性的允许范围,并且会截断到允许的最小值/最大值。即使是能显式表示无穷大作为关键字值的属性,如 animation-iteration-count,最终也会截断 ±∞,因为 数学函数 无法解析为关键字值;属性语法的数字部分仍然有最小值/最大值。
此外,如果解析为 <number> 的 数学函数 被用在只接受 <integer> 的地方,计算值 和 使用值 会以与上述截断相同的方式 四舍五入到最接近的整数。
width : calc ( 5 px -10 px ); width : calc ( -5 px ); width : 0 px ;
但请注意,width: -5px 与 width: calc(-5px) 不等效!calc() 外部 的超出范围值在语法上是无效的,并会导致整个声明被丢弃。
10.13. 序列化
本节仍处于 讨论中。
-
如果 fn 所表示的 计算树 的根节点是数值(数字、百分比或维度),并且正在进行的序列化是 计算值 或之后的,则将该值截断到其上下文允许的范围(如有必要),然后正常序列化该值并返回结果。
-
如果 fn 表示无限或 NaN 值:
-
如果 计算树 的根节点是数值或 计算运算符节点,令 s 为初始包含 "calc(" 的字符串。
否则,令 s 为初始包含根节点名称(小写,如 "sin" 或 "max")并跟随一个 "("(左括号)的字符串。
-
对于根节点的每个子项,序列化计算树。如果序列化的结果以 "(" 开头并以 ")" 结尾,则从结果中移除这些字符。连接 所有结果,使用 ", "(逗号后跟空格),然后追加到 s。
-
追加 ")"(右括号)到 s。
-
返回 s。
-
令 根节点 为 计算树 的根节点。
-
如果 根节点 是数值或非 数学函数,则按其正常规则序列化 根节点 并返回结果。
-
如果 根节点 不是 Sum、Negate、Product 或 Invert 节点,则 序列化数学函数,将节点的子项作为函数的逗号分隔 计算 参数,并返回结果。
-
如果 根节点 是一个 Negate 节点,令 s 为初始包含 "(-1 * " 的 字符串。
序列化 根节点 的子项,并追加到 s。
追加 ")" 到 s,然后返回它。
-
如果 根节点 是一个 Invert 节点,令 s 为初始包含 "(1 / " 的 字符串。
序列化 根节点 的子项,并追加到 s。
追加 ")" 到 s,然后返回它。
-
如果 根节点 是一个 Sum 节点,令 s 为初始包含 "(" 的 字符串。
序列化 根节点 的第一个子项,并追加到 s。
对于每个(根节点 的第一个之后的 子项):
-
如果 子项 是一个 Negate 节点,追加 " - " 到 s,然后 序列化 Negate 的子项并将结果追加到 s。
-
如果 子项 是一个负数值,追加 " - " 到 s,然后正常序列化该 子项 的取反形式并追加到 s。
-
否则,追加 " + " 到 s,然后 序列化 子项 并将结果追加到 s。
最后,追加 ")" 到 s 并返回它。
-
-
如果 根节点 是一个 Product 节点,令 s 为初始包含 "(" 的 字符串。
序列化 根节点 的第一个子项,并追加到 s。
对于每个(根节点 的第一个之后的 子项):
最后,追加 ")" 到 s 并返回它。
-
令 ret 为一个空列表。
-
如果 节点列表 包含一个数字,将其从 节点列表 中移除并追加到 ret。
-
如果 节点列表 包含一个百分比,将其从 节点列表 中移除并追加到 ret。
-
如果 节点列表 包含任何维度,将其从 节点列表 中移除,按单位排序(ASCII 大小写不敏感),并追加到 ret。
-
如果 节点列表 中仍包含任何项目,按相同顺序追加到 ret。
-
返回 ret。
像 calc(20px + 0%) 这样的值会序列化为 calc(0% + 20px),在序列化值中保持两项。(保持零值项很重要,这样当其中一个值恰好暂时为零时,calc() 不会在转换过程中突然“改变形状”。这也消除了当所有项均为零时“选择单位”的需要。)
像 calc(20px + 2em) 这样的值,作为指定值会序列化为 calc(2em + 20px)(保持两个单位,因为它们在指定值时间不兼容,但按字母顺序排序),或者作为计算值会序列化为类似 52px 的值(em 值在计算值时间转换为绝对长度,因此假设 1em = 16px,它们合并为 52px,随后丢弃 calc() 包装器。)
当在非属性上下文(例如 @font-face 描述符中)使用时,数学函数 被视为 指定值 进行简化。
有关序列化的更多信息,请参见 [CSSOM]。
10.14. 数学函数的组合
数学函数之间,或与数值及其他数值型函数之间的 插值 定义为 Vresult = calc((1 - p) * VA + p * VB)。(值的 简化 可能会将表达式缩减为更小、更简单的形式。)
数学函数之间,或与数值及其他数值型函数之间的 加法 定义为 Vresult = calc(VA + VB)。(值的 简化 可能会将表达式缩减为更小、更简单的形式。)
附录 A:协调列表属性
某些列表属性具有协调作用:其值列表中的每一项应用于一个不同的效果,且每个属性列表中对应的条目都指代同一个效果。通常,协调值也可以作为 简写属性 中列表的单个条目一并指定。
一个典型的例子是列表型的 background-* 属性,它可以指定 多个背景图像层。对于控制图像如何调整大小、平铺、放置等的每个属性,其列表中的第 N 项描述了应用于第 N 个背景图像的某种效果。
协调列表属性组 创建一个 协调值列表,对于每个条目,它都拥有该组中每个属性的值;这些值共同用于定义一个单一的效果,例如背景图像层或动画。协调值列表 的组装方式如下:
-
协调值列表 的长度由在一个特定 协调列表属性(即 协调列表基属性)中指定的项目数决定。(在背景的情况下,这是 background-image 属性。)
附录 B:IANA 注意事项
about : invalid URL 方案的注册
本节根据 [RFC6694] 中定义的注册程序,定义并注册了 URL。
此注册的官方记录可在 http://www.iana.org/assignments/about-uri-tokens/about-uri-tokens.xhtml 找到。
| 注册令牌 | invalid
|
|---|---|
| 预期用途 | URL 引用了一个带有通用错误条件的不存在文档。当必须使用 URL,但默认值不应被解析为任何类型的文档时,可以使用它。 |
| 联系人/变更控制器 | CSS 工作组 <www-style@w3.org> (代表 W3C) |
| 规范 | CSS 值与单位模块 Level 3 |
附录 C:怪异长度
当 CSS 以 怪异模式 解析时,<quirky-length> 是一种仅在某些属性中有效的 <length> 类型。
它不适用于包含或引用这些属性的属性,如 background 简写,或在 calc() 等 函数表示法 内部,除非它们必须在 clip 属性中的 rect() 中被允许。
此外,虽然 <quirky-length> 在解析 @supports 规则中受影响的属性时必须作为 <length> 有效,但当这些属性在 CSS.supports() 方法中使用时,它们不有效。
<quirky-length> 在语法上与 <number-token> 相同,并被解释为具有相同值的 px 长度。
(换句话说,怪异模式允许受影响属性中的所有 px 长度无单位书写,类似于无单位零长度。)
致谢
首先,编辑们感谢所有对本模块 上一级别 做出贡献的人。
其次,我们要感谢 Anthony Frehner、Emilio Cobos Álvarez、Koji Ishii、Noam Rosenthal 和 Xidorn Quan 的评论和建议,这些建议改进了 Level 4。
变更 (Changes)
最近变更
(这是 自 Level 3 以来的新增内容 的子集。)
自 2023 年 12 月 18 日工作草案(WD)以来的重大变化:
-
全面修复了类型推断处理百分比的方式(问题 10017)。
-
恢复了 视口百分比长度 对 overflow: scroll 的依赖,并增加了对 scrollbar-gutter 的依赖,使得 100 个这些单位能够真正匹配 初始包含块(问题 6026)。
自 2023 年 10 月 27 日工作草案(WD)以来的重大变化:
-
将 默认视口百分比单位 固定为 大视口百分比单位——尽管违反了“默认避免数据丢失原则”——鉴于现有的互操作性和预期的 Web 兼容性限制(问题 6452)。
-
添加了关于 CSS 语法产生式块 约定的明确定义(问题 2921)。
-
澄清了百分比编码 URL 的字符编码(问题 9301)。
自 2023 年 4 月 6 日工作草案(WD)以来的重大变化:
-
将 mix() 推迟到 [css-values-5](问题 9343)。
-
定义颜色类型为不可加(问题 8576)。
-
指定来自 CSS 的 URL 始终以 UTF-8 传输(问题 9301)。
自 2022 年 10 月 19 日工作草案(WD)以来的重大变化:
- 添加了 § 2.6 函数表示法定义,以正式定义 函数表示法 语法的定义方式(问题 2921)。
- 添加了 对齐长度作为边框宽度 的算法,以反映渲染一致笔画宽度的互操作规则(问题 5210)。
- 澄清了 mix() 的语法和 计算值(问题 8096)。
- 未定义 tan() 在渐近线值处的行为(问题 8527)。
- 指定负 <resolution> 值根据定义即为超出范围(问题 8532)。
- 澄清了完全省略 mix() 参数是有效的(问题 8556)。
- 澄清了范围截断专门发生在 顶层计算 上(而不是模糊的“表达式”术语)(问题 8158)。
- 为 <url()> 和 <src()> 添加了正式定义(除了 <url> 之外)。
- 根据树作用域引用重新措辞了仅包含片段的 URL(问题 3320)。
自 2021 年 12 月 16 日工作草案(WD)以来的重大变化:
- 更改了带有 本地 url 标志 的 url() 的解析,使其引用当前 节点树(无论文档基 URL 如何修改)(问题 3320)。
- 将逃离 数学函数 的 NaN 的审查方式从无穷大更改为零(问题 7067)。
- 添加了 附录 A:协调列表属性,以便轻松引用此属性模式(问题 7164)。
- 限制 mix() 成为声明的唯一值(问题 6700)。
- 更新以匹配最新的 Fetch 术语(Fetch PR 1413, CSS PR 7160)。
- 澄清了 字体相关长度 是在不进行文本整形的情况下计算的。
- 定义空 URL 的序列化为
(问题 6447)。url ( "" ) - 定义了 <position> 指定值 的序列化。(Issue 2274)
- 修正了 数字 的定义,允许在科学计数法中结合使用小数,正如最初意图以及 [CSS-SYNTAX-3] 中所定义的那样。(Issue 7248)
- 更正了各种函数,使其在 类型 为空时返回空映射,而不是 «[ "number" → 1 ]»。(Issue 7486)
- 阐明了特殊 UA 限制对 line-height 在 lh 和 rlh 上的影响。(Issue 3257)
- 定义了
<记法,用于指代函数式记法。(Issue 5728)function () >
自 2021年10月16日工作草案 (WD) 以来的重大变更
- 将 *vi 和 *vb 单位切换为基于元素本身的计算后 书写模式 进行解析。(Issue 6873)
- 添加了 § 4.5.4 URL 处理模型,以定义与 CORS 等的集成。(Issue 562)
- 修正了 视口百分比长度 行为在界面变更类型(A 与 B)之间分配颠倒的问题。
- 由于滚动或其他频繁页面交互而导致的界面变更,如果导致重大的布局变更会打扰用户,则必须归类为
前者 (A)后者 (B)。 - 具有足够稳定状态的界面变更,若将文档重新布局到调整后的空间对用户有益,则必须归类为
后者 (B)前者 (A)。
- 由于滚动或其他频繁页面交互而导致的界面变更,如果导致重大的布局变更会打扰用户,则必须归类为
- 将 calc() 项、参数和嵌套的最小数量定义为 32。(Issue 3462)
- 定义 mod(-0, infinity) 返回 NaN。(Issue 4723)
- 将 toggle() 和 attr() 推迟至 Level 5。
自 2021年9月30日工作草案 (WD) 以来的变更
- 添加了 rex、rcap、rch 和 ric 单位。
- 切换 toggle() 使用分号,以匹配 mix()。(Issue 6701)
- 修正了 calc() 定义中的一些措辞错误。(Issue 6506)
- 从 [QUIRKS] 导入了 <quirky-length> 的定义。(Issue 6100)
自 2021年7月7日工作草案 (WD) 以来的变更
- 添加了用于表示插值(interpolated)值的 mix() 记法。
- 通用定义了 <integer>、<number>、<percentage> 和 <length> 的计算方式。
- 阐明了仅非零长度会创建将表格单元格切换为 auto 尺寸调整的百分比加长度组合。
自 2020年11月11日工作草案 (WD) 以来的变更
- 更新了颜色的插值,引用 [CSS-COLOR-4] 而非 [CSS-COLOR-3]。
- 添加了 svh, svw, svi, svb, svmin, 和 svmax 小视口百分比单位;lvh, lvw, lvi, lvb, lvmin, 和 lvmax 大视口百分比单位;以及 dvh, dvw, dvi, dvb, dvmin, 和 dvmax 动态视口百分比单位。(Issue 4329 和 Issue 6113)
- 将过大的 <angle> 值钳制为 360deg 的倍数。(Issue 6105)
- 添加回了在从 CSS Transitions 规范迁移过程中丢失的 组合值范围检查规则。(Issue 6097)
- 指定 UA 强制执行的最小字体大小适用于使用的 font-size,而不适用于 字体相对长度 的解析。(Issue 5858)
- 阐明了 min() 和 max() 百分比如何进行部分简化。(Issue 6293)
自 Level 3 以来的新增内容
自 CSS Values and Units Level 3 以来的变更
- 明确未定义数值精度/范围。
- 添加了按值类型的插值规则及其明确的计算值。
- 更新了颜色的插值,引用 [CSS-COLOR-4]。
自 CSS Values and Units Level 3 以来的新增内容
- 定义了 <dashed-ident> 类型。
- 定义了 <ratio> 类型。
- 向 <url> 类型添加了 src()。
- 添加了 vi, vb, ic, cap, lh 和 rlh 长度单位。
- 添加了 svh, svw, svi, svb, svmin, 和 svmax 小视口百分比单位,以及 dvh, dvw, dvi, dvb, dvmin, 和 dvmax 动态视口百分比单位。
- 添加了 x 作为 dppx 的别名。
- 添加了 min(), max() 和 clamp() 比较函数。
- 添加了 round(), mod(), rem(), sin(), cos(), tan(), asin(), acos(), atan(), atan2(), pow(), sqrt(), hypot(), log(), exp(), abs(), sign() 数学函数。
- 添加了 e, pi, infinity, -infinity, NaN 常量供 calc() 使用。
- 为 calc() 添加了 单位代数,允许对 维度 进行乘法和除法运算。
- 当在需要 <integer> 的地方使用时,calc() 中的非整数会自动舍入到最接近的整数。
- 定义了 数学函数 的 序列化。
- 添加了 协同列表属性组 的通用定义,以便更容易地引用 background 属性的协同行为。
安全性考虑
本规范不提出新的安全性考虑。
本规范定义了 url() 和 src() 函数(<url>),允许 CSS 发起网络请求。根据其所使用的特性,这些可能会潜在地暴露用户是否能够访问网络资源,并暴露有关其内容的信息(例如样式表中的规则、图像的大小、字体的度量)。它们还可能允许通过 URL 窃取数据。
隐私性考虑
本规范定义的单位会暴露用户的屏幕尺寸(视口百分比长度)、默认字体大小,以及可能关于用户系统上可用字体的一些信息(字体相对长度)。
本规范定义了 url() 和 src() 函数(<url>),允许 CSS 发起网络请求。根据其所使用的特性,这些可能会潜在地暴露用户是否能够访问网络资源,并暴露有关其内容的信息(例如样式表中的规则、图像的大小、字体的度量)。它们还可能允许通过 URL 窃取数据。