CSS 数值与单位模块 4 级

W3C 工作草案,

关于本文档的更多详情
此版本:
https://www.w3.org/TR/2024/WD-css-values-4-20240312/
最新发布版本:
https://www.w3.org/TR/css-values-4/
编辑草案:
https://drafts.csswg.org/css-values-4/
历史记录:
https://www.w3.org/standards/history/css-values-4/
反馈:
CSSWG 问题库
规范内反馈
编辑:
Tab Atkins (Google)
Elika J. Etemad / fantasai (Apple)
建议编辑此规范:
GitHub 编辑器
测试套件:
https://wpt.fyi/results/css/css-values/

摘要

本 CSS 模块描述了 CSS 属性所接受的通用数值和单位,以及用于在 CSS 属性定义中描述它们的语法。

CSS 是一种用于描述结构化文档(如 HTML 和 XML)在屏幕、纸张等上的渲染方式的语言。

本文档状态

本节描述了本文档在发布时的状态。当前 W3C 发布的文档列表以及本技术报告的最新修订版,可在 W3C 技术报告索引 https://www.w3.org/TR/ 查阅。

本文档由 CSS 工作组 作为推荐标准制定流程下的工作草案发布。 作为工作草案发布,并不代表 W3C 及其成员的认可。

本文档为草案,可能随时被更新、替换或废弃。 除非作为开发中工作,否则不应作为正式引用。

请通过在 GitHub 提交 issue(推荐),并在标题中包含规范代码“css-values”,格式如:“[css-values] …评论摘要…”来反馈意见。 所有问题和评论都会被归档。 或者,也可以反馈到(归档)公共邮件列表 www-style@w3.org。

本文件受 2023年11月3日 W3C 流程文件 管辖。

本文件由遵循 W3C 专利政策 的工作组制定。 W3C 维护了公开披露的专利列表,其中列出了与该组交付物相关的任何专利披露; 该页面还包括披露专利的说明。 任何知晓专利且认为其包含必要声明的个人,必须按照W3C 专利政策第6节披露相关信息。

1. 引言

每个 CSS 属性的值定义字段可以包含关键字、数据类型(出现在 < 和 > 之间),以及它们如何组合的信息。通用的数据类型(<length> 是最常用的)可被许多属性使用,这些类型在本规范中进行了描述,而更具体的数据类型(如 <spacing-limit>)则在各自的模块中定义。

1.1. 模块交互

本模块取代并扩展了 [CSS2] 规范中 1.4.2.1、4.3 和 A.2 部分的数据类型定义。

2. 值定义语法

此处描述的 值定义语法 用于定义 CSS 属性的有效值集合(以及 CSS 其他部分的有效语法)。被如此描述的值可以包含一个或多个组件。

2.1. 组件值类型

组件值类型有几种指定方式:

  1. 关键字值(例如 auto,disc 等),直接以字面量出现,无需引号(如 auto)。

  2. 基本数据类型,出现在 < 和 > 之间(如 <length>、<percentage> 等)。对于 数值数据类型,该类型记法可以使用下文所述的括号范围记法来标注任意范围限制。

  3. 属性值范围,表示与同名属性相同的值模式。这些写作属性名,并以单引号括起,放在 < 和 > 之间,例如 <'border-width'>,<'background-attachment'> 等。

    这些类型不包括CSS 全局关键字,如 inherit。此外,如果属性的值语法是逗号分隔重复,则相应类型不包括顶层 逗号分隔列表乘子。(例如,如果有一个名为 pairing 的属性被定义为 [ <custom-ident> <integer>? ]#,则 <'pairing'> 等价于 [ <custom-ident> <integer>? ],而不是 [ <custom-ident> <integer>? ]#。)

    为什么要去除乘子?

    这些值类型去除了顶层乘子,是因为顶层逗号分隔重复主要用于协调型列表属性,而当简写属性合并多个此类属性时,需要未重复的语法,以便可以构造其自己的逗号分隔重复。

    如果没有这种特殊处理,每个这样的长属性都必须为内部值定义一个特设产生式,这会让语法整体更难理解。

  4. 函数记法及其参数。这些写作函数名,后跟一对空括号,放在 < 和 > 之间,例如 <calc()>,并指代同名的 函数记法。

  5. 其他非终结符。这些写作非终结符名称,放在 < 和 > 之间,如 <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 全局关键字值作为属性值的唯一组成部分。为便于阅读,这些关键字不会在属性值语法定义中显式列出。例如,border-color 在 CSS Cascading and Inheritance Level 3 下的完整值定义为 <color>{1,4} | inherit | initial | unset(即使语法只写作 <color>{1,4})。

注意: 这意味着通常情况下,将这些关键字与同一声明中的其他组件值组合会导致声明无效。例如,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. 组件值乘子

每种类型、关键字或带括号的分组后面都可以跟以下修饰符之一:

+ 和 # 乘子可叠加为 +#;同理,# 和 ? 也可叠加为 #?。这些叠加等价于后面的乘子作用于前面的乘子结果(用分组也可表达,但语法复杂时会导致括号过多影响可读性)。

对于重复的组件值(*、+ 或 #),UA 必须支持至少 20 次重复。如果属性值包含超过支持次数的重复,则该声明必须被忽略视为无效。

2.4. 组合符与乘子模式

有一小组常见方式用于按特定数量和顺序组合多个独立的组件值。尤其常见的需求是:从一组组件值中,作者必须选择零个或多个、一个或多个,或全部,并且顺序可以固定或任意。

所有这些都可以通过简单的组合符和乘子组合模式表达:

顺序固定 顺序任意
零个或多个 A? B? C? A? || B? || C?
一个或多个 [ A? B? C? ]! A || B || C
全部 A B C A && B && C

注意,所有“顺序任意”的情况都是用组合符表达的,而“顺序固定”都是并列变体。

2.5. 组件值与空白符

除非另有说明,空白符和/或注释可以出现在用上述组合符和乘子组合的组件之间、之前和之后。

注意: 在许多情况下,组件之间实际上必须有空格,以区分各自。例如,值 1em2em 会被解析为一个 <dimension-token>,数值为 1,标识符为 em2em,这是无效单位。此时,必须在 2 前添加空格,才能分别解析为 1em 和 2em 两个长度。

2.6. 函数式记法定义

函数式记法的语法定义为以下序列:

  1. 函数名写作标识符,后跟左括号(如 example(),或用 <function-token> 产生式表示任意函数名。

  2. 函数参数(如有),用值定义语法表达。

  3. 一个右括号字面量。

函数参数被视为隐式分组,相当于被方括号([ ... ])包围。

例如,如下语法:
example( <length> , <length> )

会匹配函数名为“example”,参数为“<length> , <length>”的函数。

例如,选择器语法通用地定义伪类,允许冒号后跟任意函数名:
<pseudo-class-selector> = ':' <ident-token> | ':' <function-token> <any-value> ')'

这表示任意函数名,<any-value> 为函数参数。

由于 函数式记法隐式分组其内容,任何组合符的作用范围仅限于函数参数。例如,函数式记法语法定义 example( foo | bar ) 等价于 example( [ foo | bar ] )。

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 语法产生式块中给出。这些定义通常以如下格式的预格式化区块表示:

<foo> 语法定义如下:
<foo> = keyword | <bar> |
        some-really-long-pattern-of-stuff
<bar> = <length>

每条定义单独占一行,由要定义的非终结符、一个 =,以及其展开的值定义语法片段组成。定义可以跨多行,直到下一行以新产生式开头或到达产生式块结尾(以先到者为准)为止。

在上述例子中,<foo> 的定义跨两行,第三行为 <bar> 启动新定义。(裸 = 在值定义语法中永远无效,因此新定义的起始是明确的。)

3. 值的组合:插值、加法与累积

某些过程(例如 过渡 和 动画)会组合两个 CSS 属性值。 下列组合操作——针对两个计算值 VA 和 VB,生成 计算值 Vresult——进行了定义。 对于非交换操作(如矩阵乘法或不匹配变换列表的累积),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 的增量。
注意:对于很多动画类型,如数字或长度,累积被定义为与加法相同。

常见的不同定义情况出现在基于列表的类型中, 此时加法可能被定义为列表追加, 而累积 可能被定义为分量加法。 例如,滤镜列表值 blur(2) 和 blur(3), 加法结果是 blur(2) blur(3), 累积结果则为 blur(5)。

如果某个值类型未定义累积的具体过程, 其 累积操作与加法相同。

这些操作仅定义在计算值上。 (因此,无需定义如 <length> 值 15pt 与 5em 如何相加,因为此类值会先被解析为规范单位后再传递给上述过程。)

3.1. 范围检查

插值可能导致结果值超出属性的有效范围,即使所有插值输入都是有效的; 这在 p 超出 [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] 等价)。

例如,border-collapse 属性的值定义为:
Value: collapse | separate

使用示例:

table { border-collapse: separate }

4.1.1. CSS 全局关键字:initial、inherit 和 unset

如上所述,所有属性都接受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> 产生式只有在没有其他未满足产生式可认领该关键字时,才能认领它。

例如,速记声明 animation: ease-in ease-out 等价于长写声明 animation-timing-function: ease-in; animation-name: ease-out;。ease-in 被 <easing-function> 产生式认领,属于 animation-timing-function, 留下 ease-out 被 <custom-ident> 产生式认领,属于 animation-name。

注意: 在设计带有 <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>。

例如,自定义属性 需要和 CSS 定义的属性区分, 因为 CSS 会不断新增属性。 为此,自定义属性名要求为 <dashed-ident>, 示例:
.foo {
  --fg-color: blue;
}
<dashed-ident> 也用于 @color-profile 规则, 用于区分作者自定义色彩配置与预定义配置(如 device-cmyk), 并允许 CSS 将来定义更多预定义(但可覆盖)配置, 无需担心与作者自定义配置冲突:
@color-profile --foo { src: url(https://example.com/foo.icc); }
.foo {
  color: color(--foo 1 0 .5 / .2);
}
随着更多作者可控语法的增加,CSS 在未来会更多使用 <dashed-ident>。 CSS 工具, 如将自定义语法转换为标准 CSS 的预处理器,也应使用 <dashed-ident>, 以避免与未来 CSS 设计发生冲突。

例如, 如果某 CSS 预处理器新增了一个“自定义” at 规则, 不应写作 @custom, 因为这会与将来官方的 @custom 规则冲突。 应该用 @--custom, 这样就保证不会与 CSS 已定义内容冲突。

更好的做法是用 @--library1-custom, 这样如果 Library2 也新增自己的 “custom” at 规则 (写作 @--library2-custom), 就不会发生冲突。 理想情况下,该前缀应是可配置的, 这样作者可以手动避免冲突。

4.4. 带引号的字符串:<string> 类型

字符串(String)由 <string> 表示。 当以字面值书写时, 它们由用双引号或单引号括起来的一系列字符组成, 对应于 <string-token> 产生式, 详见 CSS 语法模块 [CSS-SYNTAX-3]。

双引号不能直接出现在双引号包裹的字符串中,除非进行转义(如 "\"" 或 "\22")。 单引号的情况类似('\'' 或 '\27')。
content: "this is a 'string'.";
content: "this is a \"string\".";
content: 'this is a "string".';
content: 'this is a \'string\'.'

出于美观或其它原因,可以将字符串分为多行书写,但此时换行符本身必须用反斜杠(\)转义。该换行符随后会从字符串中移除。例如,以下两个选择器是完全相同的:

示例:

a[title="a not s\
o very long title"] {/*...*/}
a[title="a not so very long title"] {/*...*/}

由于字符串不能直接包含换行符,如需在字符串中包含换行,请使用转义符 "\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 作为背景图片使用:
body { background: url("http://www.example.com/pinkish.gif") }

出于兼容性原因,url() 可以在不加引号的情况下书写 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() 语法不能接受 <url-modifier> 参数, 且需要额外的转义: 括号、空白符、单引号 (') 与双引号 (") 出现在 URL 中时都必须用反斜杠转义, 例如 url(open\(parens)、url(close\)parens)。 (在带引号的 <string> url() 中,仅需转义换行符和用于包裹字符串的引号。) 视 URL 类型,也可以用 URL 转义字符书写(如 url(open%28parens) 或 url(close%29parens)),详见 [URL]。

未加引号 url() 语法的精确定义见 [CSS-SYNTAX-3]。

某些 CSS 场景(如 @import)也允许用裸 <string> 表示 <url>,无需函数包装。 在这种情况下,该字符串的行为与包裹同内容的 url() 一致。

例如,以下语句行为完全一致:
@import url("base-theme.css");
@import "base-theme.css";

4.5.1. 相对 URL

为了创建不依赖于资源绝对路径的模块化样式表,建议作者使用相对 URL。 相对 URL(定义见 [URL]) 会通过基准 URL 解析为完整 URL。RFC 3986 第3节定义了规范算法。 对于 CSS 样式表,基准 URL 是样式表本身的 URL,而不是源文档的 URL。 内嵌于文档的样式表,其基准 URL 由其容器关联。

注意: 对于 HTML 文档,基准 URL 是可变的。

当 <url> 出现在属性的计算值中时, 会根据上文描述解析为绝对 URL。 用户代理无法解析为绝对 URL 的 URL,其计算值就是指定值。

例如,假设有如下规则:
body { background: url("tile.png") }

位于样式表:

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 的 片段。

当匹配一个已设置 本地 url 标志的 <url> 时:

可能需要引用 查找潜在指示元素, 但该定义仅适用于 Document, 不适用于 ShadowRoot。

注意: 这意味着此类片段将始终相对于当前文档内容(或样式表所在的节点树,如有 shadow DOM)解析, 而不考虑其他地方的相对 URL 解析方式(如 base 元素改变基准 URL,或外链样式表的相对 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("") 或 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 处理模型

要从一个 url 或 <url> urlValue,获取样式资源, 给定一个 CSSStyleSheet sheet, 一个匹配 RequestDestination 的字符串 destination, 一个 "no-cors" 或 "cors" 的 corsMode, 以及一个接受 response 及 null、failure 或字节流的算法 processResponse:
  1. 令 environmentSettings 为 sheet 的 相关设置对象。

  2. 令 base 为 sheet 的 样式表基准 URL(如不为 null), 否则为 environmentSettings 的 API 基准 URL。[CSSOM]

  3. 令 parsedUrl 为 URL 解析器步骤的结果, 以 urlValue 的 url 和 base 为参数。 若算法返回错误,则返回。

  4. 令 req 为新建的 请求,其 url 为 parsedUrl, destination 为 destination,mode 为 corsMode,origin 为 environmentSettings 的 origin,credentials mode 为 "same-origin",use-url-credentials flag 设为 true, client 为 environmentSettings, referrer 为 environmentSettings 的 API 基准 URL。

  5. 应用所有适用于该请求的 URL 请求修改步骤。

    注意: 本规范未定义任何 URL 请求修改步骤, 但其它规范可定义。

  6. 如果 req 的 mode 为 "cors", 则将 req 的 referrer 设为 sheet 的 location。[CSSOM]

  7. 如果 sheet 的 origin-clean flag 被设置, 则将 req 的 initiator type 设为 "css"。[CSSOM]

  8. Fetch req, 并将 processresponseconsumebody 设为 processResponse。

在解析 CSS 中的 URL 时, URL 解析器 的 encoding 参数 必须省略 (即使用默认 UTF-8), 无论样式表的编码为何。

注意: 换句话说,CSS 中书写的 URL 总是会在 百分号编码非 ASCII 码点时,使用 UTF-8 编码到 URL 对象中(因此当将 URL 值用于如网络请求等场景时总是如此),与样式表本身的编码无关。注意,此过程发生在将样式表解码为 Unicode 码点之后。

5. 数值数据类型

数值数据类型用于表示数量、索引、位置等值。 虽然表达数值(数值部分)本身有多种语法变体, 但指定值和计算值不会区分这些变体: 它们代表值的抽象数量,而不是其语法表现形式。

数值数据类型 包括 <integer>、<number>、<percentage>, 以及各种带单位数值,如 <length>、<angle>、<time>、<frequency>、<resolution> 等。

注意:虽然通用带单位数值在此定义, 但其他一些模块还定义了更多数据类型 (如 [css-grid-1] 引入了 fr 单位), 它们的用途更为局部化。

CSS 中数值的精度和支持的范围是由实现定义的, 并且可能会根据值所用的属性或上下文而异。 但在 CSS 规范中, 假定为无限精度和范围。 如果由于实现的范围/精度限制而无法明确支持某个值, 则必须将其转换为实现所支持的最接近的值, 但实现如何定义“最接近”也是由实现定义的。

如果由于超出实现定义的支持范围而必须转换<angle>, 则必须将其裁剪为最接近的 360deg 的倍数。

5.1. 范围限制与范围定义记法

属性可以将数值限制在某个范围内。 如果值超出允许范围, 除非另有说明, 该声明无效,必须被忽略。 可以使用CSS 方括号范围记法([min,max])在数值类型的尖括号内、关键字后标注范围, 表示封闭区间(包含 min 和 max)。 例如,<integer [0,10]> 表示整数在 0 到 10 之间(含端点), <angle [0,180deg]> 则表示角度在 0deg 到 180deg 之间(可为任意单位)。

注意: CSS 值通常不允许开区间,因此只用方括号表示法。

理论上 CSS 支持所有值类型的无限精度和无限范围; 但实际上实现有有限能力。UA 应支持合理有用的范围和精度。 理想情况下无限的范围可用 ∞ 或 −∞ 表示。 例如,<length [0,∞]> 表示非负长度。

如果未标注范围, 无论是通过方括号范围记法还是属性描述, 则假定为 [−∞,∞]。

−∞ 或 ∞ 的值必须无单位书写, 即使该类型通常带单位。 0 可以无单位书写, 即使该类型通常不允许“无单位零” (如 <time>)。

注意: 撰写本规范时, 方括号范围记法尚属新内容; 因此多数 CSS 规范中的范围限制只用文字描述。 (如“负值无效”或“负值不允许”表示 [0,∞] 范围。) 这些说明同样具有限制效力。

5.2. 整数:<integer> 类型

整数值用 <integer> 表示。

当以字面值书写时, 整数 是一个或多个十进制数字 0 到 9,对应于 CSS 语法模块<number-token> 产生式的一个子集。[CSS-SYNTAX-3] 整数的首位数字可前置 - 或 + 表示正负号。

除非另有说明, 在 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”再跟一个整数,表示科学计数法下的十进制指数。 它对应于 <number-token> 产生式, 见 CSS 语法模块 [CSS-SYNTAX-3]。 与整数一样,数值首位可加 - 或 + 表示正负号。

<zero> 代表值为 0 的数值字面量。 只要表达式结果为 <number> 且值为 0 (如 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> 表示。

当以字面值书写时, 带单位数值 是一个 数值 紧接单位标识符, 单位是一个标识符。 对应 <dimension-token> 产生式, 见 CSS 语法模块 [CSS-SYNTAX-3]。 单位标识符同关键字一样,ASCII 不区分大小写。

CSS 用 <dimension> 表示 距离(<length>), 时长(<time>), 频率(<frequency>), 分辨率(<resolution>)等量值。

5.4.1. 兼容单位

序列化计算值时 [CSSOM], 兼容单位(指可用静态比例因子换算的单位,如 px 和 in 之间的 96:1 比例, 或 font-size 计算值下 em 和 px 之间的比例) 会被转换为同一个规范单位。 每组兼容单位会指定其中哪个作为规范单位用于序列化。

序列化已解析值(即已用值)时, 所有代表长度的值类型(百分比、数值、关键字等)都视为与长度兼容。 同理,未来返回 已用值 的 API 必须将所有代表距离/时长/频率等的值视为与相关类别 带单位数值兼容,并据此规范化。

5.4.2. 带单位数值的组合

插值兼容的单位的带单位数值(比如两个 <length> 值) 定义为 Vresult = (1 - p) × VA + p × VB

加法兼容单位的带单位数值,定义为 Vresult = VA + VB

5.5. 百分比:<percentage> 类型

百分比值用 <percentage> 表示, 表示某个参考值的一定比例。

当以字面值书写时, 百分比为一个 数值 紧跟百分号 %。 对应 <percentage-token> 产生式, 见 CSS 语法模块 [CSS-SYNTAX-3]。

百分比值总是相对于另一个量(如长度)。 每个允许百分比的属性还会定义百分比所参考的量。 该量可为同一元素其他属性的值、祖先元素属性的值、排版上下文的某个测量 (如 包含块的宽度), 或其他内容。

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>

等价于 [ <length> | <percentage> ], 其中 <percentage> 会被解析为 <length>。

<frequency-percentage>

等价于 [ <frequency> | <percentage> ], 其中 <percentage> 会被解析为 <frequency>。

<angle-percentage>

等价于 [ <angle> | <percentage> ], 其中 <percentage> 会被解析为 <angle>。

<time-percentage>

等价于 [ <time> | <percentage> ], 其中 <percentage> 会被解析为 <time>。

例如,width 属性可以接受 <length> 或 <percentage>, 都表示距离量。 这意味着 width: calc(500px + 50%); 是合法的——两个值会转换为绝对长度并相加。 如果包含块宽度为 1000px, 则 width: 50%; 等价于 width: 500px, width: calc(50% + 500px) 最终等价于 width: calc(500px + 500px) 或 width: 1000px。

另一方面,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> 或等价记法)的插值定义为:

加法的 <percentage> 的定义与插值一致,只是每个分量是相加而非插值。

5.7. 比例:<ratio> 类型

比例值用 <ratio> 表示, 代表两个数值的比值。 它通常用来表示宽高比(第一个为宽度,第二个为高度)。

当以字面值书写时, 比例 语法如下:

<ratio> = <number [0,∞]> [ / <number [0,∞]> ]?

第二个 <number> 可省略,默认值为 1。 但 <ratio> 序列化时总会写出两个分量。

<ratio> 的计算值为指定的数字对。

如果 <ratio> 中任一数为 0 或无穷, 则代表退化比例(通常不会有效果)。

如果要比较两个 <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>。

如任一 <ratio> 是退化比例, 则无法插值。

例如, 从 5 / 1 线性插值到 3 / 2 的中点, 结果约为比例 2.73 / 1(约为 11 / 4,略高于 3 / 1):
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), 并且无论宽为基准还是高为基准都对称。 这些是许多其它插值策略不具备的特性。

注意: 由于对数的性质, 可用任意对数,例子用的是 base-10, 但如用自然对数 e,插值中间结果不同,最终结果一致。

两个 <ratio> 不支持加法。

6. 距离单位:<length> 类型

长度指距离的度量,在属性定义中用 <length> 表示。 长度是一种带单位数值。

对于零长度,单位标识符是可选的 (即可以语法上写作 <number> 0)。 但如果 0 在某属性中既可解析为 <number>,也可解析为 <length> (比如 line-height), 则必须解析为 <number>。

属性可以对长度值进行范围限制。 如果值超出允许范围, 声明无效,必须被忽略。

虽然某些属性允许负长度值, 这可能会使排版变得复杂,并且可能有实现相关的限制。 如果允许但无法支持负长度值, 必须将其转换为能支持的最接近值。

在无法支持已用长度的情况下, 用户代理必须在实际值中做近似。

长度单位分为两类:相对和绝对。 长度的指定值(指定长度)由其数值和单位组成。 长度的计算值(计算长度)为指定长度解析为绝对长度, 单位不区分: 可以用任意绝对长度单位表示(但序列化时会用它的规范单位,即 px)。

虽然数值的精度支持情况及其如何舍入通常是由实现定义的,但 <length> 在 border-width 及少数其他属性中 会以特定方式舍入, 以确保良好的视觉显示。 (此算法由各属性显式调用。)

若要 将长度对齐为边框宽度,给定 <length> len:
  1. 断言:len 为非负数。

  2. 如果 len 是整数个设备像素,不做处理。

  3. 如果 len 大于零但小于 1 个设备像素, 将 len 向上舍入为 1 个 设备像素。

  4. 如果 len 大于 1 个设备像素, 向下舍入为最接近的整数个 设备像素。

6.1. 相对长度

相对长度单位表示相对于另一个长度的长度。 使用相对单位的样式表更易于在不同输出环境间缩放。

相对单位有:

相对单位简表
单位 相对于
em 元素的字体大小
ex 元素字体的 x 高度
cap 元素字体的大写字母高度
ch 元素字体中窄字形(如“0”)的典型字形进位宽度
ic 元素字体中全角字形(如“水”)的典型字形进位宽度
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 单位

字体相对长度指基于字体度量的长度, 可为使用该单位的元素自身字体度量 (局部字体相对长度), 也可为根元素的字体度量 (根字体相对长度)。

单词 Sphinx 注释了多种字体度量:上升部高度、S 的顶端为大写高度、x 的顶端为 x 高度、基线、p 的底部为下降部高度。
常见排版度量
em
等于使用该单位元素的 font-size 属性的计算值。
例如:
h1 { line-height: 1.2em }

表示 h1 元素的行高 将比其字体大小大 20%。 另一方面:

h1 { font-size: 1.2em }

表示 h1 元素的字体大小 比其继承的字体大小大 20%。

rem
等于根元素上 em 单位的计算值。
ex
等于首选字体的实际 x 高度 [CSS3-FONTS]。 x 高度通常等于小写 x 的高度。 但即使字体不含 "x" 也有 ex 的定义。 x 高度可有多种方式获得。 有些字体提供可靠的 x 高度度量。 若无可靠度量,UA 可用小写字形高度近似。 一种启发是取小写 "o" 超出基线的距离,再用其外框顶减去该值。 如无法或不便确定 x 高度,必须假定为 0.5em。
rex
等于根元素上 ex 单位的值。
cap
等于首选字体的实际大写高度 [CSS3-FONTS]。 大写高度约等于大写拉丁字母的高度。 但即使不含拉丁字母也有 cap 单位。 cap 高度可多种方式获得。 有些字体有可靠 cap 高度度量。 若无可靠度量,UA 可用大写字形高度近似。 一种启发是取大写 “O” 超出基线的距离,再用其外框顶减去该值。 如无法或不便确定 cap 高度,应使用字体的 ascent。
rcap
等于根元素上 cap 单位的值。
ch
表示欧洲字母数字的典型进位宽度,为该字体中 “0” (U+0030) 的实际进位宽度。 (进位宽度指字形在元素行内轴方向的 advance width 或 height。)

注意: 此度量是单个窄字形的前进度量的近似值(等宽字体下为精确值), 从而允许基于预期字形数量进行度量。

注意: 字形进位宽度受书写模式、文本方向、字体设置、text-transform 及其他影响字形选择或方向的属性影响。

如无法或不便确定 “0” 的度量, 应假定宽为 0.5em,高为 1em。 因此 ch 单位一般为 0.5em, 竖排时为 1em (如 writing-mode 为 vertical-rl 或 vertical-lr 且 text-orientation 为 upright)。

rch
等于根元素上 ch 单位的值。
ic
表示 CJK 字母的典型进位宽度,为所用字体中 “水” (U+6C34) 的实际 进位宽度。

注意: 这个度量通常是单个全角字形的前进度量的精确值(少数具有比例全角字形的字体中为近似值), 从而允许基于预期字形数量进行度量。

如无法或不便确定汉字进位宽度,应假定为 1em。

ric
等于根元素上 ic 单位的值。
lh
等于元素 line-height 属性的计算值, 其中 normal 通过仅用首选字体的度量转为绝对长度。
rlh
等于根元素上 lh 单位的值。

注意: 用 height 属性指定 lh 或 rlh 单位, 并不能让作者控制实际行数, 这些单位只用于理论上理想空行的长度计算; 实际行盒大小因内容而异。 如需限制元素实际行数,可用 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 等字体相对单位可能会触发字体下载, 如所需字体尚未加载。

字体相对长度的计算不考虑字形变形。

有些用户代理允许用户为文档字体大小加以限制,如设置最小字体以保证可读性。 这些限制只应用于受影响属性的已用值; 不得影响属性中 字体相对长度的解析。 但在其他场景(如 媒体查询), 若限制影响字体度量, 则会影响 字体相对长度的解析。

注意: 一般来说,尊重用户偏好(如最小字体)是有益的; 例如 (min-width: 40em) 媒体查询用实际字体大小对齐有用。 但让这些偏好影响元素属性中的字体相对长度,不符合 Web 兼容性; 太多页面要求这些单位是指定 font-size 的精确倍数, 而不是应用用户偏好后的实际字体大小。

有些用户代理对表单控件的 line-height 值有限制。 这些限制对 lh 和 rlh 单位没有影响。 但对子元素的影响为由实现定义。

6.1.2. 视口百分比长度:*vw、*vh、*vi、*vb、*vmin、*vmax 单位

视口百分比长度相对于初始包含块的大小—— 即基于视口大小(连续媒体)或页面区域(分页媒体)的大小。 改变初始包含块的宽高时,它们会相应缩放。

6.1.2.1. 大、小与动态视口尺寸

视口百分比长度单位有四种变体, 分别对应三种(可能相同)视口尺寸概念。

large viewport
大视口百分比单位(lv*) 和 默认视口百分比单位(v*) 以 大视口尺寸为基准: 该视口尺寸假定所有UA可动态展开/收起的界面都已收起。 这样作者可确保内容填满整个视口, 但这些内容在界面展开时可能会被遮挡。

大视口百分比单位的尺寸是固定的(因此稳定),除非视口本身调整。

例如,在手机上, 屏幕空间有限, 浏览器常在用户滚动页面后隐藏标题栏和地址栏。 大视口百分比单位相对于这些界面收起后的空间, 所以用这些单位的内容在界面收起时会填满整个可见页面。 但界面显示时,这些单位定位或大小的内容可能会被遮挡。
small viewport
小视口百分比单位(sv*) 以 小视口尺寸为基准: 该视口尺寸假定所有UA可动态展开/收起的界面都已展开。 这样作者可确保内容即使界面展开也不会被遮挡, 但界面收起时内容可能不会填满视口。

小视口百分比单位的尺寸是固定的(因此稳定),除非视口本身调整。

例如,height: 100svh 的元素, 在所有 UA 动态界面显示时会完美填满屏幕,不会内容被遮挡。

但这些界面收起后,该元素周围会有额外空间。 小视口百分比单位通常更安全, 但用户与页面交互后可能布局不最优。

dynamic viewport
动态视口百分比单位(dv*) 以 动态视口尺寸为基准: 即考虑动态展开/收起的所有UA界面后的视口大小。 这样作者可确保内容无论界面在否都能完全适配视口。

动态视口百分比单位的尺寸即使视口本身不变也不稳定。 使用这些单位可能导致内容在滚动等操作中随时重排, 可能影响用户体验和性能。

UA 不要求在界面动画(展开/收起)时对 动态视口百分比单位 进行动画, 可以直接按界面完全展开或收起时计算单位。 (建议 UA 在此期间假定完全收起尺寸。)

某一界面的展开/收起 (A) 是否导致所有 视口百分比长度(及初始包含块)同时改变, 还是 (B) 只体现在 大视口尺寸 与 小视口尺寸 的差异, 主要由 UA 决定。 但:

无论何种情况, 若 overflow 或 scrollbar-gutter 在 根元素任一轴上 会无条件导致滚动条出现(或预留空间) (如 overflow: scroll,但不是 overflow: auto), 该轴的视口百分比长度的计算值 会按初始包含块减少。 否则, 且在 媒体查询下始终如此, 视口百分比长度假定无滚动条 (即使与初始包含块不一致)。

注意: overflow 在 body 元素 上有时会影响 根元素 是否出现滚动条。 但这不会影响视口单位大小。

6.1.2.2. 各种视口相关单位

视口百分比长度单位包括:

vw
svw
lvw
dvw
分别等于 大视口尺寸、小视口尺寸、大视口尺寸 和 动态视口尺寸 宽度的 1%。
下例中,若视口宽为 200mm, h1 元素的字体大小将为 16mm (即 (8×200mm)/100)。
h1 { font-size: 8vw }
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 中较大者。

注意: 最初(无前缀)视口单位定义为相对于初始包含块, 在连续媒体中总是与唯一视口尺寸一致。 浏览器 chrome 在滚动中动态变化是后来的发明,大多数 UA 按 Safari 的实现将这些单位映射到较大尺寸。 这种定义在很多场合更美观,但也可能遮挡关键内容(如工具栏、头部、底部)。 因此这种映射是否最佳尚无定论,早期规范允许 UA 选择默认单位的映射。 但目前为 Web 兼容性,假定必须映射到大视口百分比单位。

无元素或尚未样式化时(如评估媒体查询), *vi 和 *vb 单位用 writing-mode 属性的初始值决定各自的轴。

6.2. 绝对长度:cm、mm、Q、in、pt、pc、px 单位

绝对长度单位彼此有固定关系,并锚定到物理度量。 主要用于已知输出环境时。 绝对单位包括 物理单位(in、cm、mm、pt、pc、Q) 和 视觉角度单位(像素单位)(px):

单位 名称 换算关系
cm 厘米 1cm = 96px/2.54
mm 毫米 1mm = 1cm 的 1/10
Q 四分之一毫米 1Q = 1cm 的 1/40
in 英寸 1in = 2.54cm = 96px
pc 派卡(pica) 1pc = 1in 的 1/6
pt 点(point) 1pt = 1in 的 1/72
px 像素 1px = 1in 的 1/96
h1 { margin: 0.5in }      /* 英寸  */
h2 { line-height: 3cm }   /* 厘米 */
h3 { word-spacing: 4mm }  /* 毫米 */
h3 { letter-spacing: 1Q } /* 四分之一毫米 */
h4 { font-size: 12pt }    /* 点 */
h4 { font-size: 1pc }     /* 派卡 */
p  { font-size: 12px }    /* px */

注意: 出版领域的长度有时写作 2p3, 表示 2 派卡 3 点的长度。 在 CSS 中可写作 calc(2pc + 3pt)(参见 § 10.1 基本算术:calc())。

所有绝对长度单位都是兼容的, 而 px 是其规范单位。

对于 CSS 设备,这些尺寸的 锚定单位可通过以下任一方式:

  1. 将物理单位与物理度量相关联,或
  2. 将像素单位与参考像素相关联。

对于典型阅读距离下的印刷介质, 锚定单位应为物理单位(英寸、厘米等)。 对于屏幕介质(包括高分辨率设备)、低分辨率设备及其它特殊距离设备, 推荐用 锚定单位 为像素单位。 这类设备建议 像素单位 指向最接近参考像素的整数个设备像素。

注意: 当锚定单位是像素单位时, 物理单位可能与实际物理尺寸不符。 若 锚定单位为物理单位, 像素单位可能无法与整数个设备像素精确对应。

注意: 本规范对像素单位与物理单位的定义不同于 CSS1、CSS2 早期版本。 早期版本中,像素单位和物理单位没有固定比例: 物理单位始终与物理尺寸相关,而像素单位会随参考像素变化。 (此变更主要是因大量现有内容假定 96dpi,改变会严重破坏兼容性。)

注意: 单位ASCII 不区分大小写,序列化为小写,例如 1Q 序列化为 1q。

参考像素 指在设备像素密度为 96dpi、与读者相距一臂长度的设备上,一个像素所对应的视角。 臂长约 28 英寸时,可视角约 0.0213 度。 按臂长距离阅读时,1px 约为 0.26 mm(1/96 英寸)。

下图展示了视距对参考像素大小的影响: 71 cm(28 英寸)时,参考像素为 0.26 mm, 3.5 m(12 英尺)时,参考像素为 1.3 mm。

该图示说明像素的定义取决于与用户距离。图中用户分别注视两个平面,一个距用户 71 cm,一个 3.5 m。投射的锥体在第一个平面投影像素高 0.26 mm,在第二个平面高 1.4 mm。
显示视距增加时像素也要变大

下图展示了设备分辨率对像素单位的影响:1px*1px 区域在低分辨率设备(如普通显示器)由一个点覆盖,在高分辨率设备(如打印机)由 16 个点覆盖。

该图示说明参考像素与设备像素的关系。左边高分辨率激光打印机输出,右边低分辨率显示器。激光打印机一个参考像素用 16 个点实现,显示器用 1 个点。
显示高分辨率设备上需更多设备像素(点)覆盖 1px*1px 区域

设备像素 是设备输出上能显示全色域的最小面积单元。 常见彩色屏幕中为包含红绿蓝子像素的正方形或矩形区域。 许多非传统输出可能模糊此定义,如某些颜色分辨率更高的设备。 这些设备仍会暴露等价的“设备像素”概念。

7. 其他数量单位

7.1. 角度单位:<angle> 类型及 deg、grad、rad、turn 单位

角度值是<dimension>,用 <angle> 表示。 角度单位标识符包括:

deg
度。一个完整圆有 360 度。
grad
梯度,也称为“gon”或“grade”。一个完整圆有 400 梯度。
rad
弧度。一个完整圆有 2π 弧度。
turn
圈。一个完整圆为 1 turn。

例如,直角可写作 90deg、100grad、0.25turn 或约 1.57rad。

所有 <angle> 单位都是兼容的, deg 是它们的规范单位。

按惯例, 当角度在 CSS 中表示方向时, 通常解释为 方位角, 即 0deg 是屏幕“上方”或“北方”, 角度增大顺时针方向增加(例如 90deg 是“右”或“东”)。

例如,在 linear-gradient() 函数中, 用于确定渐变方向的 <angle> 就按方位角解释。

注意: 出于兼容性原因, 某些 <angle> 的用法允许裸 0 表示 0deg。 但这不是通用规则,未来也不会出现在 <angle> 类型的新用法中。

7.2. 时长单位:<time> 类型及 s、ms 单位

时间值是带单位数值,用 <time> 表示。 时间单位标识符包括:

s
秒。
ms
毫秒。1 秒等于 1000 毫秒。

所有 <time> 单位都是兼容的, s 是它们的规范单位。

属性可以限制时长值的取值范围。 如果值超出允许范围, 声明无效,必须被忽略。

7.3. 频率单位:<frequency> 类型及 Hz、kHz 单位

频率值是带单位数值,用 <frequency> 表示。 频率单位标识符包括:

Hz
赫兹。表示每秒发生的次数。
kHz
千赫兹。1 千赫兹等于 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 中包含多少个点。 用法见如 resolution 媒体查询([MEDIAQ])或 image-resolution 属性([CSS3-IMAGES])。

所有 <resolution> 单位都是兼容的, dppx 是它们的规范单位。

<resolution> 的取值范围始终排除负值,此外还可有其他显式范围限制。

注意,由于 CSS in 与 CSS px 的 1:96 固定比例,1dppx 等价于 96dpi。 这与 CSS 下图片的默认分辨率对应,详见 image-resolution。

下例 @media 规则用 Media Queries [MEDIAQ] 为每个 CSS px 单位用两个及以上设备像素的设备分配特殊样式:
@media (min-resolution: 2dppx) { ... }

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 的插值。

<color> 类型不可加。

注意: 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. 二维定位:<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> 会贪婪地解析,尽可能多地消耗成分。

例如,transform-origin 定义了三维位置,实质为 <position> <length>?。 left 50px 会被解析为二值 <position>(省略 z 分量); 而 top 50px 会被解析为单值 <position> 后跟一个 <length>。

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% - 2em);

下方定义了数学函数。 其他函数式记法在各自模块中定义; 例如 <color> 函数见 [CSS-COLOR-4] 和 [CSS-COLOR-5]。

10. 数学表达式

数学函数 (calc()、clamp()、sin() 等本章定义的函数) 允许用数学表达式书写 CSS 数值。

数学函数表示一种数值, 可以是:

……或<length-percentage> 等混合类型,并可在任何该类型值可用处使用。

10.1. 基础算术:calc()

calc() 函数是一种数学函数,可对数值进行加(+)、减(-)、乘(*)、除(/)和括号内的基础算术运算。

calc() 函数包含一个 计算, 即一串值与运算符交错组成的序列,可用括号分组 (符合 <calc-sum> 语法), 表示采用标准运算符优先级规则 (* 与 / 优先于 + 与 -,其余左到右)求值的结果。 calc() 函数表示其内部计算的结果。

计算的组成可为字面值 (如 5px), 其他数学函数, 或其他表达式(如 var()), 只要能求值为有效参数类型(如 <length>)。

数学函数可以组合不同单位的值。 下例作者希望每个 section 的外边框盒占据 1/3 空间, 于是从 100%/3 开始, 再减去元素的边框和外边距。 (box-sizing 可自动处理边框和内边距, 但如要包括外边距,需用 数学函数。)

section {
  float: left;
  margin: 1em; border: solid 1px;
  width: calc(100% / 3 - 2 * 1em - 2 * 1px);
}

类似地,下例中的渐变色带只在元素的第一个和最后一个 20px 处出现颜色过渡:

.fade {
  background-image: linear-gradient(silver 0%, white 20px,
                                    white calc(100% - 20px), silver 100%);
}

数学函数也可用于让数值表达更自然易读, 而不是晦涩的小数。 例如,下例将 font-size 设为正好 35em 填满视口, 保证无论屏幕大小如何,屏幕内容始终大致一样多。

:root {
  font-size: calc(100vw / 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 {
  /* 字号为 vw 和 vh 平均数的10倍,但不得小于12px */
  font-size: max(10 * (1vw + 1vh) / 2, 12px);
}

注意: 每个参数都可用完整数学表达式,无需嵌套 calc()! 你也可以传多个参数,适用于多重约束。

用 min()/max() 时常见困惑是,用 max() 实际上是给某值加最小值 (如 min-width 实际用的是 max()), 而 min() 则用作限定最大值; 很容易用错,比如试图用 min() 加最小值。 用 clamp() 代码更直观, 因为它把值夹在最小和最大之间:
.type {
  /* 字号限定在 12px 和 100px 之间 */
  font-size: clamp(12px, 10 * (1vw + 1vh) / 2, 100px);
}

或者只想限定最小值,允许字号随意变大:

.type {
  /* 字号至少 12px */
  font-size: clamp(12px, 10 * (1vw + 1vh) / 2, none);
}
注意 clamp() 与 CSS 其它惯例一致, 若最小值与最大值顺序颠倒,以最小值为准。 即 clamp(100px, ..., 50px) 会返回 100px,超过其“最大值”。

如需其他裁剪逻辑,可结合 clamp()、min() 或 max():

让 MAX 优先生效:

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进行舍入,舍入到最接近A的B的整数倍(可以是大于或小于A)。参数 calculations 可以解析为任何 <number>、<dimension> 或 <percentage>,但必须具有一致类型,否则函数无效;结果的类型将是 一致类型。

如果A恰好等于B的整数倍,round()精确返回A(如果相关,会保留A是0⁻还是0⁺)。 否则,B的两个整数倍可能“最接近”A,lower 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 这类拥有自然“精度”(整数)可用于舍入的语言,CSS值没有这样的精度,因为值可以用许多不同的兼容单位书写。因此,精度必须被显式给出;要将宽度舍入到最接近的 50px,可以写作 round(var(--width), 50px)。

注意: 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的整数倍(大于或小于A均可)之间的差值。 参数 calculations 可解析为 <number>、<dimension> 或 <percentage>,但必须有相同的类型,否则函数无效;结果的类型与参数相同,类型为参数类型。

这两个函数非常相似,实际上当两个参数都为正或都为负时,返回结果完全一致:函数值等于A减去能使结果在零与B之间的B的整数倍。(具体来说,区间包含零但不包含B。更精确地说,如果B为正,则区间从0⁺开始,如果B为负,则从0⁻开始。)

例如,mod(18px, 5px) 的值为 3px,因为 18px 减去 5px * 3 等于 3px,这是唯一处于 0px 和 3px 之间的值。

类似地,mod(-140deg, -90deg) 的值为 -50deg,因为 -140deg 加上 -90deg * 1 等于 -50deg,这是唯一处于 0deg 和 -90deg 之间的值。

将这些示例用 rem() 计算,结果完全相同。

当A值与B步长符号相反时,这两个函数的行为会不同:mod()(即“模”)依然选择能让结果在零与B之间的B的整数倍(保证结果要么为零,要么与B同号,不与A同号),而rem()(即“余数”)选择让结果在零与-B之间的B的整数倍,避免改变值的符号。

例如,mod(-18px, 5px) 的值为 2px:-18px 加 5px * 4 等于 2px,位于 0px 和 5px 之间。

而 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。因此,通常更期望结果在0与B之间,而不管A的符号如何,这时应选择 mod()。

比如,如果作者想知道一个长度是否是偶数或奇数像素,mod(A, 2px) 会返回 0px 或 1px(假设该值本来就是整数像素),与A的正负无关。而 rem(A, 2px),如果A是偶数像素会返回0px,但如果是奇数像素,则会返回1px或-1px,取决于A的正负。

不过,也会有相反的需求,因此提供了 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相同的无穷大。

如果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,atan2(-1, 1)(点为(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 等),数值结果为实现自定。如果实现能精确表示这些输入,应在 90deg + N*360deg 的渐近处返回+∞,在 -90deg + N*360deg 处返回−∞,但实现不要求必须能精确表示这些输入(如果不能,将返回其能表示的最接近输入的正确数值结果)。作者不得依赖 tan() 在这些输入下返回特定值。

为什么这些值是实现自定?

正切函数在其渐近点是不连续的:它在一侧趋向正无穷,在另一侧趋向负无穷,且在渐近点本身没有定义。

此外,实现能否精确表示这些渐近点,取决于内部如何存储和处理角度;以度为单位时这些值很简单(如90deg),但以弧度表示时这些值是超越数(如pi / 2),无法精确表示。因此,即便要定义特定行为也比较困难;如果实现内部用弧度,需要做模糊匹配,才能在输入足够接近渐近点时返回预期结果。

Web 另一主流语言 JavaScript,这些函数只接受弧度,因此也无法精确遇到渐近点(大多数其他语言亦如此)。JS中写代码时也无法依赖这些值的特定行为,CSS的需求也不太可能有本质不同。

对于能精确表示渐近点的实现,建议的行为可以保证与 atan() 函数的互相转换:tan(atan(X)) 和 atan(tan(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
−∞ -finite 0⁻ 0⁺ +finite +∞
Y −∞ -135deg -90deg -90deg -90deg -90deg -45deg
-finite -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
+finite 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维向量的长度。(即其参数平方和的平方根。)参数 calculations 可解析为 <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 issue),即只对数值平方,单位不变。但这样结果就取决于参数的单位;如果 1em 是 16px,那么 pow(1em, 2) 是 1em,而 pow(16px, 2) 是 256px 或 16em,同样参数实际得到的结果却完全不同!CSS允许值自由规范化,而且更复杂表达式如 pow(2em + 10px, 2) 也很难解释。

同样,强制作者先转数字再转回单位可以回避这些问题;pow(30, 2) 就是 900,作者可自行解释这个值。


而 hypot() 则不存在这些问题。单位的数值精度无需担心,输入输出类型一致。结果也不依赖单位,因为其运算本质如此;hypot(3em, 4em) 和 hypot(48px, 64px) 在 1em 等于 16px 时都得到相同的长度:5em 或 80px。所以允许作者直接在 hypot() 中用带单位的值。

log(A, B?) 函数包含一个或两个 计算(分别为待取对数的值和对数的底,底默认为e),必须解析为<number>,返回A以B为底的对数,结果为 <number>,返回类型与输入 计算类型保持一致。

exp(A) 函数包含一个 计算,必须解析为 <number>,返回 pow(e, A) 的值,结果为 <number>,返回类型与输入 计算类型保持一致。

pow() 函数在如 CSS Modular Scale 这种策略中很有用,它让页面上所有字体大小都按固定比率相关联。

这些大小可以很容易地写成自定义属性:

:root {
  --h6: calc(1rem * pow(1.5, -1));
  --h5: calc(1rem * pow(1.5, 0));
  --h4: calc(1rem * pow(1.5, 1));
  --h3: calc(1rem * pow(1.5, 2));
  --h2: calc(1rem * pow(1.5, 3));
  --h1: calc(1rem * pow(1.5, 4));
}

...而不是直接写预先计算好的数值如 5.0625rem (即 calc(1rem * pow(1.5, 4)) 的值),这样在样式表中来源不明。

单参数时,hypot() 返回输入的绝对值;hypot(2em) 和 hypot(-2em) 都得 2em。

多参数时,它给出以这些值为边长的盒子的主对角线长度。这在与变换相关的场景很有用,比如计算元素在按某个X、Y、Z量平移时实际移动的距离。

例如,hypot(30px, 40px) 结果为 50px,这正是元素经 translate(30px, 40px) 变换后起止位置间的距离。如果作者希望元素随着距离增大而变小(比如做词云),就能用这个距离做缩放因子。

单参数时,log() 返回参数的“自然对数”(以e为底),与JavaScript一致。

如果想要以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或负数,B在0到1之间或大于1都有效。结果为NaN。若A为负数,结果为NaN。若A为0⁺或0⁻,结果为−∞。若A为1,结果为0⁺。若A为+∞,结果为+∞。

在 exp(A) 中,若A为+∞,结果为+∞。若A为−∞,结果为0⁺。

(关于§ 10.9 类型检查,以及数学函数如何处理NaN和无穷大,详见该节。)

所有这些行为都旨在与大多数编程语言,尤其是JS中的“标准”定义一致。

唯一不同于JS同名函数的地方在于,NaN在所有函数中都是“传染性”的:只要有任意参数为NaN,函数就返回NaN。

JS 行为细节

JS中有两种情况NaN不会“传染”到数学函数:

  • Math.hypot(Infinity, NaN) 会返回 Infinity。

  • Math.pow(NaN, 0) 会返回 1。

逻辑似乎是,只要把NaN替换成任意数,返回值都一样。但JS的 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. 数值变量

其它规范可定义可在特定上下文下用于计算的额外关键词。例如,relative color 语法定义了多个颜色通道关键词,表示每个通道的值为 <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> 值为有效值。 (例如,在 relative color 语法中,适当的通道关键字是允许的。)

此外,在 + 和 - 运算符两侧必须有 空白。 (* 和 / 运算符可以不带空白使用。)

上面的一些数学函数对其 <calc-sum> 参数有额外限制。 详见各个函数的定义。

UA 必须至少支持包含 32 个 <calc-value> 项的 计算,以及至少 32 层嵌套(括号或函数)。 对于支持可变参数个数的函数(如 min()),还必须至少支持 32 个参数。 如果一个 计算 项数、参数数或嵌套层数超过支持上限,则必须视为无效。

10.9. 类型检查

数学函数可以有多种类型,比如 <length>、<number> 等,取决于其包含的 计算,详见下文。 它可以用在允许该类型值的任何地方。

例如,width 属性接受 <length> 值,所以一个能解析为 <length> 的 数学函数,比如 calc(5px + 1em),可以用于 width。

此外,数学函数若求值为 <number>,就可以用于只接受 <integer> 的位置;值会在求值时舍入到最接近的整数。

运算符会形成子表达式,其类型由参数决定。

注意: 之前的规范版本对乘除法参数有限制,避免产生更复杂的中间结果(如 1px * 1em,即 <length>²),并便于在解析时检测除零。本版本已放宽这些限制。

要确定计算的类型:
一个值包含百分比,当其 类型为«[ "percent" → 1 ]»,或类型的百分比提示非空。
两个或多个计算具有一致类型,当相加类型不失败时。 一致类型为类型相加的结果。
要使类型 base 与 input 一致:
  1. 若 base 和 input 都有不同的非空百分比提示,则不能使其一致,返回失败。

  2. 若 base 的百分比提示为null,则将base的 百分比提示设为input的百分比提示。

  3. 返回 base。

数学函数本身有类型,由其包含的计算决定:

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> 在 used-value 阶段会变为 <length>(如 line-height 及 tab-size),<number> 在 calc() 中永远不会变成“类长度”。它们始终是 <number>。

注意: 在怪异模式 [QUIRKS] 下,一些本只接受 <length> 的属性也定义为接受 <number>,并将其解释为 px 长度。和无单位零一样,这对 数学函数 的解析和行为无影响,不过解析为 数学函数 为 <number> 的,在怪异模式下可能变为有效(并作为 px 长度解释)。

10.9.1. 无穷大、NaN 与有符号零

数学函数遵循 IEEE-754 语义,意味着它们识别正零和负零、正无穷和负无穷,以及 NaN(非数)。

不过,这些概念只在 计算树 内保留;如果 顶层计算(即未直接嵌套于其他 数学函数中的 数学函数)会产生这些特殊值,则会“屏蔽”为标准可表示值,详见下文。

有符号零(此处记为 0⁺ 或 0⁻)不能在 CSS 中直接书写;0、+0 和 -0 都产生标准“无符号”零,规则上视为正(0⁺)。

有符号零 可通过以下方式产生:

有符号零 不会逃逸 顶层计算;会被屏蔽成“无符号”零。

无穷大 (此处记为 +∞ 或 −∞) 可通过 数学常量 infinity 和 -infinity 直接书写,也可由一些计算产生:

注意: 下面 NaN 的产生规则优先于上述产生无穷大的规则。

无穷大 不会逃逸 顶层计算;会被裁剪到上下文允许的最小或最大值,详见 § 10.12 范围检查。

NaN(即“非数”,not a number) 是某些无定义结果运算的结果。 可通过 数学常量 NaN 直接书写,也可由一些计算产生:

NaN 不会逃逸 顶层计算;会被屏蔽为零值。

例如,calc(-5 * 0) 会得到无符号零——计算结果是 0⁻,但作为 顶层计算,会被屏蔽为无符号零。

而 calc(1 / calc(-5 * 0)) 会得到 −∞,与 calc(1 / (-5 * 0)) 一样——内部 calc 得到 0⁻,作为非 顶层计算,原样传递给外层 calc 从而得 −∞。若被屏蔽为无符号零,则会得到 +∞。

10.10. 内部表示

内部表示指的是数学函数的计算树:一个树结构,分支节点为运算符节点,对应于数学函数(如 Min、Cos、Sqrt 等)或计算中的运算符(Sum、Product、Negate 和 Invert,即calc-operator 节点),叶节点为数值(如数字、带单位数、百分比)或可解析为数值类型的非数学函数。

数学函数根据函数类型被转换为计算树:

calc()

内部表示对于 calc() 函数而言,是从其参数解析计算的结果。

其他任意数学函数

内部表示为与函数同名的运算符节点,其子节点为对每个参数解析为计算的结果,顺序与参数一致。

解析一个计算时,给定一个计算values,它以组件值列表表示,返回计算树:
  1. 丢弃values中的所有<whitespace-token>。

  2. 若values中的某项为<delim-token>,且值为 "+", "-", "*", "/",则为“运算符”;否则为“值”。

  3. 收集子节点到 Product 和 Invert 节点中。

    对于values中连续由"*"或"/"分隔的值项:

    1. 将每个 "/" 运算符右侧的值项 rhs 替换为以 rhs 为子节点的 Invert 节点。

    2. 将整个序列替换为以这些值项为子节点的 Product 节点。

  4. 收集子节点到 Sum 和 Negate 节点中。

    1. 将每个 "-" 运算符右侧的值项 rhs 替换为以 rhs 为子节点的 Negate 节点。

    2. 如果values只剩一个项,且为 Product 节点或括号包裹的simple block,用该项替换values。

      否则,用以values值项为子节点的 Sum 节点替换values。

  5. 此时 values 是 Sum、Product、Negate、Invert 节点组成的树,叶节点为其它类型的值。处理叶节点:

    对values中每个叶节点 leaf:

    1. 如 leaf 为括号包裹的简单块,用从 leaf 的内容解析计算所得的结果替换 leaf。

    2. 如 leaf 为数学函数,用该函数的内部表示替换该叶节点。

  6. 返回简化计算树的结果。

10.10.1. 简化

内部表示会对数学函数尽可能进行即时简化,采用标准代数化简(如乘法分配、同单位合并等)。

用于非属性上下文(如@font-face描述符)时,数学函数按指定值方式简化。

简化计算树 root:
  1. 如 root 为数值:

    1. 如为待解析的百分比且有足够信息,解析为实际数值,并用对应规范单位表达,返回该值。

    2. 如果 root 是未以其规范单位表示的带单位数,并且有足够信息将其转换为规范单位,则执行转换并返回该值。

    3. 如为可解析的<calc-keyword>,返回其解析结果并简化。

    4. 否则,返回 root。

  2. 如 root 为其它叶节点(非运算符节点):

    1. 如有足够信息确定其数值,返回其值,并用规范单位表达。

    2. 否则,返回 root。

  3. 此时 root 为运算符节点。简化其所有计算子节点。

  4. 如 root 为非calc-operator 节点的运算符节点,且其所有计算子节点均为数值,并有足够信息计算 root 所表示的运算,则以这些子节点执行该运算并返回结果,并用规范单位表达。

    此时若仍有百分比,通常会阻止该节点进一步简化,因为还需其他值解析百分比(否则前面已经被转为具体值)。比如 "min" 操作,因为百分比可能基准为负,比较关系可能变化。

    但“原始”百分比(如opacity属性)不需解析基准时,可能不会阻止简化。

  5. 如 root 为 Min 或 Max 节点,尝试部分简化:

    1. 遍历root的所有子节点 child:

      如 child 为可比较大小的数值,且有其它同单位的数值子节点,则将所有同单位子节点合并为一个值,替换 child,移除其它相关子节点。

    2. 如 root 只剩一个子节点,返回该子节点,否则返回 root。

  6. 如 root 为 Negate 节点:

    1. 如其子节点为数值,返回一个相等数值但取反(0 - value)。

    2. 如其子节点为 Negate 节点,返回子节点的子节点。

    3. 返回 root。

  7. 如 root 为 Invert 节点:

    1. 如其子节点为数字(非百分比/维度),返回其倒数。

    2. 如其子节点为 Invert 节点,返回子节点的子节点。

    3. 返回 root。

  8. 如 root 为 Sum 节点:

    1. 将子节点为 Sum 节点的,替换为其子节点。

    2. 对同单位数值子节点,合并为一个数值节点,单位相同。

      (如合并纯数字、百分比、px值等)

    3. 如只剩一个子节点,返回该节点,否则返回 root。

    注意: 零值项不能直接从 Sum 移除,只能与同单位值合并。(因为即便为零,单位有时会影响行为。)

  9. 如 root 为 Product 节点:

    1. 将子节点为 Product 节点的,替换为其子节点。

    2. 如有多个数字子节点(非百分比/维度),合并为一个数字。

    3. 如仅有两个子节点,一个为数字,一个为所有子节点为数值的 Sum,给 Sum 的每个子节点乘以该数字,返回 Sum。

    4. 如果 root 仅包含数值和/或包含数值的 Invert 节点,且对所有子节点的类型进行相乘(Invert 节点的类型是其子节点类型的逆)后所得的类型匹配数学函数可解析为的任一类型,则将所有子节点的值相乘(Invert 节点的值是其子节点值的倒数),返回结果并用规范单位表达。

    5. 返回 root。

10.11. 计算值

计算值指数学函数的计算树,在计算值时利用所有可用信息简化后的结果。(如 em 到 px 比例,某些属性下百分比的解析方式等。)

若百分比在计算值阶段未解析,则在数学函数中同样不解析。例如 calc(100% - 100% + 1px) 结果为 calc(0% + 1px),而不是 1px。如某些属性对百分比有特殊计算规则(如height),则只要含百分比的数学函数都适用该规则。

计算树会在使用值阶段再次简化;利用使用值时的信息,数学函数最终总能简化为单一数值。

例如,font-size 的百分比在计算值阶段就会解析,以便计算字体相关长度单位,而background-position的百分比则依赖布局,直到使用值阶段才解析。

因此,background-position 的计算会在 calc() 中保留百分比,而 font-size 会直接算成长度。

鉴于表格单元格和表格元素宽高计算的复杂性,同时混合百分比和非零长度用于表格列、列组、行、行组、单元格宽高的数学表达式(无论自动还是固定布局表),必须视为指定了 auto。

10.12. 范围检查

在数学函数中不会进行解析时的范围检查,因此超出范围的值不会导致声明无效。但顶层计算的结果必须被裁剪到目标上下文允许的范围。裁剪会在计算值阶段尽可能进行,如无法完全简化以检查范围,则在使用值阶段裁剪。(裁剪不会在指定值阶段进行。)

注意: 所有接受 calc() 的上下文都必须定义为闭区间(不是开区间)。

注意: 定义上,±∞ 总在任何属性允许范围之外,会裁剪为最小值或最大值。即使某些属性语法允许用关键字表达无穷大(如 animation-iteration-count),最终也会裁剪 ±∞,因为数学函数不能解析为关键字;属性的数值部分总有最小/最大值。

另外,如数学函数解析为<number>,而用于只接受<integer>的地方,则计算值和使用值同样四舍五入为最接近整数,如同上面的裁剪。

由于宽度不能小于 0px,以下三种声明等价:
width: calc(5px - 10px);
width: calc(-5px);
width: 0px;

但注意 width: -5px 不等价于 width: calc(-5px)! 超出范围的值在 calc() 外是语法无效的,会导致整个声明被丢弃。

10.13. 序列化

本节仍在讨论中。

要序列化一个数学函数 fn:
  1. 如果fn对应的计算树的根节点是数值(数字、百分比或带单位数),且当前要序列化的是计算值或更晚阶段,则将其裁剪到上下文允许的范围(如有必要),按正常方式序列化该值并返回。

  2. 如果fn表示无穷或NaN值:

    1. 令s为字符串 "calc("。

    2. 将fn的值对应的关键词 infinity、-infinity 或 NaN 序列化,并追加到s后。

    3. 如果fn的类型不是«[ ]»(即非纯 <number>),则在s后追加" * "。用fn的类型所对应的规范单位(如 px 对应<length>)创建一个数值1,序列化该数值并追加到s后。

    4. 返回s。

  3. 如果计算树的根节点是数值或calc-operator 节点,令s为字符串 "calc("。否则,令s为根节点名称的小写(如 "sin" 或 "max"),再加一个左括号"("。

  4. 对根节点的每个子节点,序列化计算树。如结果以 "(" 开头且以 ")" 结尾,去掉这两个字符。将所有结果用", "(逗号加空格)拼接,再追加到s。

  5. 在s后追加")"(右括号)。

  6. 返回s。

要序列化计算树:
  1. 令root为计算树的根节点。

  2. 如果root是数值或非数学函数,按其常规规则序列化并返回结果。

  3. 如果root不是 Sum、Negate、Product 或 Invert 节点,则为对应函数序列化数学函数,其子节点作为函数逗号分隔的计算参数,并返回结果。

  4. 如root为 Negate 节点,令s为初始包含 "(-1 * " 的字符串。序列化其子节点并追加到s。追加")"并返回。

  5. 如root为 Invert 节点,令s为初始包含 "(1 / " 的字符串。序列化其子节点并追加到s。追加")"并返回。

  6. 如root为 Sum 节点,令s为初始包含 "(" 的字符串。排序 root 的子节点。序列化第一个子节点并追加到s。遍历其余子节点:

    1. 如child为 Negate 节点,追加" - "到s,再序列化Negate的子节点并追加到s。

    2. 如child为负数,追加" - "到s,再序列化其相反数并追加。

    3. 否则,追加" + "到s,再序列化child并追加。

    最后追加")"并返回。

  7. 如root为 Product 节点,令s为初始包含 "(" 的字符串。排序 root 的子节点。序列化第一个子节点并追加到s。遍历其余子节点:

    1. 如child为 Invert 节点,追加" / "到s,再序列化Invert的子节点并追加。

    2. 否则,追加" * "到s,再序列化child并追加。

    最后追加")"并返回。

要排序计算的子节点 nodes:
  1. 令ret为一个空列表。

  2. 如nodes包含数字,将其移出并加入ret。

  3. 如nodes包含百分比,将其移出并加入ret。

  4. 如nodes包含带单位数,将它们移出,按单位以ASCII 不区分大小写的顺序排序,追加到ret。

  5. 如nodes还有其他项,按原顺序追加到ret。

  6. 返回ret。

例如,calc(20px + 30px) 作为指定值序列化为 calc(50px),作为计算值序列化为 50px。

类似 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个背景图片的效果。

协调型列表属性组会创建一个协调值列表,每一项包含该组内各属性的一个值,这些值共同定义一个效果,如一层背景或一个动画。协调值列表按如下方式组装:

附录B:IANA相关事项

为 about:invalid URL 方案注册

本节定义并注册 about:invalid URL,符合[RFC6694]定义的注册流程。

官方注册记录见 http://www.iana.org/assignments/about-uri-tokens/about-uri-tokens.xhtml。

注册Token invalid
预期用途 about:invalid URL 用于指向不存在的文档和通用错误条件。当需要URL但默认值不应能被解析为任何类型文档时,可用此URL。
联系方式/变更控制 CSS WG <www-style@w3.org>(代表W3C)
规范 CSS Values and Units Module Level 3

附录C:怪异长度(Quirky Lengths)

当CSS在怪异模式下被解析时,<quirky-length> 是一种 <length> 类型,仅在以下特定属性中有效:

它不在包含或引用这些属性的属性中有效,比如 background 简写属性,或出现在如 函数式表示法(如 calc())中,除了在 rect() 作为 clip 属性时必须允许。

另外,<quirky-length> 在 <length> 作为受影响属性被 @supports 规则解析时必须有效,但在 CSS.supports() 方法中用于这些属性时不有效。

<quirky-length> 在语法上与 <number-token> 完全相同,且会被解释为值相同的 px 长度。

(换句话说,怪异模式允许受影响属性中的所有 px 长度可以不加单位直接书写,类似于无单位的0长度。)

致谢

首先,编辑们要感谢所有为本规范前一版本做出贡献的人。

其次,我们要感谢 Anthony Frehner、Emilio Cobos Álvarez、Koji Ishii、Noam Rosenthal 和 Xidorn Quan 的意见和建议,这些都改进了第4级规范。

变更记录

近期变更

(本节为自第3级以来的增补的子集。)

自2023年12月18日 WD以来的重大变更:

自2023年10月27日 WD以来的重大变更:

自2023年4月6日 WD以来的重大变更:

自2022年10月19日 WD以来的重大变更:

自2021年12月16日 WD以来的重大变更:

自2021年10月16日 WD以来的变更:

自2021年9月30日 WD以来的变更:

自2021年7月15日 WD以来的变更:

自2020年11月11日 WD以来的变更:

自第3级以来的增补

自CSS Values and Units Level 3以来变更:

自CSS Values and Units Level 3以来的增补:

安全性注意事项

本规范未引入新的安全性注意事项。

本规范定义了 url() 和 src() 函数(<url>),允许CSS发起网络请求。根据它们所用于的特性,这些请求可能暴露用户是否能访问某网络资源,并暴露内容信息(如样式表规则、图片尺寸、字体度量等),还可能通过URL泄露数据。

隐私注意事项

本规范定义了可暴露用户屏幕尺寸的单位(视口百分比长度)、默认字体大小,以及可能暴露部分可用字体信息(字体相关长度)。

本规范定义了 url() 和 src() 函数(<url>),允许CSS发起网络请求。根据其所用特性,这些请求可能暴露用户是否能访问某网络资源,并暴露内容信息(如样式表规则、图片尺寸、字体度量等),也可能通过URL泄露数据。

一致性

文档约定

一致性要求通过描述性断言和 RFC 2119 术语的组合表达。规范性部分中的关键词 “MUST”(必须)、“MUST NOT”(禁止)、“REQUIRED”(要求)、“SHALL”(应当)、“SHALL NOT”(不得)、“SHOULD”(应该)、“SHOULD NOT”(不应该)、“RECOMMENDED”(推荐)、“MAY”(可以)、“OPTIONAL”(可选)需按照 RFC 2119 的说明解释。不过,为了可读性,本规范中这些词不会全部大写。

本规范的所有文本都是规范性的,除非明确标记为非规范性、示例和注释。[RFC2119]

本规范中的示例会以“例如”开头,或以 class="example" 与规范性文本区分,例如:

这是一个信息性示例。

信息性注释以“注意”开头,且用 class="note" 与规范性文本区分,例如:

注意,这是一个信息性注释。

建议性内容为规范性部分,并用特殊样式突出显示,且用 <strong class="advisement"> 区分,例如: UA 必须提供可访问性替代方案。

一致性类别

本规范的一致性定义了三类一致性对象:

样式表
一个CSS 样式表。
渲染器
一个UA,用于解释样式表的语义并渲染使用样式表的文档。
创作工具
一个UA,用于编写样式表。

如果样式表中使用本模块定义语法的所有语句都符合通用 CSS 语法及本模块中每个特性的语法,则该样式表符合本规范。

如果渲染器除按相关规范解释样式表外,还能正确解析并渲染本规范定义的所有特性,则符合本规范。不过,由于设备限制导致 UA 无法正确渲染文档,不视为 UA 不符合规范。(例如,UA 不要求在单色显示器上渲染颜色。)

如果创作工具编写的样式表在语法上符合通用 CSS 语法及本模块每个特性的语法,并满足本模块描述的样式表其它一致性要求,则其符合本规范。

部分实现

为便于作者利用向前兼容的解析规则指定回退值,CSS 渲染器必须将任何没有可用支持级别的 at-规则、属性、属性值、关键字及其他语法结构视为无效(并按需忽略)。特别是,用户代理不得在单个多值属性声明中有选择地忽略不支持的组件值、保留支持的值:如有值无效(不支持的值必须视为无效),则 CSS 要求整个声明被忽略。

不稳定和专有特性的实现

为避免与将来稳定 CSS 特性冲突,CSSWG 推荐遵循最佳实践实现 不稳定特性和 专有扩展。

非实验性实现

一旦规范进入候选推荐(CR)阶段,就可以进行非实验性实现。实现者应当在能够证明已按规范正确实现 CR 级特性时,发布无前缀的实现。

为建立和保持 CSS 在各实现间的互操作性,CSS 工作组请求非实验性 CSS 渲染器在发布任何 CSS 特性的无前缀实现前,向 W3C 提交实现报告(如有必要,还需提交用于该报告的测试用例)。提交给 W3C 的测试用例由 CSS 工作组审核和修正。

更多关于提交测试用例及实现报告的信息,可参考 CSS 工作组网站:https://www.w3.org/Style/CSS/Test/。如有疑问,请联系 public-css-testsuite@w3.org 邮件列表。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性引用

[CSS-2023]
Chris Lilley 等. CSS Snapshot 2023。2023年12月7日。NOTE。URL:https://www.w3.org/TR/css-2023/
[CSS-BOX-4]
Elika Etemad. CSS Box Model Module Level 4。2022年11月3日。WD。URL:https://www.w3.org/TR/css-box-4/
[CSS-CASCADE-5]
Elika Etemad;Miriam Suzanne;Tab Atkins Jr. CSS 级联与继承 第5级。2022年1月13日。CR。URL:https://www.w3.org/TR/css-cascade-5/
[CSS-COLOR-4]
Tab Atkins Jr.;Chris Lilley;Lea Verou. CSS Color Module Level 4。2022年11月1日。CR。URL:https://www.w3.org/TR/css-color-4/
[CSS-COLOR-5]
Chris Lilley 等. CSS Color Module Level 5。2022年6月28日。WD。URL:https://www.w3.org/TR/css-color-5/
[CSS-CONDITIONAL-3]
David Baron;Elika Etemad;Chris Lilley. CSS 条件规则模块 第3级。2022年1月13日。CR。URL:https://www.w3.org/TR/css-conditional-3/
[CSS-COUNTER-STYLES-3]
Tab Atkins Jr.. CSS Counter Styles Level 3。2021年7月27日。CR。URL:https://www.w3.org/TR/css-counter-styles-3/
[CSS-DISPLAY-3]
Elika Etemad;Tab Atkins Jr.. CSS Display Module Level 3。2023年3月30日。CR。URL:https://www.w3.org/TR/css-display-3/
[CSS-EASING-1]
Brian Birtles;Dean Jackson;Matt Rakow. CSS Easing Functions Level 1。2023年2月13日。CR。URL:https://www.w3.org/TR/css-easing-1/
[CSS-FONTS-4]
Chris Lilley. CSS Fonts Module Level 4。2024年2月1日。WD。URL:https://www.w3.org/TR/css-fonts-4/
[CSS-FONTS-5]
Chris Lilley. CSS Fonts Module Level 5。2024年2月6日。WD。URL:https://www.w3.org/TR/css-fonts-5/
[CSS-GRID-2]
Tab Atkins Jr.;Elika Etemad;Rossen Atanassov. CSS Grid Layout Module Level 2。2020年12月18日。CR。URL:https://www.w3.org/TR/css-grid-2/
[CSS-IMAGES-4]
Tab Atkins Jr.;Elika Etemad;Lea Verou. CSS Images Module Level 4。2023年2月17日。WD。URL:https://www.w3.org/TR/css-images-4/
[CSS-INLINE-3]
Dave Cramer;Elika Etemad. CSS Inline Layout Module Level 3。2023年4月1日。WD。URL:https://www.w3.org/TR/css-inline-3/
[CSS-MASKING-1]
Dirk Schulze;Brian Birtles;Tab Atkins Jr.. CSS Masking Module Level 1。2021年8月5日。CR。URL:https://www.w3.org/TR/css-masking-1/
[CSS-OVERFLOW-3]
Elika Etemad;Florian Rivoal. CSS Overflow Module Level 3。2023年3月29日。WD。URL:https://www.w3.org/TR/css-overflow-3/
[CSS-PAGE-3]
Elika Etemad. CSS Paged Media Module Level 3。2023年9月14日。WD。URL:https://www.w3.org/TR/css-page-3/
[CSS-POSITION-3]
Elika Etemad;Tab Atkins Jr.. CSS Positioned Layout Module Level 3。2023年4月3日。WD。URL:https://www.w3.org/TR/css-position-3/
[CSS-SCOPING-1]
Tab Atkins Jr.;Elika Etemad. CSS Scoping Module Level 1。2014年4月3日。WD。URL:https://www.w3.org/TR/css-scoping-1/
[CSS-SHAPES-1]
Rossen Atanassov;Alan Stearns. CSS Shapes Module Level 1。2022年11月15日。CR。URL:https://www.w3.org/TR/css-shapes-1/
[CSS-SIZING-3]
Tab Atkins Jr.;Elika Etemad. CSS Box Sizing Module Level 3。2021年12月17日。WD。URL:https://www.w3.org/TR/css-sizing-3/
[CSS-SYNTAX-3]
Tab Atkins Jr.;Simon Sapin. CSS Syntax Module Level 3。2021年12月24日。CR。URL:https://www.w3.org/TR/css-syntax-3/
[CSS-TEXT-4]
Elika Etemad 等. CSS Text Module Level 4。2023年10月20日。WD。URL:https://www.w3.org/TR/css-text-4/
[CSS-TYPED-OM-1]
Shane Stephens;Tab Atkins Jr.;Naina Raisinghani. CSS Typed OM Level 1。2018年4月10日。WD。URL:https://www.w3.org/TR/css-typed-om-1/
[CSS-VALUES-5]
CSS Values and Units Module Level 5。编辑草案。URL:https://drafts.csswg.org/css-values-5/
[CSS-VARIABLES-1]
Tab Atkins Jr.. CSS Custom Properties for Cascading Variables Module Level 1。2022年6月16日。CR。URL:https://www.w3.org/TR/css-variables-1/
[CSS-WRITING-MODES-4]
Elika Etemad;Koji Ishii. CSS Writing Modes Level 4。2019年7月30日。CR。URL:https://www.w3.org/TR/css-writing-modes-4/
[CSS2]
Bert Bos 等. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification。2011年6月7日。REC。URL:https://www.w3.org/TR/CSS21/
[CSS22]
Bert Bos. Cascading Style Sheets Level 2 Revision 2 (CSS 2.2) Specification。2016年4月12日。WD。URL:https://www.w3.org/TR/CSS22/
[CSS3-BACKGROUND]
Elika Etemad;Brad Kemper. CSS Backgrounds and Borders Module Level 3。2023年12月19日。CR。URL:https://www.w3.org/TR/css-backgrounds-3/
[CSS3-FONTS]
John Daggett;Myles Maxfield;Chris Lilley. CSS Fonts Module Level 3。2018年9月20日。REC。URL:https://www.w3.org/TR/css-fonts-3/
[CSS3-IMAGES]
Tab Atkins Jr.;Elika Etemad;Lea Verou. CSS Images Module Level 3。2023年12月18日。CR。URL:https://www.w3.org/TR/css-images-3/
[CSSOM]
Daniel Glazman;Emilio Cobos Álvarez. CSS 对象模型 (CSSOM)。2021年8月26日。WD。URL:https://www.w3.org/TR/cssom-1/
[DOM]
Anne van Kesteren. DOM 标准。现行标准。URL:https://dom.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch 标准。现行标准。URL:https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren 等. HTML 标准。现行标准。URL:https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren;Domenic Denicola. Infra 标准。现行标准。URL:https://infra.spec.whatwg.org/
[MEDIAQUERIES-5]
Dean Jackson 等. Media Queries Level 5。2021年12月18日。WD。URL:https://www.w3.org/TR/mediaqueries-5/
[RFC2119]
S. Bradner. 用于RFC中的需求程度关键词。1997年3月。最佳当前实践。URL:https://datatracker.ietf.org/doc/html/rfc2119
[UNICODE]
Unicode 标准。URL:https://www.unicode.org/versions/latest/
[URL]
Anne van Kesteren. URL 标准。现行标准。URL:https://url.spec.whatwg.org/
[WEB-ANIMATIONS-1]
Brian Birtles 等. Web Animations。2023年6月5日。WD。URL:https://www.w3.org/TR/web-animations-1/

参考性引用

[CSS-ANIMATIONS-1]
David Baron 等. CSS Animations Level 1。2023年3月2日。WD。URL:https://www.w3.org/TR/css-animations-1/
[CSS-BREAK-3]
Rossen Atanassov;Elika Etemad. CSS Fragmentation Module Level 3。2018年12月4日。CR。URL:https://www.w3.org/TR/css-break-3/
[CSS-CASCADE-3]
Elika Etemad;Tab Atkins Jr.. CSS 级联与继承 第3级。2021年2月11日。REC。URL:https://www.w3.org/TR/css-cascade-3/
[CSS-COLOR-3]
Tantek Çelik;Chris Lilley;David Baron. CSS Color Module Level 3。2022年1月18日。REC。URL:https://www.w3.org/TR/css-color-3/
[CSS-GRID-1]
Tab Atkins Jr. 等. CSS Grid Layout Module Level 1。2020年12月18日。CR。URL:https://www.w3.org/TR/css-grid-1/
[CSS-OVERFLOW-4]
David Baron;Florian Rivoal;Elika Etemad. CSS Overflow Module Level 4。2023年3月21日。WD。URL:https://www.w3.org/TR/css-overflow-4/
[CSS-RHYTHM-1]
Koji Ishii;Elika Etemad. CSS Rhythmic Sizing。2017年3月2日。WD。URL:https://www.w3.org/TR/css-rhythm-1/
[CSS-TEXT-3]
Elika Etemad;Koji Ishii;Florian Rivoal. CSS Text Module Level 3。2023年9月3日。CR。URL:https://www.w3.org/TR/css-text-3/
[CSS-TEXT-DECOR-4]
Elika Etemad;Koji Ishii. CSS Text Decoration Module Level 4。2022年5月4日。WD。URL:https://www.w3.org/TR/css-text-decor-4/
[CSS-TRANSFORMS-1]
Simon Fraser 等. CSS Transforms Module Level 1。2019年2月14日。CR。URL:https://www.w3.org/TR/css-transforms-1/
[CSS-UI-4]
Florian Rivoal. CSS 基础用户界面模块 第4级。2021年3月16日。WD。URL:https://www.w3.org/TR/css-ui-4/
[MEDIAQ]
Florian Rivoal;Tab Atkins Jr.. Media Queries Level 4。2021年12月25日。CR。URL:https://www.w3.org/TR/mediaqueries-4/
[QUIRKS]
Simon Pieters. Quirks Mode Standard。现行标准。URL:https://quirks.spec.whatwg.org/
[RFC6694]
S. Moonesamy, Ed.. The "about" URI Scheme。2012年8月。Informational。URL:https://www.rfc-editor.org/rfc/rfc6694

问题索引

可以参考 find a potential indicated element,但那是专为 Document 定义的,不适用于 ShadowRoot。 ↵
CSSOM 需要指定舍入方式,且让 CSS 函数默认采用相同的舍入方式可能更好。应采用什么行为?[Issue #5689] ↵
本节仍在讨论中。↵
CanIUse

Support:Android Browser2.1+Baidu Browser13.18+Blackberry Browser7+Chrome4+Chrome for Android122+Edge12+Firefox3.6+Firefox for Android123+IE11+IE Mobile10+KaiOS Browser2.5+Opera11.6+Opera MiniAllOpera Mobile12+QQ Browser13.1+Safari5+Safari on iOS6.0+Samsung Internet4+UC Browser for Android15.5+

Source: caniuse.com as of 2024-03-07

CanIUse

Support:Android Browser4.4+Baidu Browser13.18+Blackberry Browser10+Chrome27+Chrome for Android122+Edge12+Firefox2+Firefox for Android123+IE (limited)9+IE Mobile10+KaiOS Browser2.5+Opera15+Opera MiniNoneOpera Mobile73+QQ Browser13.1+Safari7+Safari on iOS7.0+Samsung Internet4+UC Browser for Android15.5+

Source: caniuse.com as of 2024-03-07

CanIUse

Support:Android Browser4.4+Baidu Browser13.18+Blackberry Browser10+Chrome26+Chrome for Android122+Edge16+Firefox19+Firefox for Android123+IE (limited)9+IE Mobile (limited)10+KaiOS Browser2.5+Opera15+Opera MiniNoneOpera Mobile73+QQ Browser13.1+Safari6.1+Safari on iOS8+Samsung Internet4+UC Browser for Android15.5+

Source: caniuse.com as of 2024-03-07

CanIUse

Support:Android Browser122+Baidu Browser13.18+Blackberry Browser10+Chrome26+Chrome for Android122+Edge12+Firefox16+Firefox for Android123+IE (limited)9+IE Mobile10+KaiOS Browser2.5+Opera15+Opera MiniNoneOpera Mobile73+QQ Browser13.1+Safari6.1+Safari on iOS7.0+Samsung Internet4+UC Browser for Android15.5+

Source: caniuse.com as of 2024-03-07