1. 引言
本节不是规范性的。
测试
本节不是规范性的,不需要测试。
本模块描述了 CSS 属性,这些属性允许作者指定元素文本内容的前景颜色和不透明度。 本模块还详细描述了 CSS <color> 值类型。
它不仅定义了已经存在于 CSS1、CSS2 和 CSS Color 3 中的与颜色相关的属性和值, 还定义了新的属性和值。
特别是,它允许在 sRGB 之外的其他 颜色空间 中指定颜色; 以前,即使显示设备支持,更饱和的颜色(超出 sRGB 色域的颜色)也不能在 CSS 中使用。
可用的 草稿实现报告 已发布。
1.1. 值的定义
本规范遵循 CSS 属性定义惯例,来自 [CSS2],使用 值定义语法,来自 [CSS-VALUES-3]。 本规范未定义的值类型在 CSS 值与单位 [CSS-VALUES-3] 中定义。 与其他 CSS 模块的组合可能会扩展这些值类型的定义。
除了在定义中列出的特定于属性的值外,本规范中定义的所有属性还接受 CSS-wide 关键字 作为其属性值。 为了可读性,它们没有被显式重复。
2. 颜色术语
测试
本节提供后续使用的定义,不需要测试。
颜色 是对人类视觉对光线或被光照亮的物体的视觉感知的定义(数值或文本)。 对人类颜色感知的客观研究称为 颜色测量学。
物体的颜色取决于它在每个可见波长上反射的光的多少, 以及照亮它的光的实际颜色(同样是每个波长上的光量)。 它通过分光光度计进行测量。
发光物体的颜色(包括计算机屏幕上的颜色) 取决于它在每个可见波长上发射的光的多少。 它通过分光辐射计进行测量。
如果两个物体具有不同的光谱,但仍然产生相同的物理感觉, 我们说它们具有相同的颜色。 我们可以通过将光谱转换为 CIE XYZ(三个数字)来计算两个颜色是否相同。
颜色空间 是对颜色相对于基础颜色测量学模型的组织, 使得在该颜色空间中任何颜色都有明确的、可客观测量的含义。 这也意味着相同的颜色可以在多个颜色空间中表示, 或从一个颜色空间转换为另一个颜色空间, 同时看起来保持相同。
使用分光光度计对叶子进行测量,发现颜色为 lch(51.2345% 21.2 130), 也就是 lab(51.2345% -13.6271 16.2401)。
同样的颜色可以在不同的颜色空间中表示:
color ( sRGB0.41587 0.503670 0.36664 ); color ( display-p30.43313 0.50108 0.37950 ); color ( a98-rgb0.44091 0.49971 0.37408 ); color ( prophoto-rgb0.36589 0.41717 0.31333 ); color ( rec20200.42210 0.47580 0.35605 );
加色色彩空间意味着坐标系在光强度上是线性的。 CIE XYZ 色彩空间是一种加色色彩空间。 XYZ 的 Y 分量是亮度,即单位面积的光强度, 或者说“它有多亮”。亮度以坎德拉每平方米 (cd/m²) 为单位进行测量, 也称为尼特。
在加色色彩空间中,可以进行计算 以准确预测颜色混合。大多数 RGB 空间 不是加色的,因为其分量是伽马编码的。取消这种伽马编码 会产生线性光值。
如果我们有两种不同颜色的聚光灯照射在舞台上, 一种测得的值是 color(xyz 0.15 0.24 0.17), 另一种是 color(xyz 0.11 0.06 0.06), 那么我们可以准确预测,如果两个有色光束重叠, 混合后的颜色将是 XYZ 分量值的总和,即 color(xyz 0.26 0.30 0.23)。
色度 是将亮度分量排除后的颜色测量值。 从上述相同的灯光示例中,一个灯光的u',v' 色度为 (0.2537, 0.5268), 而两个灯光的色度相同(它们的颜色相同,只是更亮)。
色度是加性的, 因此它可以准确预测混合物的色度(但不能预测其产生的亮度)。 色度是二维的,因此可以在色度图上轻松表示,以预测颜色混合的色度。 任何两个颜色都可以混合,结果颜色将位于图上连接它们的直线上。 三种颜色形成一个平面,结果颜色将位于它们在图上形成的三角形内。
因此,一旦线性化,RGB 色彩空间就是加色的, 它们的色域由红、绿、蓝三原色的色度, 加上白点(所有三种原色都达到最大强度时形成的颜色)的色度定义。
大多数色彩空间使用少数几种模拟日光的白点之一, 这些白点以相应黑体辐射器的相关色温 (CCT) [Understanding_CCT] 命名。 例如,D65 是一个日光白点, 对应于 6500 开尔文的相关色温 (实际上是 6504, 因为自从最初定义该颜色以来,普朗克常数的值已发生变化)。
为了避免累积的往返误差, 在计算的所有地方必须一致地使用相同的色度值, 这样才能实现最大兼容性。 因此,在本规范中定义了以下两个标准的白昼模拟白点:
| 名称 | x | y | CCT |
|---|---|---|---|
| D50 | 0.345700 | 0.358500 | 5003K |
| D65 | 0.312700 | 0.329000 | 6504K |
当已知颜色空间或产生颜色的设备的物理特性 (例如其使用的基色的色度, 或对一组给定输入的响应所产生的颜色)时, 我们称它为已表征。
如果另外进行了调整,使设备满足校准目标,例如白点、中性色、调响应的可预测性和一致性, 那么它被称为已校准。
目前的物理设备还无法产生人眼可以看到的每种可能颜色。 给定设备能够产生的颜色范围称为色域 (不要与伽马混淆)。 色域有限的设备无法产生非常饱和的颜色, 如彩虹中的颜色。
不同颜色空间的色域可以通过查看可以表示的颜色体积(以立方 Lab 单位为单位)来比较。 下表检查了 CSS 中可用的预定义颜色空间。
| 颜色空间 | 体积(百万 Lab 单位) |
|---|---|
| sRGB | 0.820 |
| display-p3 | 1.233 |
| a98-rgb | 1.310 |
| prophoto-rgb | 2.896 |
| rec2020 | 2.042 |
CSS 中的颜色要么是无效颜色, 如下所述的每种语法形式, 要么是有效颜色。
任何不是无效颜色的颜色都是有效颜色。
某些颜色可以是有效颜色, 但仍然超出输出设备(屏幕、投影仪或打印机)可以产生的颜色范围。
这种情况称为超出色域。
每个有效颜色要么对于特定输出设备(屏幕或打印机)在色域内, 要么超出色域。
color ( prophoto-rgb0.88 0.45 0.10 )
因为,在 display-p3 中表示时, 一个或多个坐标要么大于 1.0,要么小于 0.0:
color ( display-p31.0844 0.43 0.1 )
此颜色是有效的, 例如,它可以用作渐变的停止点, 但需要进行CSS 色域映射, 以便显示,从而产生看起来相似但色度较低(饱和度较低)的颜色。
3. 在 CSS 中应用颜色
3.1. 可访问性与通过颜色传达信息
测试
本节提供编写指导,不需要测试。
虽然颜色可以为文档增加重要信息并提高其可读性, 但颜色本身不应成为传达重要信息的唯一手段。 作者在文档中使用颜色时应考虑 W3C Web 内容可访问性指南 [WCAG21]。
3.2. 前景颜色:color 属性
| 名称: | color |
|---|---|
| 值: | <color> |
| 初始值: | CanvasText |
| 适用于: | 所有元素和文本 |
| 继承: | 是 |
| 百分比: | N/A |
| 计算值: | 计算的颜色,参见解析颜色值 |
| 规范顺序: | 按语法 |
| 动画类型: | 按计算值类型 |
测试
此属性指定元素的主要前景颜色。 它用作文本内容的填充颜色, 并且还指定了 使用的值,currentcolor 将解析为该值, 这允许间接引用该前景颜色,并影响其他各种颜色属性的初始值, 如 border-color 和 text-emphasis-color。
- <color>
- 将主要前景颜色设置为指定的 <color>。
em{ color : lime; } /* 颜色关键字 */ em{ color : rgb ( 0 255 0 ); } /* RGB 范围 0-255 */ em{ color : rgb ( 0 % 100 % 0 % ); } /* RGB 范围 0%-100% */ em{ color : color ( sRGB0 1 0 ); } /* sRGB 范围 0.0-1.0 */
当应用于文本时,此属性(包括其 alpha 分量)对“彩色字形”没有影响(例如某些字体中的表情符号),这些字形由内置调色板着色。
然而,一些彩色字体能够引用上下文“前景色”,
例如 OpenType 的 COLR 表中的调色板条目 0xFFFF,
或者 SVG-in-OpenType 中的 context-fill 值。
在这种情况下,前景色由此属性设置,与设置 currentcolor 值相同。
3.3. 透明度:opacity 属性
透明度可以被看作是后处理操作。 从概念上讲,在元素(包括其子元素)被渲染为 RGBA 离屏图像后, 透明度设置指定如何将离屏渲染与当前的合成渲染进行混合。 详情见简单的 alpha 合成。
| 名称: | opacity |
|---|---|
| 值: | <opacity-value> |
| 初始值: | 1 |
| 适用于: | 所有元素 |
| 继承: | 否 |
| 百分比: | 映射到范围 [0,1] |
| 计算值: | 指定的数值,限定在 [0,1] 范围内 |
| 规范顺序: | 按语法 |
| 动画类型: | 按计算值类型 |
测试
- clip-opacity-out-of-flow.html (实时测试) (来源)
- t32-opacity-basic-0.0-a.xht (实时测试) (来源)
- t32-opacity-basic-0.6-a.xht (实时测试) (来源)
- t32-opacity-basic-1.0-a.xht (实时测试) (来源)
- t32-opacity-clamping-0.0-b.xht (实时测试) (来源)
- t32-opacity-clamping-1.0-b.xht (实时测试) (来源)
- t32-opacity-offscreen-b.xht (实时测试) (来源)
- t32-opacity-offscreen-multiple-boxes-1-c.xht (实时测试) (来源)
- t32-opacity-offscreen-multiple-boxes-2-c.xht (实时测试) (来源)
- t32-opacity-offscreen-with-alpha-c.xht (实时测试) (来源)
- t32-opacity-zorder-c.xht (实时测试) (来源)
- opacity-computed.html (实时测试) (来源)
- opacity-valid.html (实时测试) (来源)
- opacity-invalid.html (实时测试) (来源)
- composited-filters-under-opacity.html (实时测试) (来源)
- filters-under-will-change-opacity.html (实时测试) (来源)
- color-composition.html (实时测试) (来源)
- opacity-interpolation.html (实时测试) (来源)
- canvas-change-opacity.html (实时测试) (来源)
- opacity-animation-ending-correctly-001.html (实时测试) (来源)
- opacity-animation-ending-correctly-002.html (实时测试) (来源)
- <不透明度值>
-
应用于元素的透明度。
最终的透明度应用于整个元素,而不是某个特定颜色。
透明度值超出范围 [0,1] 并非无效,且在指定值中会被保留, 但在计算值中会被限定在 [0, 1] 范围内。
CSS 中的不透明度使用 <opacity-value> 语法表示, 例如在 opacity 属性中。
<opacity-value> = <number> | <percentage>
表示为 <number> 时, 其值的有效范围是 0(表示完全透明) 到 1(表示完全不透明)。 它也可以写成 <percentage>, 其计算结果为等效的 <number>(0% 对应 0,100% 对应 1)。
opacity 属性将指定的不透明度应用于元素 整体, 包括其内容,而不是单独应用于每个子元素。 这意味着,例如,即使 opacity 小于 1, 遮挡部分背景的不透明子元素仍然会继续遮挡,但元素和子元素作为一个整体将显示底层页面。
这也意味着, 元素中所有字符的字形都被 作为一个整体 处理; 任何重叠部分都不会增加不透明度。
如果希望每个字形具有不同的不透明度, 可以通过使用包含 alpha 通道的颜色值来实现, 而不是设置 opacity 属性。
如果一个盒子具有小于 1 的 opacity, 它会为其子元素形成一个堆叠上下文。 (这可以防止其内容在 z 轴上与外部内容交错。)
此外,如果 z-index 属性应用于盒子, 则该元素的 auto 值被视为 0; 否则它会在其父堆叠上下文中与具有堆叠级别 0 的定位元素在同一层上绘制 (就好像它是具有 z-index:0 的定位元素一样)。
更多关于堆叠上下文的信息,请参阅 第 9.9 节 和 附录 E,参见 [CSS2]。
这些关于堆叠顺序的规则不适用于 SVG 元素, 因为 SVG 有其自己的 渲染模型([SVG11],第 3 章)。
opacity 属性的值 不会影响命中测试。
3.4. 标记图像的颜色空间
标记图像是指显式分配了颜色配置文件的图像, 由图像格式定义。 这通常通过包含国际色彩联盟(ICC)配置文件来完成 [ICC]。
例如,JPEG [JPEG]、PNG [PNG] 和 TIFF [TIFF] 都指定了一种嵌入 ICC 配置文件的方法。
图像格式也可以使用其他等效的方法,通常是为了简洁。
例如,PNG 指定了一种方法(sRGB 块), 用于显式地将图像标记为 sRGB 颜色空间, 而无需包含 sRGB ICC 配置文件。
类似地,PNG 指定了一种紧凑的方法 (cICP 块), 用于显式地将图像标记为各种 SDR 或 HDR 颜色空间之一, 例如 Display P3 或 BT.2100 HLG, 而无需包含 ICC 配置文件。
标记的 RGB 图像, 以及使用 RGB 转换(如 YCbCr)的标记图像, 如果颜色配置文件或其他识别信息有效, 必须被视为处于指定的颜色空间中。
测试
例如,当运行在具有 Display P3 显示器的系统上的浏览器显示一个标记为 ITU Rec BT.2020 [Rec.2020] 色彩空间的 JPEG 图像时,必须将颜色从 ITU Rec BT.2020 转换为 Display P3,以便正确显示。不能将 ITU Rec BT.2020 值视为 Display P3 值,否则会产生错误的颜色。
如果颜色配置文件或其他标识信息无效,则图像将按照未标记图像的描述进行处理。
3.5. 未标记颜色的色彩空间
为了兼容性,HTML 中指定的颜色 以及未标记图像必须被视为 处于 sRGB 色彩空间([SRGB]) 除非另有规定。
未标记图像是指未根据图像格式定义明确指定颜色配置文件的图像。
此规则不适用于未标记视频,因为未标记视频应假定采用 ITU 定义的色彩空间。
-
低于 720p 时,使用 Recommendation ITU-R BT.601 [ITU-R-BT.601]
-
720p 时,使用 SMPTE ST 296(与 709 具有相同的色彩学) [SMPTE296]
-
1080p 时,使用 Recommendation ITU-R BT.709 [ITU-R-BT.709]
-
4k (UHDTV) 及更高分辨率时,使用 ITU-R BT.2020 [Rec.2020] 用于 SDR 视频
4. 表示颜色: <color> 类型
测试
本节描述了一种类型,主要在使用该类型的地方进行测试。
CSS 中的颜色表示为颜色分量列表, 有时也称为“通道”, 代表色彩空间中的轴。 每个分量都有一个最小值和最大值, 并且可以取这两个值之间的任何值。 此外,每种颜色都附带一个 Alpha 分量, 指示其透明程度, 从而指示可以通过颜色看到多少背景。
CSS 有多种指定颜色值的语法:
-
sRGB 十六进制颜色表示法,它以十六进制表示法表示 RGB 和 Alpha 分量
-
各种颜色函数,可以使用各种色彩空间和坐标系表示颜色
-
常量命名颜色关键字
-
变量<system-color>关键字和currentColor关键字。
颜色函数使用 CSS 函数表示法通过指定其分量坐标来表示各种色彩空间中的颜色。 其中一些使用圆柱极坐标颜色模型, 通过<hue>角度、代表亮度 (黑到白)的中心轴, 以及代表饱和度或色度 (颜色与中性灰色的距离)的半径来指定颜色。 其他的则使用矩形正交颜色模型, 使用三个正交分量轴指定颜色。
第 4 级中可用的颜色函数有:
-
rgb() 及其 rgba() 别名, 与 十六进制颜色表示法类似,直接通过红/绿/蓝/透明度分量指定 sRGB 颜色。
-
lab(), 按照 CIE LAB 矩形坐标模型, 通过 CIE 明度和 a、b 轴色调坐标(红/绿与黄/蓝倾向性)指定 CIELAB 颜色。
-
lch(), 按照 CIE LCH 圆柱坐标模型 通过 CIE 明度、色度和色调指定 CIELAB 颜色。
-
oklab(), 按照 Oklab 矩形坐标模型, 通过 Oklab 明度和 a、b 轴色调坐标(红/绿与黄/蓝倾向性)指定 Oklab 颜色。
-
color(), 允许在多种色彩空间中指定颜色, 包括 sRGB、 线性光 sRGB、 Display P3、 线性光 Display P3、 A98 RGB、 ProPhoto RGB、 ITU-R BT.2020-2, 以及 CIE XYZ。
为便于其他规范引用, 不透明黑色 定义为 颜色 rgb(0 0 0 / 100%); 透明黑色 为同样的颜色, 但完全透明,即 rgb(0 0 0 / 0%)。
测试
4.1. <color> 语法
测试
本节提供稍后使用的定义,不需要测试。
在 CSS 中,颜色由 <color> 类型表示:
<color> = <color-base> | currentColor | <system-color> <color-base> = <hex-color> | <color-function> | <named-color> | transparent <color-function> = <rgb () > | <rgba () > | <hsl () > | <hsla () > | <hwb () > | <lab () > | <lch () > | <oklab () > | <oklch () > | <color () >
绝对颜色是一个 <color>,其计算值具有绝对的、色度学解释。这意味着该值不是:
-
currentColor(它取决于 color 属性的值)
-
一个 <system-color>(它取决于颜色模式)
解析为 sRGB 的颜色有:
支持旧版颜色语法的函数有:
<hsl()>、<hsla()>、<hwb()>、<lch()> 和 <oklch()> 颜色函数是使用 <hue> 角度的圆柱极坐标颜色表示法; 其他颜色函数使用矩形正交颜色表示法。
4.1.1. 现代(空格分隔)颜色函数语法
本规范中首次定义的所有绝对颜色函数形式 都使用现代颜色语法, 这意味着:
-
颜色分量由空格分隔
-
可选的 alpha 项由斜杠 (“/”) 分隔
-
序列化时的最低所需精度已定义, 并且可能大于每个分量 8 位
-
使用 <percentage> 和 <number> 的分量可以自由混合
4.1.2. 传统(逗号分隔)颜色函数语法
为了 Web 兼容性, rgb()、rgba()、hsl() 和 hsla() 的语法形式 (在早期规范中定义的那些) 也支持一种旧版颜色语法,它具有以下区别:
-
颜色分量用逗号分隔 (可选地在前面和/或后面加上空格)
-
非不透明形式使用单独的表示法 (例如 hsla() 而不是 hsl()) 并且 alpha 项用逗号分隔 (可选地在前面和/或后面加上空格)
-
最低所需精度较低,每个分量 8 位
-
不允许使用 none 值
-
颜色分量必须全部使用 <percentage> 或全部使用 <number> 来指定,它们不能混合使用。
对于本级别或随后的级别中引入的 颜色函数,在没有 Web 兼容性问题的情况下,传统颜色语法是无效的。
4.2. 表示颜色中的透明度:<alpha-value> 语法
测试
本节提供后续使用的定义,不需要测试。
<alpha-value> = <number> | <percentage>
除非另有规定,颜色的 <alpha-value> 组件在省略时默认为 100%。超出范围 [0,1] 的值不是无效的,但在解析值时会被限制在该范围内。
4.3. 表示圆柱坐标色相:<hue> 语法
测试
本节提供后续使用的定义,不需要测试。
色相表示为颜色圆的一个角度(将彩虹扭曲成一个圆,并在紫色和红色之间加入紫红色)。
<hue> = <number> | <angle>
由于这个值通常以度数给出,参数也可以用数字表示,这个数字被解释为度数,是 标准单位。
这个数字被标准化为范围 [0,360)。
在 hsl(360 0 0) 中,<hue> 分量被标准化为 0 度。
在 hsl(calc(-infinity) 0 0) 或 hsl(calc(infinity) 0 0) 中, <hue> 分量再次被标准化为 0 度。
注意: 特定色相对应的角度和间距取决于色彩空间。例如,在使用 sRGB 色彩空间的 HSL 和 HWB 中,sRGB 的绿色是 120 度。在 LCH 中,sRGB 绿色是 134.39 度,display-p3 绿色是 136.01 度,a98-rgb 绿色是 145.97 度,prophoto-rgb 绿色是 141.04 度(因为这些都是不同的绿色阴影)。
<hue> 分量是最常变为无效的颜色分量; 任何足够接近中心非彩色轴的颜色 都将具有无效的色相分量。
4.4. “缺失”的颜色组件和 none 关键字
在某些情况下,颜色可能有一个或多个 缺失的颜色组件。
在本规范中,由于某些颜色的 基于色相的插值,这种情况会自动发生(例如 白色);其他规范可以定义组件自动缺失的其他情况。
也可以显式指定,通过在颜色函数中为组件提供关键字 none。所有颜色函数(使用 传统颜色语法 的除外)允许其组件中的任意一个被指定为 none。
这应该谨慎使用,只有在需要特定效果时才应这样做。
测试
- color-computed-color-function.html (实时测试) (来源)
- color-computed-hsl.html (实时测试) (来源)
- color-computed-hwb.html (实时测试) (来源)
- color-computed-lab.html (实时测试) (来源)
- color-computed-relative-color.html (实时测试) (来源)
- color-computed-rgb.html (实时测试) (来源)
- color-invalid-hsl.html (实时测试) (来源)
- color-invalid-rgb.html (实时测试) (来源)
- color-valid-color-function.html (实时测试) (来源)
- color-valid-color-mix-function.html (实时测试) (来源)
- color-valid-hsl.html (实时测试) (来源)
- color-valid-hwb.html (实时测试) (来源)
- color-valid-lab.html (实时测试) (来源)
- color-valid-relative-color.html (实时测试) (来源)
- color-valid-rgb.html (实时测试) (来源)
有关在颜色插值等组合两种颜色的情况下处理缺失分量的信息, 请参阅 § 12.2 使用缺失分量进行插值。
对于其他所有用途,缺失组件表现为零值,采用该组件的适当单位:0,0%,或0deg。这包括直接渲染颜色、将其转换为其他颜色空间、对颜色组件值执行计算等。
如果带有缺失组件的颜色被序列化或直接呈现给作者,对于传统颜色语法,其表示该组件为零值;否则,则表示该组件为none关键字。
结果将是一个真正看起来像绿色和白色混合的颜色,而不是看起来略带红色(如果将白色的色相默认为0deg)。
例如,要将一种颜色动画化为“灰度”,无论该颜色是什么,可以将其与oklch(none 0 none)进行插值。这将从起始颜色中获取色相和亮度,但将其色度动画化为0,使其在整个动画中保持均匀亮度的灰色。
手动执行此操作将需要显式匹配起始颜色的色相和亮度。
4.4.1. “无效”颜色组件
个别颜色语法可以指定,在某些情况下,它们的语法中的某个组件会成为无效颜色组件。这表明该组件的值不会影响渲染的颜色;无论你赋予它什么值,屏幕上显示的颜色都是相同的。
例如,在hsl()中,当饱和度组件为0%时,色相组件是无效的;0%的饱和度表示灰度颜色,它根本没有色相,因此0deg和180deg或任何其他角度,都会得到完全相同的结果。
如果手动指定了无效分量, 则其行为正常; 其无效的事实没有任何影响。
但是,如果颜色是通过色彩空间转换自动生成的, 则结果中的任何无效分量都必须设置为缺失, 而不是转换过程中产生的任何值。
当执行到圆柱极坐标色彩空间的色彩空间转换时, 如果色度(或其他色彩度量,例如 hsl 中的饱和度) 小于为该色彩空间指定的 epsilon (ε),则用户代理必须将色相分量视为无效。 例如,由于数值误差, 转换为 oklch() 的灰色可能具有极小的色度,而不是精确的 0%; 因此,色相分量是无效的。
4.5. 解析 <color> 值
测试
本节提供了一个在其他地方引用的定义,不需要测试。
注意:此算法并非旨在解析 CSS 样式表或 CSSOM 接口中指定的 CSS <color> 值,而是在 HTML 属性或 Canvas 接口等其他地方使用。
5. sRGB 颜色
CSS 中位于 sRGB 色彩空间内的颜色通过三元值来表示——红、绿和蓝——标识 sRGB 色彩空间中的一个点 [SRGB]。 这是一种国际公认的设备无关的色彩空间,因此适用于指定在计算机屏幕上显示的颜色,也适用于在其他类型的设备(如打印机)上指定颜色。
CSS 也允许使用非 sRGB 的 色彩空间,如 第 10 节 预定义的色彩空间 中所述。
CSS 提供了几种直接指定 sRGB 颜色的方法:十六进制颜色、rgb()/rgba() 颜色函数、hsl()/hsla() 颜色函数、hwb() 颜色函数、命名颜色, 以及 transparent 关键字。
5.1. RGB 函数:rgb() 和 rgba()
rgb() 和 rgba() 函数通过直接指定 r、g 和 b(红、绿、蓝)分量来定义 sRGB 颜色。 它们的语法是:
rgb () =[ <legacy-rgb-syntax> | <modern-rgb-syntax>] rgba () =[ <legacy-rgba-syntax> | <modern-rgba-syntax>] <legacy-rgb-syntax> =rgb ( <percentage>#{ 3 } , <alpha-value>?) |rgb ( <number>#{ 3 } , <alpha-value>?) <legacy-rgba-syntax> =rgba ( <percentage>#{ 3 } , <alpha-value>?) |rgba ( <number>#{ 3 } , <alpha-value>?) <modern-rgb-syntax> =rgb ( [ <number> | <percentage> | none] { 3 } [ /[ <alpha-value> | none] ] ?) <modern-rgba-syntax> =rgba ( [ <number> | <percentage> | none] { 3 } [ /[ <alpha-value> | none] ] ?)
| 百分比 | 适用于 r、g 和 b |
|---|---|
| 百分比参考范围 | 对于 r、g 和 b:0% = 0.0,100% = 255.0 对于 alpha:0% = 0.0,100% = 1.0 |
测试
- rgb-001.html (实时测试) (来源)
- rgb-002.html (实时测试) (来源)
- rgb-003.html (实时测试) (来源)
- rgb-004.html (实时测试) (来源)
- rgb-005.html (实时测试) (来源)
- rgb-006.html (实时测试) (来源)
- rgb-007.html (实时测试) (来源)
- rgb-008.html (实时测试) (来源)
- out-of-gamut-legacy-rgb.html (实时测试) (来源)
- color-valid.html (实时测试) (来源)
- color-computed-rgb.html (实时测试) (来源)
- color-invalid-rgb.html (实时测试) (来源)
- color-valid-rgb.html (实时测试) (来源)
前三个参数分别指定颜色的 r、g 和 b(红、绿、蓝)分量。 0% 表示 sRGB 色域中该颜色分量的最小值, 100% 表示最大值。
颜色分量的百分比参考范围源于这样一个历史事实:许多图形引擎在内部将颜色分量存储为单个字节, 该字节可以容纳 0 到 255 之间的整数。 实现应尽可能遵循创作或计算的分量精度。 如果无法做到,则应将分量向 +∞ 舍入。
最后一个参数 <alpha-value> 指定颜色的 Alpha 值。 如果省略,则默认为 100%。
测试
超出这些范围的值并非无效, 而是在解析值时被限制在此处定义的范围内。
由于历史原因,rgb() 和 rgba() 也支持旧版颜色语法。
测试
5.2. RGB 十六进制表示法:#RRGGBB
CSS 十六进制颜色表示法允许通过将分量指定为十六进制数来指定 sRGB 颜色, 这与颜色通常在计算机代码中直接编写的方式类似。 它也比用 rgb() 表示法写出相同的颜色要短。
<hex-color> 的语法是一个 <hash-token> 标记,其值由 3、4、6 或 8 个十六进制数字组成。 换句话说,十六进制颜色写为一个哈希字符“#”, 后跟一些数字 0-9 或字母 a-f (字母的大小写无关紧要 - #00ff00 与 #00FF00 相同)。
给定的十六进制数字的数量决定了如何将十六进制表示法解码为 RGB 颜色:
- 6 位数字
- 第一对数字,解释为十六进制数, 指定颜色的红色分量, 其中 00 表示最小值, ff(十进制的 255)表示最大值。 下一对数字,以相同的方式解释, 指定绿色分量, 最后一对指定蓝色分量。 颜色的 Alpha 分量是完全不透明的。
- 8 位数字
- 前 6 位数字的解释与 6 位数字表示法相同。 最后一对数字,解释为十六进制数, 指定颜色的 Alpha 分量, 其中 00 表示完全透明的颜色, ff 表示完全不透明的颜色。
- 3 位数字
- 这是 6 位数字表示法的一种较短的变体。 第一个数字,解释为十六进制数, 指定颜色的红色分量, 其中 0 表示最小值, f 表示最大值。 接下来的两个数字分别以相同的方式表示绿色和蓝色分量。 颜色的 Alpha 分量是完全不透明的。
- 4 位数字
- 这是 8 位数字表示法的一种较短的变体, 其“扩展”方式与 3 位数字表示法相同。 第一个数字,解释为十六进制数, 指定颜色的红色分量, 其中 0 表示最小值, f 表示最大值。 接下来的三个数字分别表示绿色、蓝色和 Alpha 分量。
测试
- hex-001.html (实时测试) (来源)
- hex-002.html (实时测试) (来源)
- hex-003.html (实时测试) (来源)
- hex-004.html (实时测试) (来源)
- border-bottom-color.xht (实时测试) (来源)
- border-left-color.xht (实时测试) (来源)
- border-right-color.xht (实时测试) (来源)
- border-top-color.xht (实时测试) (来源)
- color-valid.html (实时测试) (来源)
- color-computed-hex-color.html (实时测试) (来源)
- color-invalid-hex-color.html (实时测试) (来源)
6. 颜色关键词
除了 <color> 的各种数字语法外, CSS 还定义了几组颜色关键字,可以替代使用——每组都有其自身的优点或用例。
6.1. 命名颜色
CSS 定义了一组 命名颜色,这样常见的颜色可以更容易地书写和阅读。 一个 <named-color> 以 <ident> 的形式编写,任何需要 <color> 的地方都接受这种形式。 对于 CSS 定义的 <ident>,所有这些关键词都是 ASCII 大小写不敏感的。
这些名字解析为 sRGB 颜色。
CSS 的 16 个命名颜色最初来自 VGA 调色板,后来被 HTML 采用:aqua、black、blue、fuchsia、gray、green、lime、maroon、navy、olive、purple、red、silver、teal、white 和 yellow。 其余大部分颜色来自 X11 颜色系统的一个版本,该系统用于 Unix 衍生系统的控制台颜色指定,后来被 SVG 采用。
注意:这些颜色名称在这里被标准化,不是因为它们好,而是因为它们的使用和实现已经存在了几十年,标准需要反映现实。 实际上,很难想象每个名字对应的颜色是什么(因此有下面的列表);这些名字在 sRGB 色彩空间中的分布并不均匀,甚至它们内部也不一致( darkgray 比 gray 更亮,而 lightpink 却比 pink 更暗), 并且一些名字(例如 indianred,最初是以来自印度的红色颜料命名的)被发现具有冒犯性。因此,不建议使用它们。
(两个特殊的颜色值 transparent 和 currentcolor 在各自的章节中有特殊定义。)
下表定义了所有不透明的命名颜色,通过给出其他颜色语法的等价数值表示。
| 命名 | 数值 | 颜色名称 | 十六进制 RGB | 十进制 |
|---|---|---|---|---|
| aliceblue | #f0f8ff | 240 248 255 | ||
| antiquewhite | #faebd7 | 250 235 215 | ||
| aqua | #00ffff | 0 255 255 | ||
| aquamarine | #7fffd4 | 127 255 212 | ||
| azure | #f0ffff | 240 255 255 | ||
| beige | #f5f5dc | 245 245 220 | ||
| bisque | #ffe4c4 | 255 228 196 | ||
| black | #000000 | 0 0 0 | ||
| blanchedalmond | #ffebcd | 255 235 205 | ||
| blue | #0000ff | 0 0 255 | ||
| blueviolet | #8a2be2 | 138 43 226 | ||
| brown | #a52a2a | 165 42 42 | ||
| burlywood | #deb887 | 222 184 135 | ||
| cadetblue | #5f9ea0 | 95 158 160 | ||
| chartreuse | #7fff00 | 127 255 0 | ||
| chocolate | #d2691e | 210 105 30 | ||
| coral | #ff7f50 | 255 127 80 | ||
| cornflowerblue | #6495ed | 100 149 237 | ||
| cornsilk | #fff8dc | 255 248 220 | ||
| crimson | #dc143c | 220 20 60 | ||
| cyan | #00ffff | 0 255 255 | ||
| darkblue | #00008b | 0 0 139 | ||
| darkcyan | #008b8b | 0 139 139 | ||
| darkgoldenrod | #b8860b | 184 134 11 | ||
| darkgray | #a9a9a9 | 169 169 169 | ||
| darkgreen | #006400 | 0 100 0 | ||
| darkgrey | #a9a9a9 | 169 169 169 | ||
| darkkhaki | #bdb76b | 189 183 107 | ||
| darkmagenta | #8b008b | 139 0 139 | ||
| darkolivegreen | #556b2f | 85 107 47 | ||
| darkorange | #ff8c00 | 255 140 0 | ||
| darkorchid | #9932cc | 153 50 204 | ||
| darkred | #8b0000 | 139 0 0 | ||
| darksalmon | #e9967a | 233 150 122 | ||
| darkseagreen | #8fbc8f | 143 188 143 | ||
| darkslateblue | #483d8b | 72 61 139 | ||
| darkslategray | #2f4f4f | 47 79 79 | ||
| darkslategrey | #2f4f4f | 47 79 79 | ||
| darkturquoise | #00ced1 | 0 206 209 | ||
| darkviolet | #9400d3 | 148 0 211 | ||
| deeppink | #ff1493 | 255 20 147 | ||
| deepskyblue | #00bfff | 0 191 255 | ||
| dimgray | #696969 | 105 105 105 | ||
| dimgrey | #696969 | 105 105 105 | ||
| dodgerblue | #1e90ff | 30 144 255 | ||
| firebrick | #b22222 | 178 34 34 | ||
| floralwhite | #fffaf0 | 255 250 240 | ||
| forestgreen | #228b22 | 34 139 34 | ||
| fuchsia | #ff00ff | 255 0 255 | ||
| gainsboro | #dcdcdc | 220 220 220 | ||
| ghostwhite | #f8f8ff | 248 248 255 | ||
| gold | #ffd700 | 255 215 0 | ||
| goldenrod | #daa520 | 218 165 32 | ||
| gray | #808080 | 128 128 128 | ||
| green | #008000 | 0 128 0 | ||
| greenyellow | #adff2f | 173 255 47 | ||
| grey | #808080 | 128 128 128 | ||
| honeydew | #f0fff0 | 240 255 240 | ||
| hotpink | #ff69b4 | 255 105 180 | ||
| indianred | #cd5c5c | 205 92 92 | ||
| indigo | #4b0082 | 75 0 130 | ||
| ivory | #fffff0 | 255 255 240 | ||
| khaki | #f0e68c | 240 230 140 | ||
| lavender | #e6e6fa | 230 230 250 | ||
| lavenderblush | #fff0f5 | 255 240 245 | ||
| lawngreen | #7cfc00 | 124 252 0 | ||
| lemonchiffon | #fffacd | 255 250 205 | ||
| lightblue | #add8e6 | 173 216 230 | ||
| lightcoral | #f08080 | 240 128 128 | ||
| lightcyan | #e0ffff | 224 255 255 | ||
| lightgoldenrodyellow | #fafad2 | 250 250 210 | ||
| lightgray | #d3d3d3 | 211 211 211 | ||
| lightgreen | #90ee90 | 144 238 144 | ||
| lightgrey | #d3d3d3 | 211 211 211 | ||
| lightpink | #ffb6c1 | 255 182 193 | ||
| lightsalmon | #ffa07a | 255 160 122 | ||
| lightseagreen | #20b2aa | 32 178 170 | ||
| lightskyblue | #87cefa | 135 206 250 | ||
| lightslategray | #778899 | 119 136 153 | ||
| lightslategrey | #778899 | 119 136 153 | ||
| lightsteelblue | #b0c4de | 176 196 222 | ||
| lightyellow | #ffffe0 | 255 255 224 | ||
| lime | #00ff00 | 0 255 0 | ||
| limegreen | #32cd32 | 50 205 50 | ||
| linen | #faf0e6 | 250 240 230 | ||
| magenta | #ff00ff | 255 0 255 | ||
| maroon | #800000 | 128 0 0 | ||
| mediumaquamarine | #66cdaa | 102 205 170 | ||
| mediumblue | #0000cd | 0 0 205 | ||
| mediumorchid | #ba55d3 | 186 85 211 | ||
| mediumpurple | #9370db | 147 112 219 | ||
| mediumseagreen | #3cb371 | 60 179 113 | ||
| mediumslateblue | #7b68ee | 123 104 238 | ||
| mediumspringgreen | #00fa9a | 0 250 154 | ||
| mediumturquoise | #48d1cc | 72 209 204 | ||
| mediumvioletred | #c71585 | 199 21 133 | ||
| midnightblue | #191970 | 25 25 112 | ||
| mintcream | #f5fffa | 245 255 250 | ||
| mistyrose | #ffe4e1 | 255 228 225 | ||
| moccasin | #ffe4b5 | 255 228 181 | ||
| navajowhite | #ffdead | 255 222 173 | ||
| navy | #000080 | 0 0 128 | ||
| oldlace | #fdf5e6 | 253 245 230 | ||
| olive | #808000 | 128 128 0 | ||
| olivedrab | #6b8e23 | 107 142 35 | ||
| orange | #ffa500 | 255 165 0 | ||
| orangered | #ff4500 | 255 69 0 | ||
| orchid | #da70d6 | 218 112 214 | ||
| palegoldenrod | #eee8aa | 238 232 170 | ||
| palegreen | #98fb98 | 152 251 152 | ||
| paleturquoise | #afeeee | 175 238 238 | ||
| palevioletred | #db7093 | 219 112 147 | ||
| papayawhip | #ffefd5 | 255 239 213 | ||
| peachpuff | #ffdab9 | 255 218 185 | ||
| peru | #cd853f | 205 133 63 | ||
| pink | #ffc0cb | 255 192 203 | ||
| plum | #dda0dd | 221 160 221 | ||
| powderblue | #b0e0e6 | 176 224 230 | ||
| purple | #800080 | 128 0 128 | ||
| rebeccapurple | #663399 | 102 51 153 | ||
| red | #ff0000 | 255 0 0 | ||
| rosybrown | #bc8f8f | 188 143 143 | ||
| royalblue | #4169e1 | 65 105 225 | ||
| saddlebrown | #8b4513 | 139 69 19 | ||
| salmon | #fa8072 | 250 128 114 | ||
| sandybrown | #f4a460 | 244 164 96 | ||
| seagreen | #2e8b57 | 46 139 87 | ||
| seashell | #fff5ee | 255 245 238 | ||
| sienna | #a0522d | 160 82 45 | ||
| silver | #c0c0c0 | 192 192 192 | ||
| skyblue | #87ceeb | 135 206 235 | ||
| slateblue | #6a5acd | 106 90 205 | ||
| slategray | #708090 | 112 128 144 | ||
| slategrey | #708090 | 112 128 144 | ||
| snow | #fffafa | 255 250 250 | ||
| springgreen | #00ff7f | 0 255 127 | ||
| steelblue | #4682b4 | 70 130 180 | ||
| tan | #d2b48c | 210 180 140 | ||
| teal | #008080 | 0 128 128 | ||
| thistle | #d8bfd8 | 216 191 216 | ||
| tomato | #ff6347 | 255 99 71 | ||
| turquoise | #40e0d0 | 64 224 208 | ||
| violet | #ee82ee | 238 130 238 | ||
| wheat | #f5deb3 | 245 222 179 | ||
| white | #ffffff | 255 255 255 | ||
| whitesmoke | #f5f5f5 | 245 245 245 | ||
| yellow | #ffff00 | 255 255 0 | ||
| yellowgreen | #9acd32 | 154 205 50 |
注意:此颜色列表及其定义是 SVG 1.1 定义的命名颜色 列表的超集。
为了历史原因,这也被称为 X11 颜色集。注意: X11 颜色系统的历史非常有趣,并由 Alex Sexton 在其演讲 “Peachpuffs and Lemonchiffons” 中做了极好的总结。
测试
6.2. 系统颜色
通常,<系统颜色>关键字反映了用户、浏览器或操作系统做出的默认颜色选择。因此,它们通常在浏览器的默认样式表中使用。
为了保持可读性,<系统颜色>关键字也会响应亮模式或暗模式的变化。
可读链接文本
不可读链接文本
可读链接文本
然而,在强制颜色模式下,页面上的大多数颜色会被强制转换为用户选择的受限调色板。<系统颜色>关键字会暴露这些用户选择的颜色,以便页面的其他部分能够与受限的调色板融合。
当强制颜色 媒体特性 激活时,作者应该使用<系统颜色>关键字作为属性中的颜色值,这些属性除外,请参考CSS 颜色调整 1 § 3.1 被强制颜色模式影响的属性,以确保页面的可读性和一致性,避免用户强制颜色和页面选择颜色的混乱拼凑。
测试
当<系统颜色>关键字的值来自浏览器(而不是作为操作系统的默认值或用户选择)时,浏览器应确保匹配的前景/背景对具有最小的WCAG AA对比度。然而,用户偏好(无论是更高还是更低的对比度),无论是作为浏览器偏好设置、用户样式表设置,还是通过更改操作系统的默认设置,必须优先于此要求。
作者也可以随时使用这些关键字,但应该小心使用匹配的背景-前景对来确保适当的对比度,因为跨不匹配对的特定对比关系(例如,Canvas和ButtonText)不保证。
<系统颜色>关键字定义如下:
- AccentColor
- 突出显示的用户界面控件的背景。
- AccentColorText
- 突出显示的用户界面控件的文本。
- ActiveText
- 活动链接中的文本。对于浅色背景,通常为红色。
- ButtonBorder
- 按钮的边框颜色。
- ButtonFace
- 按钮的表面背景颜色。
- ButtonText
- 按钮上的文本。
- Canvas
- 应用程序内容或文档的背景。
- CanvasText
- 应用程序内容或文档中的文本。
- Field
- 输入字段的背景。
- FieldText
- 输入字段中的文本。
- GrayText
- 禁用文本。(通常,但不一定是灰色。)
- Highlight
- 选中文本的背景,例如来自::selection。
- HighlightText
- 选中文本的文本。
- LinkText
- 非活动、未访问链接中的文本。对于浅色背景,通常为蓝色。
- Mark
- 被特别标记的文本的背景(例如通过HTML
mark元素)。 - MarkText
- 被特别标记的文本(例如通过HTML
mark元素)。 - SelectedItem
- 选中项的背景,例如选中的复选框。
- SelectedItemText
- 选中项的文本。
- VisitedText
- 已访问链接中的文本。对于浅色背景,通常为紫色。
测试
注意:与所有其他关键字一样,这些名称是ASCII 大小写不敏感的。它们在这里以混合大小写显示以便于阅读。
对于没有特定系统 UI 概念的系统,指定的值应映射到最接近的相关系统颜色值。以下系统颜色配对预计将形成可读的背景-前景颜色:
-
Canvas背景与ButtonBorder边框以及相邻颜色Canvas
-
ButtonFace背景与ButtonText前景配对。
-
ButtonFace或Field背景与ButtonBorder边框以及相邻颜色Canvas
-
Highlight背景与HighlightText前景配对。
-
SelectedItem背景与SelectedItemText前景配对。
-
AccentColor背景与AccentColorText前景配对。
此外,GrayText预计可以阅读,尽管对比度可能较低,在任何背景上都可以阅读。
为保持与组件强调色样式的一致性, AccentColor 的取值来自 accent-color, 除非启用了强制色彩模式。 AccentColorText 的取值为 和 AccentColor 对比的前景色, 具体如组件 强调色样式中所描述。
Canvas 与 CanvasText:CanvasText
Canvas 与 LinkText:LinkText
Canvas 与 VisitedText:VisitedText
Canvas 与 ActiveText:ActiveText
Canvas 与 GrayText:GrayText
Canvas 与 ButtonBorder 以及相邻的 Canvas:CanvasText相邻
ButtonFace 与 ButtonText:ButtonText
ButtonFace 与 ButtonText 和 ButtonBorder:ButtonText
ButtonFace 与 GrayText:GrayText
Field 与 FieldText:FieldText
Field 与 GrayText:GrayText
Mark 与 MarkText:MarkText
Mark 与 GrayText:GrayText
Highlight 与 HighlightText:HighlightText
Highlight 与 GrayText:GrayText
SelectedItem 与 SelectedItemText:SelectedItemText
AccentColor 与 AccentColorText:AccentColorText
AccentColor 与 GrayText:GrayText
早期版本的CSS定义了其他<系统颜色>,这些已经被弃用。它们在附录A:弃用的CSS系统颜色中进行了记录。
注意:<系统颜色>存在一些隐私和安全风险,详见§ 21 隐私考虑和§ 20 安全考虑。
用户代理可以选择返回固定值以减轻隐私和安全风险(例如指纹识别),这些值不反映用户的自定义或主题选择。
6.3. transparent关键字
关键字transparent指定了透明黑。它是一种<named-color>。
测试
6.4. currentcolor关键字
关键字currentcolor表示同一元素上的color属性的值。与<named-color>不同,它不局限于 sRGB;该值可以是任何<color>。其使用值由解析颜色值来确定。
测试
- border-color-currentcolor.html (实时测试) (来源)
- color-mix-currentcolor-nested-for-color-property.html (实时测试) (来源)
- currentcolor-001.html (实时测试) (来源)
- currentcolor-002.html (实时测试) (来源)
- currentcolor-003.html (实时测试) (来源)
- currentcolor-004.html (实时测试) (来源)
- currentcolor-visited-fallback.html (实时测试) (来源)
- color-valid.html (实时测试) (来源)
.foo{ color : red; background-color : currentcolor; }
这相当于写成:
.foo{ color : red; background-color : red; }
< p >< em > Some< strong > really</ strong > emphasized text.</ em > < style > p { color : black ; } em { text-emphasis : dot ; } strong { color : red ; } </ style >

在上面的示例中,强调标记在文本 "Some" 和 "emphasized text" 上为黑色,但在文本 "really" 上为红色。
注意: CSS 中的多词关键字通常用连字符分隔各个组成词。 currentcolor 没有这样做,因为(深呼吸) 它最初在 SVG 中作为属性值引入,名字写作 "current-color",符合 CSS 通常拼法。 后来(以及所有其他属性及其值) 它变成了展示属性和值, 以及属性, 以便用 XSLT 方便生成。 接着所有展示属性都从用连字符的写法 改成了驼峰式,因为 DOM 对连字符含义为“减号”有问题。 但这样又不符合 CSS 的习惯写法 所以所有已经被 CSS 采用的属性及属性值 又都改回用连字符了! currentcolor 那时还没进 CSS, 所以还是 camelCase。 CSS 后来才采用它, 这时候大小写就无所谓了, 因为 CSS 关键字 ASCII 不区分大小写。
7. HSL 颜色:hsl() 和 hsla() 函数
RGB 系统用于指定颜色, 对于机器和图形库来说很方便, 但通常被认为对人类来说很难直观地理解。 例如,很难知道如何改变 RGB 颜色以产生同一色调的较亮变体。
还有几种其他的颜色方案可行。 其中一种是 HSL [HSL] 颜色方案, 使用起来更直观, 但仍可以轻松映射回 RGB 颜色。
HSL 颜色是通过色相、饱和度和亮度三元组来指定的。 hsl() 和 hsla() 函数的语法是:
hsl () =[ <legacy-hsl-syntax> | <modern-hsl-syntax>] hsla () =[ <legacy-hsla-syntax> | <modern-hsla-syntax>] <modern-hsl-syntax> =hsl ( [ <hue> | none] [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ /[ <alpha-value> | none] ] ?) <modern-hsla-syntax> =hsla ( [ <hue> | none] [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ /[ <alpha-value> | none] ] ?) <legacy-hsl-syntax> =hsl ( <hue>, <percentage>, <percentage>, <alpha-value>?) <legacy-hsla-syntax> =hsla ( <hue>, <percentage>, <percentage>, <alpha-value>?)
| 百分比 | 适用于 S 和 L |
|---|---|
| 百分比参考范围 | 对于 S 和 L:0% = 0.0,100% = 100.0 |
| 无效色相 ε | S <= 0.001 |
测试
- hsl-001.html (实时测试) (来源)
- hsl-002.html (实时测试) (来源)
- hsl-003.html (实时测试) (来源)
- hsl-004.html (实时测试) (来源)
- hsl-005.html (实时测试) (来源)
- hsl-006.html (实时测试) (来源)
- hsl-007.html (实时测试) (来源)
- hsl-008.html (实时测试) (来源)
- hsl-clamp-negative-saturation.html (实时测试) (来源)
- background-color-hsl-001.html (实时测试) (来源)
- background-color-hsl-002.html (实时测试) (来源)
- background-color-hsl-003.html (实时测试) (来源)
- background-color-hsl-004.html (实时测试) (来源)
- color-computed-hsl.html (实时测试) (来源)
- color-invalid-hsl.html (实时测试) (来源)
- color-valid-hsl.html (实时测试) (来源)
第一个参数指定色相角度。
在 HSL(和 HWB)中,角度 0deg 代表 sRGB 原始红色(同样适用于 360deg、720deg 等),其余的色相围绕圆周分布,所以 120deg 代表 sRGB 原始绿色,240deg 代表 sRGB 原始蓝色,依此类推。
接下来的两个参数分别是饱和度和亮度。对于饱和度,100% 或 100 表示完全饱和、明亮的颜色,而 0% 或 0 表示完全不饱和的灰色。对于亮度,50% 或 50 表示“正常”颜色,而 100% 或 100 是白色,0% 或 0 是黑色。
由于历史原因,如果饱和度小于 0%,它将在解析值阶段被钳制到 0%,然后再转换为 sRGB 颜色。
最后一个参数指定颜色的 Alpha 分量。 它的解释与 rgb() 函数的第四个参数完全相同。 如果省略,则默认为 100%。
HSL 颜色解析为 sRGB。
如果 HSL 颜色的饱和度为 0% 或 0,则色相分量是无效的。
与 RGB 相比,HSL 的一个优点是它更直观:人们可以猜测他们想要的颜色,然后进行调整。
hsl ( 120 deg 100 % 50 % ) 亮绿色hsl ( 120 deg 100 % 25 % ) 深绿色hsl ( 120 deg 100 % 75 % ) 浅绿色hsl ( 120 deg 75 % 85 % ) 粉绿色
HSL 相对于 OKLCh 的一个缺点是,色相操作会改变视觉亮度,并且色相并非均匀分布。
因此,在 HSL 中创建一组匹配的颜色(通过保持色相不变并改变饱和度和亮度)比操作 sRGB 组件值更容易;但是,由于亮度只是伽马校正的红、绿和蓝组件的平均值,因此它不对应于色相的视觉亮度。
在 OKLCh 中,sRGB 蓝色为 oklch(0.452 0.313 264.1),而 sRGB 黄色为 oklch(0.968 0.211 109.8)。OKLCh 的亮度值 0.452 和 0.968 明确地反映了两种颜色的视觉亮度。
在 HSL 中,色相角度并非感知上均匀的;颜色在某些区域聚集,而在其他区域则较为稀疏。
在 OKLCh 中,相同的颜色对 oklch(0.533 0.26 262.6) 和 oklch(0.462 0.306 268.9) 的色相差异为 268.9 - 262.6 = 6.3度,而另一对 oklch(0.882 0.181 94.24) 和 oklch(0.91 0.245 129.9) 的色相差异为 129.9 - 94.24 = 35.66度,正确地反映了色相的视觉分离程度。
由于历史原因,hsl() 和 hsla() 也支持旧版颜色语法。
测试
7.1. 将 HSL 颜色转换为 sRGB
将 HSL 颜色转换为 sRGB 在数学上很简单。 以下是 JavaScript 中转换算法的示例实现。 它返回一个包含三个数字的数组, 分别表示颜色的红色、绿色和蓝色分量, 对于 sRGB 色域中的颜色,这些分量将在 [0, 1] 范围内。
此代码假设已经应用了解析时对负饱和度的限制。
/** * @param {number} hue - Hue as degrees 0..360 * @param {number} sat - Saturation in reference range [0,100] * @param {number} light - Lightness in reference range [0,100] * @return {number[]} Array of sRGB components; in-gamut colors in range [0..1] */ function hslToRgb( hue, sat, light) { sat/= 100 ; light/= 100 ; function f( n) { let k= ( n+ hue/ 30 ) % 12 ; let a= sat* Math. min( light, 1 - light); return light- a* Math. max( - 1 , Math. min( k- 3 , 9 - k, 1 )); } return [ f( 0 ), f( 8 ), f( 4 )]; }
7.2. 将 sRGB 颜色转换为 HSL
反向的转换过程类似。
特别注意处理由远离 sRGB 色域的颜色产生的中间负饱和度值。
/** * @param {number} red - Red component 0..1 * @param {number} green - Green component 0..1 * @param {number} blue - Blue component 0..1 * @return {number[]} Array of HSL values: Hue as degrees 0..360, Saturation and Lightness in reference range [0,100] */ function rgbToHsl( red, green, blue) { let max= Math. max( red, green, blue); let min= Math. min( red, green, blue); let [ hue, sat, light] = [ NaN , 0 , ( min+ max) / 2 ]; let d= max- min; let epsilon= 1 / 100000 ; // max Sat is 1, in this code if ( d!== 0 ) { sat= ( light=== 0 || light=== 1 ) ? 0 : ( max- light) / Math. min( light, 1 - light); switch ( max) { case red: hue= ( green- blue) / d+ ( green< blue? 6 : 0 ); break ; case green: hue= ( blue- red) / d+ 2 ; break ; case blue: hue= ( red- green) / d+ 4 ; } hue= hue* 60 ; } // Very out of gamut colors can produce negative saturation // If so, just rotate the hue by 180 and use a positive saturation // see https://github.com/w3c/csswg-drafts/issues/9222 if ( sat< 0 ) { hue+= 180 ; sat= Math. abs( sat); } if ( hue>= 360 ) { hue-= 360 ; } if ( sat<= epsilon) { hue= NaN ; } return [ hue, sat* 100 , light* 100 ]; }
7.3. HSL 颜色示例
本节不是规范性的。
测试
本节不是规范性的,因此不需要测试。
下表展示了可能的 HSL 颜色的广泛范围。 每个表格代表一个色相, 以 30° 为间隔选择, 以说明常见的 "核心" 色调: 红色, 黄色, 绿色, 青色, 蓝色, 洋红色, 以及这些之间的六种中间颜色。
在每个表格中,X 轴表示饱和度, Y 轴表示亮度。
| 0° 红色 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 30° 红-黄(=橙色) | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 60° 黄色 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 90° 黄绿色 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 120° 绿色 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 150° 绿青色 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 180° 青色 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 210° 青-蓝色 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 240° 蓝色 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 270° 蓝-洋红 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 300° 洋红 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 330° 洋红-红 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
8. HWB 颜色:hwb() 函数
HWB(色相-白度-黑度的缩写)[HWB] 是另一种指定 sRGB 颜色的方法,类似于HSL,但通常对人类来说更容易使用。它通过一个起始色相,然后混入一定程度的白色和黑色来描述颜色。
许多颜色选择器基于 HWB 色彩系统,因为它直观易用。
HWB 颜色解析为 sRGB。
< input type = "color" >
时显示。外部的轮盘用于选择色相,然后通过单击内部三角形选择相对的白色和黑色量。hwb() 函数的语法如下:
hwb () =hwb ( [ <hue> | none] [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ /[ <alpha-value> | none] ] ?)
| 百分比 | 允许用于 W 和 B |
|---|---|
| 百分比参考范围 | 对于 W 和 B:0% = 0.0,100% = 100.0 |
| 无效色相 ε | W + B >= 99.999 |
第一个参数指定色相, 其定义与 hsl() 完全相同; 这意味着它具有相同的缺点,例如色相均匀性。
第二个参数指定要混合的白色量, 百分比范围从 0%(无白色)到 100%(全白色)。 类似地,第三个参数指定要混合的黑色量, 百分比范围也从 0%(无黑色)到 100%(全黑色)。
超出这些范围的值并不无效;色相角度超出 [0,360) 范围将被归一化至该范围,而白色和黑色的值相加为 100% 或更高时,将生成如下所述的无彩色。
最终的颜色可以在概念上理解为选择的色相、白色颜料和黑色颜料的混合物,相对的数量由百分比决定。
如果白色加黑色的和大于或等于 100%,则定义为无彩色,即灰色阴影;转换为 sRGB 时,R、G 和 B 的值相等,其值为 white / (white + black)。
无彩色的 HWB 颜色不再包含任何所选择的色相。在这种情况下,色相组件为无效。
第四个参数指定颜色的 Alpha 分量。 它的解释与 rgb() 函数的第四个参数完全相同。 如果省略,则默认为 100%。
由于 hwb 是本规范此级别中的新增内容,因此不存在 Web 兼容性问题,所以 hwb() 不支持使用逗号分隔其所有参数的旧版颜色语法。 在 hwb() 内部使用逗号是错误的。
测试
8.1. 将 HWB 颜色转换为 sRGB
将 HWB 颜色转换为 sRGB 非常简单,类似于将 HSL 转换为 RGB 的方式。以下是算法的 Javascript 实现,首先将白色和黑色组件标准化,使它们的总和不超过 100%。
/** * @param {number} hue - Hue as degrees 0..360 * @param {number} white - Whiteness in reference range [0,100] * @param {number} black - Blackness in reference range [0,100] * @return {number[]} Array of RGB components 0..1 */ function hwbToRgb( hue, white, black) { white/= 100 ; black/= 100 ; if ( white+ black>= 1 ) { let gray= white/ ( white+ black); return [ gray, gray, gray]; } let rgb= hslToRgb( hue, 100 , 50 ); for ( let i= 0 ; i< 3 ; i++ ) { rgb[ i] *= ( 1 - white- black); rgb[ i] += white; } return rgb; }
8.2. 将 sRGB 颜色转换为 HWB
反向转换的过程类似。
/** * @param {number} red - Red component 0..1 * @param {number} green - Green component 0..1 * @param {number} blue - Blue component 0..1 * @return {number} Hue as degrees 0..360 */ function rgbToHue( red, green, blue) { // Similar to rgbToHsl, except that saturation and lightness are not calculated, and // potential negative saturation is ignored. let max= Math. max( red, green, blue); let min= Math. min( red, green, blue); let hue= NaN ; let d= max- min; if ( d!== 0 ) { switch ( max) { case red: hue= ( green- blue) / d+ ( green< blue? 6 : 0 ); break ; case green: hue= ( blue- red) / d+ 2 ; break ; case blue: hue= ( red- green) / d+ 4 ; } hue*= 60 ; } if ( hue>= 360 ) { hue-= 360 ; } return hue; } /** * @param {number} red - Red component 0..1 * @param {number} green - Green component 0..1 * @param {number} blue - Blue component 0..1 * @return {number[]} Array of HWB values: Hue as degrees 0..360, Whiteness and Blackness in reference range [0,100] */ function rgbToHwb( red, green, blue) { let epsilon= 1 / 100000 ; // account for multiply by 100 var hue= rgbToHue( red, green, blue); var white= Math. min( red, green, blue); var black= 1 - Math. max( red, green, blue); if ( white+ black>= 1 - epsilon) { hue= NaN ; } return ([ hue, white* 100 , black* 100 ]); }
8.3. HWB 颜色示例
本节不是规范性内容。
测试
本节不是规范性内容,不需要测试。
| 0° 红色 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 30° 红-黄色(橙色) | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 60° 黄色 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 90° 黄-绿色 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 120° 绿色 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 150° 绿-青色 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 180° 青色 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 210° 青-蓝色 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 240° 蓝色 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 270° 蓝-品红色 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 300° 品红色 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 330° 品红-红色 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
9. 设备无关颜色:CIE Lab 和 LCH,Oklab 和 OKLCh
9.1. CIE Lab 和 LCH
本节不具规范性。
测试
本节不具规范性,不需要测试。
颜色的物理测量通常表示为 CIE L*a*b* [CIELAB] 色彩空间, 该空间由 CIE 于 1976 年创建,通常简称为 Lab。 从一个设备转换到另一个设备的颜色也可以使用 Lab 作为中间步骤。 Lab 是基于人类视觉实验得出的, 代表了人类可见的所有颜色范围。
Lab 是一个具有中央亮度(L)轴的直角坐标系统。 该值通常表示为无单位的数字; 为了与 CSS 其他部分兼容,也可以写为百分比。 100% 表示 L 值为 100,而不是 1.0。 L=0% 或 0 是深黑色(完全没有光) 而 L=100% 或 100 是漫反射白。
有用的是,L=50% 或 50 是中灰色,且设计上, L 的等增量在视觉上是均匀间隔的: Lab 色彩空间旨在实现感知上的均匀性。
a 和 b 轴传递色相; a 轴正值表示紫红色, 而负值则是互补色,绿色。 类似地,b 轴正值表示黄色, 负值表示互补色蓝色/紫色。 去饱和的颜色具有较小的 a 和 b 值, 并靠近 L 轴; 饱和的颜色则远离 L 轴。
光源是 D50 白光,这是一种标准化的日光光谱,色温为 5000K, 由完美漫反射体反射;它近似于晴天阳光的颜色。 D50 也是 ICC 颜色相互转换中配置文件连接空间使用的白点, 是提供 Lab 编辑功能的图像编辑器中使用的白点, 也是物理测量设备(如分光光度计和分光辐射计) 在报告 Lab 测量颜色时使用的值。
使用其他白点指定颜色的转换被称为 色度适应变换, 其模拟了人类视觉系统在适应新的照明条件时的变化。 线性布拉德福德算法 [ICC](原布拉德福德算法的简化版 [Bradford-CAT]) 是行业标准的色度适应变换, 计算非常简单,因为它只是一个矩阵乘法。
CIE LCH 与 Lab 具有相同的 L 轴, 但使用极坐标 C(色度)和 H(色相), 形成了一个极坐标的柱面坐标系统。 C 是从 L 轴的几何距离, H 是从 a 轴正向到 b 轴正向的角度。
注:Lab 和 LCH 的 L 轴 不要与 HSL 的 L 轴混淆。 例如,在 HSL 中,sRGB 颜色蓝色(#00F)和黄色(#FF0) 具有相同的 L 值(50%),即使在视觉上,蓝色要暗得多。 在 Lab 中这就非常清晰: sRGB 蓝色为 lab(29.567% 68.298 -112.0294) 而 sRGB 黄色为 lab(97.607% -15.753 93.388)。 在 Lab 和 LCH 中,如果两个颜色具有相同的 L 值, 那么它们在视觉亮度上是相同的。 HSL 和相关的极坐标 RGB 模型是为了试图 提供类似于 LCH 给 Lab 的可用性好处的 RGB, 但其准确性显著低于 Lab 和 LCH。
尽管 CIE Lab 和 LCH 得到了广泛使用, 但它们也存在一些问题,尤其是:
- 色相线性度
- 在蓝色区域(LCH 色相介于 270° 和 330° 之间), 视觉色相偏离了 LCH 的预测。 如果绘制一组相同色相且色度不同的蓝色, 这些颜色应该形成一条从中性轴延伸的直线, 但实际上形成了曲线。 换句话说, 随着一个饱和的蓝色的色度逐渐减少, 它会变得显著偏紫。
- 色相均匀性
- 虽然 LCH 中的色相通常是均匀间隔的, (且远优于 HSL 或 HWB), 但均匀性并不完美。
- 高色度差异的过度预测
- 对于高色度的颜色, 色度的变化不如中性色更明显。
这些缺陷影响了,例如, 创建均匀间隔的渐变, 将一个色彩空间映射到一个较小的色彩空间, 以及计算两个颜色之间的视觉差异。
为弥补这一点, 预测两个颜色之间视觉差异的公式 (Delta E) 随时间的推移变得更加准确 (但也更复杂)。 当前的行业标准公式, Delta E 2000, 对于缓解 Lab 和 LCH 的某些问题效果良好。 § 19.1 ΔE2000 中给出了示例实现。
但是这对色相曲率问题没有帮助。
9.2. Oklab 和 OKLCh
本节不具规范性。
测试
本节不具规范性,不需要测试。
最近,Oklab,一种改进的类 Lab 空间被开发出来 [Oklab]。 对应的极坐标形式称为 OKLCh。 它是通过对大量视觉上相似的颜色数据集进行数值优化而产生的, 与 CIE LCH 相比,其色相线性度、色相均匀性和色度均匀性都有所提高。
与 CIE Lab 一样,Oklab 有一个中心的亮度 L 轴, 通常表示为范围 [0,1] 的无单位数值; 为了与 CSS 其他部分兼容, 也可以写为百分比。100% 表示 L 值为 1.0。 L=0% 或 0.0 表示深黑色(完全没有光),而 L=100% 或 1.0 表示漫反射白。
注: 与 CIE Lab 不同,CIE Lab 假设适应漫反射白色, 而 Oklab 假设适应被定义的颜色, 这旨在使其具有比例不变性。
与 CIE Lab 一样,a 和 b 轴传递色相; a 轴正值表示紫红色, 负值表示互补色,绿色。 类似地,b 轴正值表示黄色, 负值表示互补的蓝色/紫色。
光源是 D65,与大多数 RGB 色彩空间使用的白点相同。
OKLCh 与 Oklab 具有相同的 L 轴, 但使用极坐标 C(色度)和 H(色相)。
注意:与 CIE LCH 中色度可以达到 200 或更高不同, OKLCh 色度范围约为 0.5。 CIE LCH 和 OKLCh 之间的色相角大致相似, 但不完全相同。
由于 Oklab 的感知均匀性优于 CIE Lab, 因此颜色差异可以通过 3D 空间中的距离(平方和的平方根)直接计算。 尽管计算简单, § 19.2 ΔEOK 中给出了示例实现。
9.3. 指定 Lab 和 LCH:lab() 和 lch() 函数表示法
CSS 允许直接以 Lab 和 LCH 表示颜色。
lab () =lab ( [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ /[ <alpha-value> | none] ] ?)
| 百分比 | 允许用于 L, a 和 b |
|---|---|
| 百分比参考范围 | 对于 L:0% = 0.0, 100% = 100.0 对于 a 和 b:-100% = -125, 100% = 125 |
测试
- lab-001.html (实时测试) (来源)
- lab-002.html (实时测试) (来源)
- lab-003.html (实时测试) (来源)
- lab-004.html (实时测试) (来源)
- lab-005.html (实时测试) (来源)
- lab-006.html (实时测试) (来源)
- lab-007.html (实时测试) (来源)
- lab-008.html (实时测试) (来源)
- lab-l-over-100-1.html (实时测试) (来源)
- lab-l-over-100-2.html (实时测试) (来源)
- color-valid.html (实时测试) (来源)
- color-computed-lab.html (实时测试) (来源)
- color-invalid-lab.html (实时测试) (来源)
- color-valid-lab.html (实时测试) (来源)
在Lab中, 第一个参数指定了 CIE 亮度,即 L。 这是一个介于 0% 或 0 和 100% 或 100 之间的数值。 值小于 0% 或 0 时必须在解析值时夹紧为 0%; 值大于 100% 或 100 时在解析值时夹紧为 100%。
第二个和第三个参数是 Lab 色彩空间中 “a” 轴和 “b” 轴上的距离, 如前一节所述。 这些值是有符号的 (允许为正或负值), 理论上不受限 (但实际应用中真实颜色不会超过 ±160)。
有一个可选的第四个 <alpha-value> 分量, 用斜杠分隔, 表示 alpha 分量。
如果 Lab 颜色的明度(经过钳制后)为 0%, 或 100%, 那么该颜色因显示设备的色域映射 会分别显示为黑色或白色。
lab ( 29.2345 % 39.3825 20.0664 ); lab ( 52.2345 40.1645 59.9971 ); lab ( 60.2345 -5.3654 58.956 ); lab ( 62.2345 % -34.9638 47.7721 ); lab ( 67.5345 -8.6911 -41.6019 ); lab ( 29.69 % 44.888 % -29.04 % )
lch () =lch ( [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ <hue> | none] [ /[ <alpha-value> | none] ] ?)
| 百分比 | 允许用于 L 和 C |
|---|---|
| 百分比参考范围 | 对于 L: 0% = 0.0, 100% = 100.0 对于 C: 0% = 0, 100% = 150 |
| 无效色相 ε | C <= 0.0015 |
测试
- lch-001.html (实时测试) (来源)
- lch-002.html (实时测试) (来源)
- lch-003.html (实时测试) (来源)
- lch-004.html (实时测试) (来源)
- lch-005.html (实时测试) (来源)
- lch-006.html (实时测试) (来源)
- lch-007.html (实时测试) (来源)
- lch-008.html (实时测试) (来源)
- lch-009.html (实时测试) (来源)
- lch-010.html (实时测试) (来源)
- lch-l-over-100-1.html (实时测试) (来源)
- lch-l-over-100-2.html (实时测试) (来源)
- color-valid.html (实时测试) (来源)
在 CIE LCH 中,第一个参数表示 CIE 的亮度 L,与 lab() 的亮度参数相同。
第二个参数是色度 C(大致表示“颜色的浓度”)。 它的最小有效值为 0,而最大值在理论上是无限的(但实际上不超过 230)。 如果提供的值为负数,则在解析值阶段将其夹紧到 0。
第三个参数是色相角 H。 它的解释方式类似于 <hue> 参数在 hsl() 中的解释方式, 但在这里色相均匀地分布在角度上,而不是与角度相同的映射。 因此,0deg 沿正 "a" 轴方向(朝向紫红色),(同样适用于 360deg、720deg 等); 90deg 沿正 "b" 轴方向(朝向芥黄色),180deg 沿负 "a" 轴方向 (朝向绿色青色),270deg 沿负 "b" 轴方向(朝向天蓝色)。
有一个可选的第四个 <alpha-value> 组件, 用斜线分隔,表示 alpha 组件。
如果 LCH 颜色的色度为 0%,则色相组件是 无效的。 如果 LCH 颜色的亮度(在夹紧后)为 0% 或 100%,则颜色将分别显示为黑色或白色, 这是由于显示器的色域映射。
lch ( 29.2345 % 44.2 27 ); lch ( 52.2345 % 72.2 56.2 ); lch ( 60.2345 59.2 95.2 ); lch ( 62.2345 % 59.2 126.2 ); lch ( 67.5345 % 42.5 258.2 ); lch ( 29.69 % 45.553 % 327.1 )
在lab或lch 中, 这些函数在此规范级别是全新的, 因此lab() 和 lch() 不 支持使用逗号分隔其所有参数的 旧颜色语法。 在这些函数中使用逗号是错误的。
9.4. 指定 Oklab 和 OKLCh:oklab() 和 oklch() 函数表示法
CSS 允许直接用 Oklab 和 OKLCh 表示颜色。
oklab () =oklab ( [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ /[ <alpha-value> | none] ] ?)
| 百分比 | L、a 和 b 可以使用百分比 |
|---|---|
| 百分比参考范围 | 对于 L:0% = 0.0,100% = 1.0 对于 a 和 b:-100% = -0.4,100% = 0.4 |
测试
- oklab-001.html (实时测试) (来源)
- oklab-002.html (实时测试) (来源)
- oklab-003.html (实时测试) (来源)
- oklab-004.html (实时测试) (来源)
- oklab-005.html (实时测试) (来源)
- oklab-006.html (实时测试) (来源)
- oklab-007.html (实时测试) (来源)
- oklab-008.html (实时测试) (来源)
- oklab-009.html (实时测试) (来源)
- oklab-l-almost-0.html (实时测试) (来源)
- oklab-l-almost-1.html (实时测试) (来源)
- oklab-l-over-1-1.html (实时测试) (来源)
- oklab-l-over-1-2.html (实时测试) (来源)
- color-valid.html (实时测试) (来源)
在 Oklab 中,第一个参数指定 Oklab 的亮度。 这是一个在 0% 或 0 和 100% 或 1.0 之间的数字。
小于 0% 或 0.0 的值必须在解析时被钳制到 0%; 大于 100% 或 1.0 的值在解析时被钳制到 100%。
第二个和第三个参数是沿 Oklab 颜色空间中的 "a" 和 "b" 轴的距离, 如前一节所述。 这些值是有符号的 (允许正值和负值) 理论上是无限的 (但实际上不超过 ±0.5)。
还有一个可选的第四个 <alpha-value> 组件, 用斜杠分隔, 表示alpha 组件。
如果 Oklab 颜色的亮度为 0% 或 0, 或者 100% 或 1.0, 则由于显示的色域映射, 颜色将分别显示为黑色或白色。
oklab ( 40.101 % 0.1147 0.0453 ); oklab ( 59.686 % 0.1009 0.1192 ); oklab ( 0.65125 -0.0320 0.1274 ); oklab ( 66.016 % -0.1084 0.1114 ); oklab ( 72.322 % -0.0465 -0.1150 ); oklab ( 42.1 % 41 % -25 % )
oklch () =oklch ( [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ <hue> | none] [ /[ <alpha-value> | none] ] ?)
| 百分比 | 适用于 L 和 C |
|---|---|
| 百分比参考范围 | 对于 L:0% = 0.0, 100% = 1.0 对于 C:0% = 0.0, 100% = 0.4 |
| 无效色相 ε | C <= 0.000004 |
测试
- oklch-001.html (实时测试) (来源)
- oklch-002.html (实时测试) (来源)
- oklch-003.html (实时测试) (来源)
- oklch-004.html (实时测试) (来源)
- oklch-005.html (实时测试) (来源)
- oklch-006.html (实时测试) (来源)
- oklch-007.html (实时测试) (来源)
- oklch-008.html (实时测试) (来源)
- oklch-009.html (实时测试) (来源)
- oklch-010.html (实时测试) (来源)
- oklch-011.html (实时测试) (来源)
- oklch-l-almost-0.html (实时测试) (来源)
- oklch-l-almost-1.html (实时测试) (来源)
- oklch-l-over-1-1.html (实时测试) (来源)
- oklch-l-over-1-2.html (实时测试) (来源)
- color-valid.html (实时测试) (来源)
在 OkLCh 中, 第一个参数指定 OkLCh 明度 L, 与 oklab() 的明度参数解释方式完全一致。
第二个参数是色度 C。 它的最小有效值是 0, 最大值理论上没有限制 (但实际上不会超过 0.5)。 如果提供的值为负数, 解析时会被钳制为 0。
第三个参数是色相角 H。 它的解释方式类似 <hue>, 以及 hsl() 和 lch() 的参数, 但色相与角度的映射方式不同。 0deg 指向正 "a" 轴(偏向紫红色), (360deg、720deg 等也如此); 90deg 指向正 "b" 轴(偏向芥末黄), 180deg 指向负 "a" 轴(偏向青绿色), 270deg 指向负 "b" 轴(偏向天蓝色)。
有一个可选的第四个 <alpha-value> 分量, 用斜杠分隔, 表示 alpha 分量。
如果 OkLCh 颜色的色度为 0% 或 0, 那么色相分量是无效分量。 如果 OkLCh 颜色的明度为 0% 或 0, 或 100% 或 1.0, 那么该颜色会因显示设备的色域映射 分别显示为黑色或白色。
oklch ( 40.101 % 0.12332 21.555 ); oklch ( 59.686 % 0.15619 49.7694 ); oklch ( 0.65125 0.13138 104.097 ); oklch ( 0.66016 0.15546 134.231 ); oklch ( 72.322 % 0.12403 247.996 ); oklch ( 42.1 % 48.25 % 328.4 )
对于 oklab 和 oklch,它们都是本规范此级新增内容, 所以 oklab() 和 oklch() 不支持用逗号分隔所有参数的传统颜色语法。 在这些函数内部使用逗号会被视为错误。
9.5. Lab 或 Oklab 颜色转换为 LCH 或 OkLCh 颜色
转换为极坐标形式非常简单:
- C = sqrt(a^2 + b^2)
- 如果 (C > epsilon) H = atan2(b, a) 否则 H 缺省
- L 保持一致
当 a 和 b 极小(色度接近零)时, 虽然视觉颜色不会发生改变,依旧位于中性轴, 但这些值稍作变动,就导致输出的色相角剧烈抖动,呈现几乎随机的结果。 在 CSS 中,这意味着该色相为无效分量, 并在转换到 LCH 或 OkLCh 时视为缺省分量; 而在非 CSS 场景下,这可能体现在输出缺省值(如 NaN)。
9.6. LCH 或 OkLCh 颜色转换为 Lab 或 Oklab 颜色
转换为直角坐标形式非常简单:
- 如果 H 缺省,则 a = b = 0
-
否则,
- a = C cos(H)
- b = C sin(H)
- L 保持一致
10. 预定义的色彩空间
CSS 提供了几种预定义的色彩空间, 包括 display-p3 [Display-P3], 这是一种典型的广色域空间,适用于当前的广色域显示器,prophoto-rgb,广泛用于摄影师, 以及 rec2020 [Rec.2020], 这是一种广播行业标准, 超广色域空间,几乎可以表示所有可见的真实世界色彩。
10.1. 指定预定义颜色:color() 函数
color() 函数允许在特定的、指定的 色彩空间 中指定颜色 (而不是大多数其他颜色函数操作的隐含 sRGB 色彩空间)。 它的语法如下:
color () =color ( <colorspace-params>[ /[ <alpha-value> | none] ] ?) <colorspace-params> =[ <predefined-rgb-params> | <xyz-params>] <predefined-rgb-params> = <predefined-rgb>[ <number> | <percentage> | none] { 3 } <predefined-rgb> = srgb | srgb-linear | display-p3 | a98-rgb | prophoto-rgb | rec2020 <xyz-params> = <xyz-space>[ <number> | <percentage> | none] { 3 } <xyz-space> = xyz | xyz-d50 | xyz-d65
测试
color 函数接受指定颜色的参数,并在显式列出的色彩空间中指定。
参数形式如下:
-
一个 <ident>,表示 预定义的色彩空间之一(例如 display-p3)。 具体的 预定义色彩空间 可能进一步限制是否可以使用 <number> 或 <percentage> 或两者。
如果 <ident> 指定的名称不是一个有效的色彩空间 (即不是 预定义色彩空间 之一), 那么该参数表示一个 无效颜色。
-
色彩空间接受的三个参数值(如 RGB 或 XYZ 值)。
超出色域的颜色具有小于 0 或 0%,或者大于 1 或 100% 的分量值。 这些并不是无效的,且会保留用于中间计算; 但是在显示时,它们会使用相对比色意图进行 CSS 色域映射, 使得值(在显示色彩空间中)在实际值时落入 0/0% 到 1/100% 的范围内。
-
一个可选的斜线分隔的 <alpha-value>。
使用 color() 没有 Web 兼容性问题, 因为它是在这个规范级别中新引入的,因此 color() 不 支持使用逗号分隔所有参数的 旧色彩语法。 在这个函数中使用逗号是错误的。
如果颜色是 无效颜色 或者 是 超出色域 的颜色, 那么该颜色 无法显示。
如果指定的颜色 可以显示, (即它不是 无效颜色 并且不是 超出色域), 那么这就是 color() 函数的实际值。
如果指定的颜色 是一个 有效颜色 但 无法显示, 那么实际值是从指定的颜色派生的,并经过 CSS 色域映射 用于显示。
color ( rec20200.42053 0.979780 0.00579 );
在 LCH 中,该颜色为
lch ( 85.9017 % 166.116 138.207 );
在 display-p3 中,该颜色为
color ( display-p3-0.350289 1.00707 -0.144209 );
且超出了 display-p3 的色域 (红色和蓝色为负值,绿色大于1)。 如果你有显示 p3 屏幕,则该颜色:
- 有效
- 在色域范围内(对于 rec.2020)
- 超出色域范围(对于你的显示器)
- 因此 无法显示
color ( profoto-rgb0.4835 0.9167 0.2188 )
10.2. 预定义的 sRGB 颜色空间:sRGB 关键字
下面定义的 sRGB 预定义颜色空间 与用于传统 sRGB 颜色(如 rgb())的相同。
- srgb
-
srgb
[SRGB]
色彩空间接受三个数字参数,分别表示颜色的红色、绿色和蓝色分量。
色域内的颜色,其三个分量均在 [0, 1] 范围内。
白点是 D65。
[SRGB] 指定了两种观看条件:编码和典型。[ICC] 建议使用编码条件进行颜色转换和最佳观看,这些值如下表所示。
sRGB 是 CSS 的默认色彩空间,用于所有旧版颜色函数。
它具有以下特性:
x y 红色色度 0.640 0.330 绿色色度 0.300 0.600 蓝色色度 0.150 0.060 白色色度 D65 传递函数 见下文 白色亮度 80.0 cd/m2 黑色亮度 0.20 cd/m2 图像状态 显示参考 百分比 允许用于 R、G 和 B 百分比参考范围 对于 R,G,B:0% = 0.0,100% = 1.0 let sign= c< 0 ? - 1 : 1 ; let abs= Math. abs( c); if ( abs<= 0.04045 ) { cl= c/ 12.92 ; } else { cl= sign* ( Math. pow(( abs+ 0.055 ) / 1.055 , 2.4 )); } c 是经过伽马编码的红色、绿色或蓝色分量。 cl 是相应的线性光分量。
sRGB 色彩空间在 LCH 中的可视化。显示了原色和二次色。
10.3. 预定义的线性光 sRGB 颜色空间:srgb-linear 关键字
sRGB-linear 预定义颜色空间 与 srgb 相同,除了传递函数为线性光(无伽马编码)。
- srgb-linear
-
srgb-linear [SRGB]
色彩空间接受三个数字参数,
分别表示颜色的红色、绿色和蓝色分量。
色域内的颜色,其三个分量均在 [0, 1] 范围内。
白点是 D65。
它具有以下特性:
x y 红色色度 0.640 0.330 绿色色度 0.300 0.600 蓝色色度 0.150 0.060 白色色度 D65 传递函数 统一,见下文 白色亮度 80.0 cd/m2 黑色亮度 0.20 cd/m2 图像状态 显示参考 百分比 允许用于 R, G 和 B 百分比参考范围 对于 R, G, B: 0% = 0.0, 100% = 1.0 cl
= c; c 是红、绿或蓝分量。 cl 是相应的线性光分量,且与 c 相同。
为避免带状伪影,需要更高的精度用于 srgb-linear 相较于 srgb。
测试
10.4. 预定义的 Display P3 颜色空间:display-p3 关键字
- display-p3
-
display-p3 [Display-P3] 色彩空间接受三个数字参数,
分别表示颜色的红色、绿色和蓝色分量。
色域内的颜色,其三个分量均在 [0, 1] 范围内。
它使用与 [DCI-P3] 相同的主色度,
但使用 D65 白点,以及与 sRGB 相同的传递曲线。
现代显示器、电视、笔记本屏幕和手机屏幕能够显示全部或几乎全部的 display-p3 色域。
它具有以下特性:
x y 红色色度 0.680 0.320 绿色色度 0.265 0.690 蓝色色度 0.150 0.060 白色色度 D65 传递函数 与 srgb 相同 白色亮度 80.0 cd/m2 黑色亮度 0.80 cd/m2 图像状态 显示参考 百分比 允许用于 R, G 和 B 百分比参考范围 对于 R, G, B: 0% = 0.0, 100% = 1.0 在 LCH 中可视化 P3 颜色空间。图中显示了原色和次原色(但在 sRGB 中,并不是正确的颜色)。为了对比,还显示了 sRGB 的原色和次原色,作为虚线圆圈。 P3 原色具有更高的色度。
测试
- predefined-005.html (实时测试) (来源)
- predefined-006.html (实时测试) (来源)
- display-p3-001.html (实时测试) (来源)
- display-p3-002.html (实时测试) (来源)
- display-p3-003.html (实时测试) (来源)
- display-p3-004.html (实时测试) (来源)
- display-p3-005.html (实时测试) (来源)
- display-p3-006.html (实时测试) (来源)
- 2d.color.space.p3.fillText.html (P3 色彩空间填充文本) (实时测试) (来源)
- 2d.color.space.p3.fillText.shadow.html (P3 色彩空间填充文本阴影) (实时测试) (来源)
- 2d.color.space.p3.strokeText.html (P3 色彩空间描边文本) (实时测试) (来源)
- 2d.color.space.p3.to.p3.html (P3 色彩空间转换为 P3) (实时测试) (来源)
- 2d.color.space.p3.to.srgb.html (P3 色彩空间转换为 sRGB) (实时测试) (来源)
- 2d.color.space.p3.toBlob.p3.canvas.html (P3 色彩空间画布转换为 Blob) (实时测试) (来源)
- 2d.color.space.p3.toBlob.with.putImageData.html (P3 色彩空间使用 putImageData 转换为 Blob) (实时测试) (来源)
- 2d.color.space.p3.toDataURL.jpeg.p3.canvas.html (P3 色彩空间画布转换为 JPEG DataURL) (实时测试) (来源)
- 2d.color.space.p3.toDataURL.p3.canvas.html (P3 色彩空间画布转换为 DataURL) (实时测试) (来源)
- 2d.color.space.p3.toDataURL.with.putImageData.html (P3 色彩空间使用 putImageData 转换为 DataURL) (实时测试) (来源)
10.5. 预定义线性光 Display P3 色彩空间:display-p3-linear 关键字
display-p3-linear 预定义色彩空间 与 display-p3 唯一的区别是其变换函数 是线性光(没有伽玛编码)。
其具有以下特性:
| x | y | |
| 红色色度 | 0.680 | 0.320 |
|---|---|---|
| 绿色色度 | 0.265 | 0.690 |
| 蓝色色度 | 0.150 | 0.060 |
| 白色色度 | D65 | |
| 变换函数 | 恒等函数,见下方 | |
| 白色亮度 | 80.0 cd/m2 | |
| 黑色亮度 | 0.80 cd/m2 | |
| 图像状态 | 显示参考 | |
| 百分比 | R、G 和 B 都允许 | |
| 百分比参考范围 | 对于 R、G、B:0% = 0.0,100% = 1.0 | |
cl= c;
c 为红色、绿色或蓝色分量, cl 为相应的线性光分量,且与 c 完全一致。
为避免出现色带伪影, display-p3-linear 要求的精度更高 相较于 display-p3。
测试
10.6. 预定义 A98 RGB 色彩空间:a98-rgb 关键字
- a98-rgb
-
a98-rgb 色彩空间接受三个数值参数,
表示颜色的红、绿、蓝分量。
色域范围内的颜色,其三个分量都在 [0, 1] 之间。
变换曲线是
接近但不等于 1/2.2 的伽玛函数。
其具有以下特性:
x y 红色色度 0.6400 0.3300 绿色色度 0.2100 0.7100 蓝色色度 0.1500 0.0600 白色色度 D65 变换函数 256/563 白色亮度 160.0 cd/m2 黑色亮度 0.5557 cd/m2 图像状态 显示参考 百分比 R、G 和 B 都允许 百分比参考范围 对于 R、G、B:0% = 0.0,100% = 1.0 A98 色彩空间在 LCH 中的可视化。 图中展示了主色和二次色 (但呈现为 sRGB 色,不是实际色彩)。 对比参考,还显示了 sRGB 主色和二次色(虚线圆)。 a98 主色具有更高色度, 尤其是黄色、绿色和青色。
测试
10.7. 预定义 ProPhoto RGB 色彩空间:prophoto-rgb 关键字
- prophoto-rgb
-
prophoto-rgb 色彩空间接受三个数字参数,
分别表示颜色的红色、绿色和蓝色分量。
色域内的颜色,其三个分量均在 [0, 1] 范围内。
传递曲线是一个伽马值为 1/1.8 的伽马函数,
在黑色附近有一个小的线性部分。
白点是 D50,与 CIE Lab 使用的白点相同。因此,
转换为 CIE Lab 不需要色度适应步骤。
ProPhoto RGB 空间使用超饱和的、非物理可实现的原色。 这些原色的选择旨在提供广色域,特别是为了在色调操作下最小化色相偏移。 它通常用于数字摄影作为宽色域的颜色空间, 用于保存摄影图像的存档版本。 prophoto-rgb 颜色空间允许 CSS 指定与这些图像中 RGB 值相同的颜色。
ProPhoto RGB 空间最初由柯达开发,并在 [Wolfe] 中进行了描述。 它由 ISO 标准化为 [ROMM],[ROMM-RGB]。
白色亮度给出一个范围,视场耀斑(也就是黑色亮度)是此范围的 0.5% 到 1.0%。
它具有以下特性:
x y 红色色度 0.734699 0.265301 绿色色度 0.159597 0.840403 蓝色色度 0.036598 0.000105 白色色度 D50 传递函数 见下文 白色亮度 160.0 到 640.0 cd/m2 黑色亮度 见文本 图像状态 显示参考 百分比 允许用于 R, G 和 B 百分比参考范围 对于 R, G, B: 0% = 0.0, 100% = 1.0 const E= 16 / 512 ; let sign= c< 0 ? - 1 : 1 ; let abs= Math. abs( c); if ( abs<= E) { cl= c/ 16 ; } else { cl= sign* Math. pow( c, 1.8 ); } c 是伽玛编码的红、绿或蓝分量。 cl 是相应的线性光分量。
在 LCH 中可视化 ProPhoto RGB 颜色空间。 图中显示了原色和次原色(但在 sRGB 中,并不是正确的颜色)。 为了对比,还显示了 sRGB 的原色和次原色,作为虚线圆圈。 ProPhoto RGB 的原色和次原色具有更高的色度,但这种超宽色域的大部分 不对应于物理上可实现的颜色。
测试
10.8. 预定义的 ITU-R BT.2020-2 颜色空间:rec2020 关键字
- rec2020
-
rec2020 [Rec.2020]
色彩空间接受三个数值参数,
分别代表颜色的红、绿、蓝分量。
色域内的颜色这三个分量都在 [0, 1] 范围内,
(在视频术语中称为“满范围”)。
ITU 参考 2020 用于
超高清、4k 和 8k 电视。
主色可以物理实现, 但难度很高, 因为它们非常接近光谱曲线边界。
目前的显示器无法还原 rec2020 的全部色域。 随着显示技术提升,覆盖率未来会逐步增加。
其具有以下特性:
x y 红色色度 0.708 0.292 绿色色度 0.170 0.797 蓝色色度 0.131 0.046 白色色度 D65 变换函数 伽玛 2.40,参考 [REC_BT.1886] 图像状态 显示参考 百分比 R、G 和 B 都允许 百分比参考范围 R、G、B:0% = 0.0,100% = 1.0 rec2020 色彩空间在 LCH 中的可视化。图中展示了主色和二次色 (但显示为 sRGB 色,而非真实色彩)。 作为对比,还显示了 sRGB 主色和二次色(虚线圆)。 rec2020 主色具有更高的色度。
测试
10.9. 预定义的 CIE XYZ 颜色空间:xyz-d50、xyz-d65 和 xyz 关键字
- xyz-d50、xyz-d65、xyz
-
xyz
色彩空间接受三个数字参数,
分别表示 X、Y 和 Z 值。
它表示 CIE XYZ [COLORIMETRY] 色彩空间,
经过缩放以使漫射白的亮度 (Y) 为 1.0,
并且在必要时进行色度适应以匹配参考白。
xyz-d50 的参考白是 D50,而 xyz-d65 和 xyz 的参考白是 D65。
允许大于 1.0/100% 的值,并且不得被限制; Y 大于 1.0 的颜色表示比漫射白更亮的颜色。 小于 0/0% 的值不常见, 但可能由于色度适应而出现, 同样不得被限制。
它具有以下特性:
百分比 允许用于 X, Y, Z 百分比参考范围 对于 X, Y, Z: 0% = 0.0, 100% = 1.0
测试
- predefined-016.html (实时测试) (来源)
- xyz-001.html (实时测试) (来源)
- xyz-002.html (实时测试) (来源)
- xyz-003.html (实时测试) (来源)
- xyz-004.html (实时测试) (来源)
- xyz-005.html (实时测试) (来源)
- xyz-d50-001.html (实时测试) (来源)
- xyz-d50-002.html (实时测试) (来源)
- xyz-d50-003.html (实时测试) (来源)
- xyz-d50-004.html (实时测试) (来源)
- xyz-d50-005.html (实时测试) (来源)
- xyz-d65-001.html (实时测试) (来源)
- xyz-d65-002.html (实时测试) (来源)
- xyz-d65-003.html (实时测试) (来源)
- xyz-d65-004.html (实时测试) (来源)
- xyz-d65-005.html (实时测试) (来源)
- color-valid.html (实时测试) (来源)
10.10. 将预定义的颜色空间转换为 Lab 或 Oklab
对于所有预定义的 RGB 颜色空间,转换为 Lab 需要几个步骤,虽然在实践中,除第一个步骤外,其余步骤都是线性计算,并且可以组合在一起。
- 将伽玛编码的 RGB 转换为线性光 RGB(撤销伽玛编码)
- 将线性 RGB 转换为 CIE XYZ
- 如需,将 D65 白点 (用于 sRGB、display-p3、a98-rgb 以及 rec2020) 转换为 Lab 所用的 D50 白点, 使用线性 Bradford 变换。prophoto-rgb 已采用 D50 白点。
- 将 D50 适配的 XYZ 转换为 Lab
转换为 Oklab 类似, 但色度适配步骤 只需要对 prophoto-rgb 进行。
- 将伽玛编码的 RGB 转换为线性光 RGB(撤销伽玛编码)
- 将线性 RGB 转换为 CIE XYZ
- 如需,将 D50 白点(用于 prophoto-rgb) 转换为 Oklab 所用的 D65 白点, 使用线性 Bradford 变换。
- 将 D65 适配的 XYZ 转换为 Oklab
这些转换的 JavaScript 示例代码可以在 § 18 颜色转换的示例代码 中找到。
10.11. 将 Lab 或 Oklab 转换为预定义的 RGB 颜色空间
从 Lab 转换为诸如 display-p3 或 rec2020 等预定义空间也需要多个步骤,并且在实践中,除最后一步外,其余步骤都是线性计算,并且可以组合在一起。
- 将 Lab 转换为(D50 适应的)XYZ
- 如果需要,使用线性 Bradford 变换将 Lab 使用的 D50 白点转换为 sRGB 和大多数其他 RGB 空间中使用的 D65 白点。 prophoto-rgb 不需要此步骤。
- 将(D65 适应的)CIE XYZ 转换为线性 RGB
- 将线性光 RGB 转换为 RGB(执行伽马编码)
从 Oklab 转换类似,但色度适应步骤仅对 prophoto-rgb 需要。
- 将 Oklab 转换为(D65 适应的)XYZ
- 如果需要,使用线性 Bradford 变换将 Oklab 使用的 D65 白点转换为 prophoto-rgb 中使用的 D50 白点。
- 将(D65 适应的)CIE XYZ 转换为线性 RGB
- 将线性光 RGB 转换为 RGB(执行伽马编码)
这些转换的 JavaScript 示例代码可以在 § 18 颜色转换的示例代码 中找到。
实现可能选择以其他方式实现这些步骤(例如,使用具有相对色度渲染意图的 ICC 配置文件),只要源和目标色域中的颜色的结果相同即可。
10.12. 在预定义 RGB 颜色空间之间转换
从一个预定义的 RGB 颜色空间转换到另一个需要多个步骤,其中一个步骤仅在白点不同的情况下需要。要从 src 转换到 dest:
- 从伽马编码的 srcRGB 转换为线性光 srcRGB(撤销伽马编码)
- 将线性 srcRGB 转换为 CIE XYZ
- 如果 src 和 dest 具有不同的白点,则将 XYZ 值从 srcWhite 转换为 destWhite,使用线性 Bradford 转换。
- 将 CIE XYZ 转换为线性 destRGB
- 将线性光 destRGB 转换为 destRGB(进行伽马编码)
这些预定义 RGB 颜色空间的转换的 JavaScript 示例代码可以在 § 18 颜色转换的示例代码 中找到。
10.13. 简单的 Alpha 合成
绘制时,实施必须根据 《合成与混合》第 5.1 节“简单 alpha 合成”中的规则处理 alpha 值 [Compositing]。
11. 转换颜色
测试
本节提供的算法在后面使用,不需要测试。
颜色可以从一个颜色空间转换到另一个颜色空间,前提是没有色域映射,并且每个颜色空间都可以表示超出色域的颜色(对于 RGB 空间,这意味着传递函数在扩展范围内定义),那么(受限于数值精度和舍入误差)两个颜色看起来会相同,表示相同的颜色感受。
要将源颜色空间 src 中的颜色 col1,白点为 src-white,转换为目标颜色空间 dest 中的颜色 col2,白点为 dest-white:
- 如果 src 是圆柱极坐标色彩表示, 首先将 col1 转换为对应的矩形正交色彩表示, 并将其作为新的 col1。
- 将所有缺省分量替换为零。
- 如果 src 不是 线性光表示法, 则将其转换为线性光(撤销伽玛编码), 并将其作为新的 col1。
- 将 col1 按指定白点 src-white 转换为 CIE XYZ, 并将其命名为 xyz。
- 如果 dest-white 与 src-white 不同, 用线性 Bradford 色度适配变换对 xyz 进行色度适配到 dest-white, 并将其作为新的 xyz。
- 如果 dest 是圆柱极坐标色彩表示, 则令 dest-rect 为对应的矩形正交色彩表示。 否则,令 dest-rect 为 dest。
- 将 xyz 转换为 dest, 并执行任何变换函数(伽玛编码), 生成 col2。
- 如果 dest 是物理输出色彩空间,如显示设备, 则必须对 col2 进行css 色域映射, 以确保它可显示。
- 如果 dest-rect 与 dest 不同, 即 dest 是圆柱极坐标色彩表示, 则从 dest-rect 转换为 dest,并将结果赋值为 col2。 此过程可能产生缺省分量。
12. 颜色插值
颜色插值发生在渐变、合成、滤镜、过渡、动画以及颜色混合和颜色修改函数中。
两个 <color> 值之间的插值通过执行以下步骤进行:
- 检查两种颜色的类似分量,这些分量将被沿用
- 将它们转换为给定的色彩空间, 下文将其称为插值色彩空间。 如果一种或两种颜色已处于插值色彩空间中, 此转换会将任何无效分量更改为缺失值
- (如果需要)在转换后的颜色中重新插入沿用的值
- (如果需要)根据所选的 <hue-interpolation-method> 修正色相
- 将颜色分量更改为预乘形式
- 分别对颜色的计算值的每个分量进行线性插值
- 撤销预乘
可以插值到或从 currentcolor。为此使用的数值为使用的值。
12.1. 插值的颜色空间
CSS 中的各种特性依赖于插值颜色。
混合或组合颜色时,结果会因所使用的 插值颜色空间 不同而有所差异。因此,不同的插值用途可能适用于不同的颜色空间。
-
在某些情况下,可能需要物理混合两束有色光的结果。 此时,CIE XYZ、display-p3-linear 或 srgb-linear 色彩空间是合适选择,因为它们在光强度上是线性的。
-
最后,兼容旧版 Web 内容可能是最重要的考虑因素。 sRGB 色彩空间既不是线性光,也不是感知均匀的,这种情况下选择它, 即使它的效果较差(混合结果偏暗或偏灰)。
这些功能统称为宿主语法。
为了允许宿主语法指示插值色彩空间, 本规范导出一个 color-interpolation-method 产生式。 它本身不被本规范使用, 仅暴露出来以便其他规范可以使用它;例如,请参阅 CSS 图像 4 § 3.1 线性渐变:linear-gradient() 表示法中的用法。
宿主语法应定义每种情况下默认的插值色彩空间应该是什么, 并且最好提供语法供作者覆盖此默认值。 如果此类语法是属性值的一部分,则应使用下面定义的 color-interpolation-method 产生式, 以便其他规范轻松参考。 这确保了 CSS 之间的一致性, 并且有关如何执行颜色插值的进一步自定义可以自动渗透到所有 CSS 中。
<color-space> = <rectangular-color-space> | <polar-color-space> <rectangular-color-space> = srgb | srgb-linear | display-p3 | display-p3-linear | a98-rgb | prophoto-rgb | rec2020 | lab | oklab | <xyz-space> <polar-color-space> = hsl | hwb | lch | oklch <hue-interpolation-method> =[ shorter | longer | increasing | decreasing] hue <color-interpolation-method> = in[ <rectangular-color-space> | <polar-color-space> <hue-interpolation-method>?]
在 <rectangular-color-space> 和 <polar-color-space> 的定义中的关键字各自引用其对应的颜色空间,这些颜色空间在 CSS 中既可以通过同名的函数语法表示,也可以(如果没有这样的函数)通过 <ident> 在 color() 函数中表示。
测试
- gradients-with-transparent.html (实时测试) (来源)
- gradient-eval-001.html (实时测试) (来源)
- gradient-eval-002.html (实时测试) (来源)
- gradient-eval-003.html (实时测试) (来源)
- gradient-eval-004.html (实时测试) (来源)
- gradient-eval-005.html (实时测试) (来源)
- gradient-eval-006.html (实时测试) (来源)
- gradient-eval-007.html (实时测试) (来源)
- gradient-eval-008.html (实时测试) (来源)
- gradient-eval-009.html (实时测试) (来源)
- gradient-none-interpolation.html (实时测试) (来源)
- oklab-gradient.html (实时测试) (来源)
- srgb-gradient.html (实时测试) (来源)
- srgb-linear-gradient.html (实时测试) (来源)
- xyz-gradient.html (实时测试) (来源)
- gradient-interpolation-method-valid.html (实时测试) (来源)
- gradient-interpolation-method-invalid.html (实时测试) (来源)
- gradient-interpolation-method-computed.html (实时测试) (来源)
如果宿主语法未定义应在什么色彩空间插值, 则默认为 Oklab。
但 用户代理 必须 处理旧版 sRGB 色彩格式之间的插值 (十六进制颜色、命名颜色、 rgb()、hsl() 或 hwb() 以及包括 alpha 的等价形式) 在伽玛编码的 sRGB 空间进行。 这样可确保 Web 兼容性; 旧版 sRGB 内容默认在 sRGB 空间内插值。
这也意味着作者可以选择 启用更优的插值效果, 即使是针对 sRGB 颜色, 只需对至少一个颜色使用非旧版 color(srgb r g b) 形式, 或明确指定 插值色彩空间。
如果待插值的颜色超出了 插值色彩空间 的色域, 那么转换到该空间后, 结果会包含超出范围的值。
这些值不会被裁剪,必须按原样进行插值。
12.2. 插值时的缺失组件
在将两个颜色转换为 插值颜色空间 的过程中,任何 缺失组件 都会被替换为值 0。
因此,插值两个颜色的第一步是对输入颜色中的任何 缺失组件 进行分类,并将其与 插值颜色空间 的组件进行比较。如果找到任何作为 缺失组件 的 类似组件,它们将被带入并在预乘和线性插值之前重新插入转换后的颜色中。
类似组件 如下:
| 类别 | 组件 |
|---|---|
| 红色 | r,x |
| 绿色 | g,y |
| 蓝色 | b,z |
| 亮度 | L |
| 色彩度 | C, S |
| 色相 | H |
| 对立 a | a |
| 对立 b | b |
| Alpha | alpha |
注意:对于此分类的目的,XYZ 空间被视为超饱和的 RGB 空间。此外,尽管饱和度依赖于亮度,但在这里它仍与色度归为同一类别。HWB 的白度和黑度在其他颜色空间中没有对应的类似组件。
lch ( 50 % 0.02 none) color ( display-p30.7 0.5 none)
转换结果为
oklch ( 56.897 % 0.0001 0 ) oklch ( 63.612 % 0.1522 78.748 )
在重新插入继承的 缺失分量 后, 实际插值的两种颜色为:
oklch ( 56.897 % 0.0001 none) oklch ( 63.612 % 0.1522 78.748 )
如果带有继承的 缺失分量 的颜色, 与另一种未缺失该分量的颜色插值, 缺失分量 视为具有 另一颜色的该分量值。
因此, 继承步骤 必须在进行 任何 无效分量处理之前完成。
oklch ( 78.3 % 0.108 326.5 ) oklch ( 39.2 % 0.4 none)
实际插值的颜色为
oklch ( 78.3 % 0.108 326.5 ) oklch ( 39.2 % 0.4 326.5 )
而不是
oklch ( 78.3 % 0.108 326.5 ) oklch ( 39.2 % 0.4 0 )
如果继承的 缺失分量 是透明度,则必须用继承值对颜色做预乘, 而不是使用颜色转换所得的零值。
oklch ( 0.783 0.108 326.5 /0.5 ) oklch ( 0.392 0.4 0 / none)
则实际插值的颜色为
oklch ( 78.3 % 0.108 326.5 /0.5 ) oklch ( 39.2 % 0.4 0 /0.5 )
对应的预乘 OkLCh 值为 [0.3915, 0.054, 326] 和 [0.196, 0.2, 0]。
如果两种颜色都缺失 某一分量, 那么插值结果 也会 缺失 该分量。
12.3. 带有 Alpha 的插值
当要插值的颜色不完全不透明时, 它们首先按如下方式进行预乘:
-
如果 alpha 值为 none,预乘值就是未预乘的值。否则,
-
如果任一组件值为 none,则预乘值也为 none。
-
对于直角坐标颜色系统,所有组件值都与 alpha 值相乘。
-
对于圆柱极坐标颜色坐标系,色相角不进行预乘,但其他两个轴会进行预乘。
要从预乘颜色值中获取颜色值,
为什么预乘 Alpha 有用?
使用预乘表示法插值颜色往往比非预乘表示法产生更具吸引力的过渡,尤其是在从完全不透明颜色过渡到完全透明时。
请注意,如果透明度或颜色保持不变(例如在 (不透明的红色)和
(不透明的蓝色),或
(不透明的红色)和
(透明的红色)之间进行过渡),则不论在预乘还是非预乘颜色空间中进行颜色插值,结果都是相同的。只有当两个端点之间的颜色和透明度都不同的时候,才会出现差异。
线性插值这些颜色的中点将是 [23.4% 10.2% 38.8%],使用 alpha 值 0.5,撤销预乘后的颜色为 rgb(46.8% 20.4% 77.6% / 0.5)。
线性插值的中点将是 [29.4365% 25.776 3.554],使用 alpha 值 0.5,撤销预乘后的颜色为 lab(58.873% 51.552 7.108 / 0.5)。
沿着 较短 色调弧(默认)进行线性插值的中点为 [29.4365% 40.563 31.82],使用 alpha 值 0.5,撤销预乘后的颜色为 lch(58.873% 81.126 31.82 / 0.5)。
有关 alpha 预乘和撤销预乘的示例 JavaScript 代码(适用于极坐标和直角坐标颜色空间),请参见 § 18 颜色转换示例代码。
12.4. 色调插值
对于具有色调角度的颜色函数(如 LCH、HSL、HWB 等),有多种插值方式。 由于大于 360° 的弧度通常不理想, 色调角度在插值之前会被调整 使得每个分量的插值小于 360°,通常小于 180°。
主语法可以指定以下任何一种算法用于色调插值 (以下角度单位为度,但无论如何指定,逻辑都是相同的)。 指定色调插值策略已是 <color-interpolation-method> 语法的一部分 通过 <hue-interpolation-method> 标记来完成。
除非另有说明,如果主语法未选择特定的色调插值算法,默认使用 较短 弧度。
注意: 请记住, 如果要插值的颜色尚未处于指定的插值颜色空间中, 那么将其转换会将任何无效分量变为缺失分量。
12.4.1. 较短
色调角度通过插值取起始和结束色调之间的较短弧。
角度调整使得 θ₂ - θ₁ ∈ [-180, 180]。伪 JavaScript 代码:
if( θ₂ - θ₁ >180 ) { θ₁ +=360 ; } else if( θ₂ - θ₁ <-180 ) { θ₂ +=360 ; }
12.4.2. 较长
色调角度通过插值取起始和结束色调之间的较长弧。
角度调整使得 θ₂ - θ₁ ∈ {(-360, -180], [180, 360)}。伪 JavaScript 代码:
if( 0 < θ₂ - θ₁ <180 ) { θ₁ +=360 ; } else if( -180 < θ₂ - θ₁ <=0 ) { θ₂ +=360 ; }
12.4.3. 递增
色调角度被插值为使其在从第一个颜色到第二个颜色的过程中, 始终保持递增。 如果角度增加到 360,则重置为零, 然后继续增加。
根据两个角度之间的差异, 这将看起来与较短或较长类似。但是,如果其中一个色调角度被动画化, 并且色调角度差异经过 180 度, 则插值不会翻转到另一弧。
但是,如果第二种颜色的色调被动画化为 oklch(0.7 0.1 230), 则插值的中点为 (30 + 230) * 0.5 = 130 度, 继续沿相同的递增方向, 得到另一种绿色 oklch(0.6 0.1 130) 而不是在动画的过程中翻转到对方颜色。
角度调整使得 θ₂ - θ₁ ∈ [0, 360)。伪 JavaScript 代码:
if( θ₂ < θ₁) { θ₂ +=360 ; }
12.4.4. 递减
色调角度被插值为使其在从第一个颜色到第二个颜色的过程中, 始终保持递减。 如果角度减小到 0,则重置为 360, 然后继续递减。
根据两个角度之间的差异, 这将看起来与较短或较长类似。但是,如果其中一个色调角度被动画化, 并且色调角度差异经过 180 度, 则插值不会翻转到另一弧。
但是,如果第二种颜色的色调被动画化为 oklch(0.7 0.1 230), 则插值的中点为 (30 + 360 + 230) * 0.5 = 310 度, 继续沿相同的递减方向, 得到另一种紫色 oklch(0.6 0.1 310) 而不是在动画的过程中翻转到对方颜色。
角度调整使得 θ₂ - θ₁ ∈ (-360, 0]。伪 JavaScript 代码:
if( θ₁ < θ₂) { θ₁ +=360 ; }
13. 色域映射
13.1. 色域映射简介
注意: 本节为文档其他部分 所述具体要求提供重要背景。
本节不具规范性
测试
本节不是规范要求,无需测试。
当一个原色空间的颜色 被转换到另一个色域更小的目标色空间时, 某些颜色值会超出目标色域。
对于中间色彩计算, 这些超出色域的值会被保留。 但如果目标是显示设备 (屏幕或打印机), 则必须把超出色域的值转换成 色域内的颜色。
色域映射就是在视觉效果尽量不显著变化的前提下, 找到一个色域内的颜色的过程。
有些超出色域的颜色对应真实世界的颜色 (理论上可物理呈现), 另一些则是虚拟色彩 (它们超出了光谱包络线, 需要超过 100% 的单一波长能量) 永远无法物理实现。 这种颜色通常由计算产生, 例如“令此颜色饱和度提高 100 倍”。
这四个角中有三个超出了光谱包络线, 对应虚拟色彩。
13.1.1. 裁剪
最简单但最不可取的方法 就是直接将分量值 剪裁到可显示范围。
由于这种方法的动力就是速度, 剪裁通常在伽玛编码值上完成, 而不是转换到线性光。
这会改变 三个基色(对 RGB 显示来说)的比例, 导致色相偏移。
color ( srgb-linear 0.5 1 3 ) 。
由于这是线性光色彩空间,
我们可以对比三个分量的强度,
得到
蓝光是绿光的三倍,
红光是绿光的一半。
蓝色基色是红色基色的六倍。
在 OkLCh 中,此色相角 265.1°
如果现在将此颜色
剪裁到 sRGB 色域,
得到 。
这时蓝光量与绿光一致。
在 OkLCh 中,该色相角 196.1°,
变化高达 69°。
如果颜色并非严重超出色域, 剪裁还能带来可接受的效果。 尤其是对较暗或为负的 分量值。
color ( rec2020 0.54 0.9 0 )
即 oklch ( 80.72 % 0.3296 141.6 ) 。
转换到 p3 色彩空间时,负值的蓝色分量表明
该颜色已经超出色域范围:
在线性光下为
。
对 gamma 编码的 p3 颜色做 gamut 剪裁得到
在线性光下为
对比得
。
这是个不错的结果; 色相角和明度几乎没变, 但色度有所降低,属于预期范围。
就线性光红绿蓝百分比而言, 红绿完全一样, 而蓝色高出 -1.46%。
color ( prophoto-rgb 0.2 1.0 0.1 )
即 oklch ( 85.07 % 0.4873 151.4 )
转换到 p3 色彩空间后,该颜色明显
超出色域:
在线性光下为
。
对 gamma 编码的 p3 颜色做 gamut 剪裁得到
在线性光下依然为
(分量值恰好为0或1时不受 gamma 影响)
对比得
。
视觉效果不如前例,但仍可接受。 色相影响略大,变化了 5.8°。
就线性光红绿蓝百分比而言, 红色高 57%,绿色低 6.7%,蓝色高 23%。
13.1.2. 最接近的颜色 (MINDE)
更好的方法是在一个感知均匀的颜色空间中通过找到最接近的在色域内的颜色进行映射 (所谓的最小 ΔE 或 MINDE)。 显然,这种技术的成功 取决于 色域映射颜色空间的均匀程度 以及所使用的 deltaE 函数的预测精度。
但是,在进行色域映射时, 色调的变化特别令人反感; 色度的变化更容易接受, 而 如果另一种选择是较大幅度的色度降低, 那么轻微的亮度变化也是可以接受的。 MINDE 对每个维度的变化赋予相同的权重, 因此产生次优的结果。
13.1.3. 色度减少
实现 MINDE 时, 颜色会在感知均匀的极坐标色彩空间中映射, 方法是保持色相不变, 并降低色度,直到颜色落入色域范围。
这可以算法化完成, 通过求解常亮、常色相射线 与色域边界的几何交点; 或采用迭代方式, 逐步减少色度直到落入色域。
注意: 为了性能考虑, 迭代通常采用二分查找。
color ( display-p3 1 1 0 ) )
要映射到 sRGB 显示器。
使用的色域映射空间为 OkLCh。
color ( display-p31 1 0 )
变为
color ( srgb1 1 -0.3463 )
即
color ( oklch0.96476 0.24503 110.23 )
通过逐步减少色度分量 直到结果颜色进入 sRGB 色域 (没有分量为负或大于一), 就得到了映射到色域内的颜色。
color ( oklch0.96476 0.21094 110.23 )
其对应
color ( srgb0.99116 0.99733 0.00001 )
13.1.4. 过度的色度减少
此外,这种简单的 MINDE 方法对于某些颜色会得到次优结果, 主要是非常浅亮的颜色, 如黄色和青色, 当色域边界的上沿非常浅或者略呈凹面时, 常亮射线可能刚好掠过色域边界, 导致色度异常低。
选用的色彩空间会影响色域映射颜色的可接受性。
color ( display-p3 1 1 0 )
在 CIE LCH 色彩空间不断降低色度。
color ( display-p3 1 1 0 )
在 OkLCh 色彩空间不断降低色度。
13.1.5. 带局部剪裁的色度减少
可以改进简单的色度减少算法: 在每一步中, 计算当前映射颜色和该颜色的剪裁版本之间的颜色差异。 如果当前颜色超出色域边界, 但它与剪裁版本之间的颜色差异 低于刚好可见差异(JND)的阈值, 则返回该颜色的剪裁版本作为映射结果。 实际上,这在每个阶段都在进行 MINDE 映射, 但受限于色调和亮度变化非常小, 因此不明显。
color ( display-p3 1 1 0 )
在 CIE LCH 颜色空间中逐步减少色度,
并使用了局部剪裁修改。
color ( display-p3 1 1 0 )
的色度逐渐降低,但这次是在 OKLCh 色彩空间中
并使用局部裁剪修改。
13.1.6. 偏离感知均匀性:色相曲率
即使使用 deltaE2000 距离度量, 在 CIE LCH 色彩空间进行色域映射, 已知会产生次优结果, 对于色相在 270° 到 330° 范围的颜色, 会出现明显的色相漂移。
采用 OkLCh 色彩空间 和 deltaEOK 距离度量 可以避免此问题, 在所有色相角度下都有效。
13.2. CSS 色域映射到 RGB 目标
测试
颜色的实际值不会暴露给脚本,因此难以自动化测试。
这三种CSS 色域映射算法 适用于单独的标准动态范围(SDR)CSS 颜色, 当其超出 RGB 显示器的色域时, 需要进行CSS 色域映射。
实现可以根据性能和质量的权衡, 选择三种算法中的任意一种, 并且必须在 CSS 要求色域映射时使用选定算法。
它们都采用了相对比色渲染意图, 因此目标色域内的颜色不变。
注: 其它情况, 特别是映射到最大黑值显著高于零的打印机色域时, 需要用不同的算法, 使黑点和白点对齐, 这会导致极浅或极深颜色在降低色度时亮度发生变化。
注: 这些算法适用于单独的、独立的颜色; 对于色彩图像, 当相邻像素关系很重要,且需要保留细节和纹理时, 更适合使用感知渲染意图, 在那种情况下,色域内的颜色也可能会变化。
三种 CSS 色域映射算法的目标都是 在OkLCh 色彩空间中 恒亮度、恒色相地降低色度。
对于亮度超出范围的颜色, 若亮度大于等于 1.0,则目标色空间返回白色, 若亮度小于等于 0.0,则目标色空间返回黑色。
13.2.1. 二分查找色域映射(Local MINDE)
该二分查找算法 使用的颜色差公式为deltaEOK。 采用local-MINDE改进。 在每一步搜索中, 都计算当前映射颜色与其裁剪版本的 deltaEOK。
如果当前颜色在色域边界外, 但与裁剪版本的 deltaEOK 低于“刚刚可觉察差异”(JND)阈值, 则返回裁剪颜色作为映射结果。 这样可以获得良好的效果且几乎没有色相漂移, 避免了在凹形色域表面附近过度色度降低, 但计算量可能较大。
对 OkLCh 色彩空间, 一个 JND 代表 0.02 的 OkLCh 差值。
注: 在 CIE Lab 色彩空间, 亮度范围 0 到 100, 并用 deltaE2000 时, 一个 JND 是 2。 因为 Oklab 和 OkLCh 的亮度是 0 到 1, 用 deltaEOK 时, 一个 JND 小 100 倍。
注: 为方便实验和对比, 二分查找(Local MINDE)算法已在 Coloraide(Python)[Coloraide-MINDE] 与 color.js(JavaScript)[colorjs-MINDE]实现。
13.2.2. 二分查找色域映射(Local MINDE)伪代码示例
- 如果destination没有色域限制(XYZ-D65、XYZ-D50、Lab、LCH、Oklab、OkLCh),直接将 origin转换为destination并返回,作为色域映射后的颜色
- 令origin_OkLCh为origin从origin color space转换到OkLCh颜色空间的结果
- 如果origin_OkLCh的亮度大于等于100%, 则将`oklab(1 0 0 / origin.alpha)`转换为destination,并返回作为色域映射后的颜色
- 如果origin_OkLCh的亮度小于等于0%, 则将`oklab(0 0 0 / origin.alpha)`转换为destination,并返回作为色域映射后的颜色
- 令 inGamut(color) 为一个函数,判断传入颜色是否在 destination色域内。 对于HSL和HWB,如果该颜色在sRGB色域内则返回true。
- 如果 inGamut(origin_OkLCh) 为true,直接将origin_OkLCh 转换为destination并返回,作为色域映射后的颜色
- 否则,令 delta(one, two) 为一个函数,计算两颜色的deltaEOK差异
- 令 JND 为0.02
- 令 epsilon 为0.0001
- 令 clip(color) 为一个函数,将color转换为destination, 将每个分量钳制到其参考范围内,并返回结果
- 令 current 为 origin_OkLCh
- 令 clipped 为 clip(current)
- 令 E 为 delta(clipped, current)
-
如果 E < JND
- 返回 clipped 作为色域映射后的颜色
- 令 min 为零
- 令 max 为 origin_OkLCh 的OkLCh色度
- 令 min_inGamut 为布尔值,表示min当前是否在色域内,初始设为true
-
当 (max - min 大于 epsilon) 时,重复以下步骤
- 令 chroma = (min + max) /2
- 将current的色度分量设为chroma
- 如果 min_inGamut 为 true 且 inGamut(current) 也为 true,则 把min设为chroma,继续重复这些步骤
-
否则,执行以下步骤:
- 令 clipped 为 clip(current)
- 令 E 为 delta(clipped, current)
-
如果 E < JND
- 如果 (JND - E < epsilon),则返回 clipped 作为色域映射后的颜色
-
否则,
- 将min_inGamut设为false
- 将min设为chroma
- 否则,将max设为chroma,继续重复这些步骤
- 返回 clipped 作为色域映射后的颜色
13.2.3. EdgeSeeker色域映射
EdgeSeeker算法是一种基于几何与查找表的色域映射方法, 最初由Alexey Ardov为color.js库开发 [colorjs-EdgeSeeker]。
对于任意给定的色相,色域边界切片 由上方的曲线段和下方的线性段组成, 在该色相的最大色度点处连接。
初始化本算法时, 针对目标RGB空间, 构建一个查找表(LUT), 包含每个色相切片上的最大色度OkLCh颜色。 对实际映射颜色的色相,使用查找表中最近值做线性插值, 估算其对应的最大色度值。
随后计算常亮射线与色域边界的交点, 对于边界下部(线性段)非常快, 上部(曲线段)效率也很高。
这种方法效果理想,但查找表(LUT)会占用更多内存。
13.2.4. EdgeSeeker色域映射伪代码示例
13.2.5. Ray Trace色域映射
Ray Trace算法是一种基于几何的RGB色域映射方法, 可实现快速常亮色度压缩。 它最初由Isaac Muse为Coloraide Python库开发 [Coloraide-Ray-Trace]。
要进行映射的颜色首先会被转换为Oklch, 然后生成该颜色的无彩色对应版本,作为中性轴锚点。 这两个颜色接着会被转换为目标RGB空间的线性光形式。
由于此时色域边界为坐标轴对齐的立方体, 求交点运算更迅速。
从RGB立方体内部,沿锚点与当前颜色的连线发射射线, 交点即为第一次色域映射的近似值。
由于RGB空间的感知均匀性较差, 实际等色相、等亮度的射线在RGB空间为曲线轨迹。
第一次近似结果会被转换回Oklch, 并投影到色度压缩曲线上以修正色相与亮度, 得到新的当前颜色,更接近压缩色度的理想点。
此过程最多再迭代三次, 每次都能使结果逼近该曲线上的最佳位置。 最后一步通过简单的钳制以处理浮点误差。
该方法效果可与低JND的二分查找局部MINDE媲美, 但速度更快、耗时更为稳定。
图片版权归Isaac Muse所有。
注:为便于实验和实现对比, Ray Trace算法可在Coloraide库(Python实现) [Coloraide-Ray-Trace] 及color.js库(JavaScript实现)[colorjs-RayTrace]中获取。
13.2.6. Ray Trace色域映射伪代码示例
- 如果destination没有色域限制(XYZ-D65、XYZ-D50、Lab、LCH、Oklab、OkLCh),则直接将 origin转换为destination并返回作为色域映射后的颜色
- 令origin_OkLCh为origin 从origin color space转换为OkLCh颜色空间的结果
- 若origin_OkLCh的亮度大于等于100%, 将`oklab(1 0 0 / origin.alpha)`转换为destination并返回
- 若origin_OkLCh的亮度小于等于0%, 将`oklab(0 0 0 / origin.alpha)`转换为destination并返回
- 令l_origin为origin_OkLCh的OkLCh亮度分量
- 令h_origin为origin_OkLCh的OkLCh色相分量
- 令anchor为一个无色度OkLCh颜色,取 l_origin作为亮度,0为色度,h_origin为色相, 并转为线性光destination
- 令origin_rgb为origin_OkLCh 转为线性光destination
-
若origin_rgb不在色域内
- 令low为 0.0 + 1E-6 1
- 令high为 1.0 - 1E-6 2
- 令last为origin_rgb
-
循环 (i=0; i<4; i++)
-
如果 (i > 0)
- 令current_OkLCh为origin_rgb转为OkLCh
- 令current_OkLCh亮度为l_origin
- 令current_OkLCh色相为h_origin 3
- 令origin_rgb为current_OkLCh 转为线性光destination
- 投射射线,起点为anchor,终点为origin_rgb, 得到射线与色域边界的交点intersection
- 如未找到交点, 令origin_rgb为last并退出循环 5
- 若 (i >0) 且 (origin_rgb每个分量都在low至high之间), 则令anchor为origin_rgb 4
- 令origin_rgb为intersection
- 令last为intersection
-
如果 (i > 0)
- 令clip(color)为一个函数,将color转为destination, 再将每分量钳制到参考范围,并返回
- 令clipped为clip(current)
- 返回clipped作为色域映射后的颜色
- 令bmin和bmax为 分别指定色域下界与上界的三个分量数组 6
- 令tfar为无穷(或非常大的数)
- 令tnear为负无穷(或非常小的负数)
- 令direction为三个分量的数组
-
循环 (i = 0; i < 3; i++):
- 令a为start [i]
- 令b为end [i]
- 令d为b-a
- 令direction [i]为d
-
如果 abs(d) < 1E-12
- 令inv_d为1/d
- 令t1 = (bmin [i] - a) * inv_d
- 令t2 = (bmax [i] - a) * inv_d
- 令tnear为max(min(t1, t2), tnear)
- 令tfar为min(max(t1, t2), tfar)
-
否则,如果(a < bmin[i] 或 a >
bmax[i])
- 返回未找到交点
-
如果 (tnear > tfar 或 tfar < 0)
- 返回未找到交点
-
如果 tnear < 0
- 令tnear为tfar 7
-
如果 tnear为无穷大(或等于初始大数)
- 返回未找到交点
-
循环 (i =0; i < 3; i++):
- 令result [i]为start [i] + direction [i] * tnear
- 返回result
13.2.6.1. Ray Trace算法脚注
14. 解析 <color> 值
除非为特定属性另有规定,指定的颜色将解析为 计算颜色,然后进一步解析为 使用颜色,如下所述。
测试
14.1. 解析 sRGB 值
这适用于:
-
hwb() 数值
它 不 适用于:
-
color() 数值,使用 srgb 或 srgb-linear 颜色空间。
如果 sRGB 颜色被作者作为命名颜色, 或作为系统颜色明确指定, 声明值就是该命名或者系统颜色,并转换为 ASCII 小写。 计算值和使用值 是对应的 sRGB 颜色, 以及指定的 alpha 分量 (在限定为 [0, 1] 后), 未指定时默认为不透明。
否则,声明值、计算值和使用值 是对应的 sRGB 颜色, 以及指定的 alpha 分量 (在限定为 [0, 1] 后), 未指定时默认为不透明。
出于历史原因,当 sRGB 颜色中的 calc() 计算结果为单一数值时, 声明值的串行化不带 “calc( )” 包裹。
同样出于历史原因, 当 calc() 简化为单一数值时, 颜色值会被截断到 [0.0, 255.0] 区间。
这种截断也会处理如 Infinity、-Infinity 及 NaN 此类值,分别会被截断到 255、0 和 0。
测试
14.2. 解析 Lab 和 LCH 值
声明值、计算值和使用值 是相应的 CIE Lab 或 LCH 颜色 (在限制 L、C 和 H 后) 与指定的 alpha 分量配对 (作为 <number>,而非 <percentage>; 如果未指定则默认为不透明)。
虽然 a、b 和 C 的数值 理论上没有上限, 但对于趋于无穷大的数值, 实现上可能会有 实现自定义的极限。
14.3. 解析 Oklab 和 OkLCh 数值
声明值、计算值和使用值 为对应的 Oklab 或 OkLCh 颜色 (L、C、H 分量已经裁剪后) 以及指定的 alpha 分量 (为<number> ——不是<percentage>; 未指定时 alpha 默认为不透明)。
虽然 a、b 和 C 的取值理论上无限制, 但对于趋近无穷大的数值, 实现上可能有实现自定义的极限。
14.4. 解析 color() 函数的值
声明值、计算值和使用值 是指定色彩空间中的颜色, 与指定的 alpha 分量配对 (作为 <number>,而非 <percentage>; 如果未指定则默认为不透明)。
对于在 xyz 颜色空间 中指定的颜色, 这是 xyz-d65 颜色空间 的别名, 计算值和使用值 采用 xyz-d65 颜色空间。
虽然 r、g、b、x、y 和 z 的数值 理论上没有上限, 但对于趋近无穷大的数值, 实现上可能会有 实现自定义的极限。
14.5. 解析其他颜色
这适用于系统颜色(包括 <deprecated-color>),transparent, 和 currentcolor。
每个 <system-color> 关键字 和 <deprecated-color> 关键字 的声明值是其自身。 计算值 是其色彩空间中的相应颜色。 然而,这类颜色不得被 "强制颜色模式"改变。
< button style = "color: ButtonText; background: ButtonFace" ></ button >
color 属性的声明值是 "ButtonText", 而计算值可能是,例如, rgb(0, 0, 0)。
transparent 的声明值是 "transparent", 而计算值和使用值是透明黑色。
currentcolor 关键字计算为其自身。
在 color 属性中, currentcolor 的使用值是 已解析的继承值。 在任何其他属性中, 其使用值是同一元素上 color 属性的使用值。
注意:这意味着如果 currentcolor 值被继承, 它是作为关键字被继承的, 而不是作为 color 属性的值, 所以后代元素将使用它们自己的 color 属性 来解析它。
< div > < p > 假设这个示例文本足够长,可以在多行中换行。</ p > </ div >
和以下 CSS:
div{ color : forestgreen; text-shadow : currentColor; } p{ color : mediumseagreen; } p::firstline{ color : yellowgreen; }
继承的 text-shadow 属性在第一行片段上的使用值将是 yellowgreen。
测试
15. 序列化<color> 值
本节更新并替换了 CSS 对象模型中关于序列化 CSS 值部分中与序列化 <color> 值相关的内容。
在本节中,规范中使用的字符串及其对应的字符如下。
| 字符串 | 字符 |
|---|---|
| " " | U+0020 空格 |
| "#" | U+0023 数字符号 |
| "," | U+002C 逗号 |
| "-" | U+002D 连字符 |
| "." | U+002E 句号 |
| "/" | U+002F 斜线 |
| "none" | U+006E 小写字母 n U+006F 小写字母 o U+006E 小写字母 n U+0065 小写字母 e |
字符串 "." 应作为小数点分隔符使用,无论地区如何,且不应有千位分隔符。
对于支持缺少的颜色组件的语法形式, 值 none(等同于 NONE,nOnE 等)应以全小写的字符串“none”进行序列化。
15.1. 序列化 alpha 值
这适用于任何可以接受可选 alpha 值的<color>值。 这不适用于 opacity 属性。
如果在被限制到范围 [0, 1] 后,alpha 为 1,则在序列化中省略它;默认值为 1(完全不透明)。
如果 alpha 的值为 1 以外的任何值,则按照下面描述显式包含在序列化中。
如果值内部表示为 0 到 255 之间的整数(即 8 位无符号整数),请按以下步骤操作:
- 设 alpha 为给定的整数。
- 如果存在一个 0 到 100 之间的整数,当它乘以 2.55 并四舍五入到最接近的整数(如果两个值同等接近则向上取整)时等于 alpha,则设 rounded 为该整数除以 100。
- 否则,将 rounded 设为 alpha 除以 0.255 并四舍五入到最接近的整数(如果两个值同等接近则向上取整),再除以 1000。
- 将 rounded 序列化为<number> 的结果返回。
否则,返回给定值的序列化结果(作为 <number>,而不是 <percentage>)。
例如,如果 alpha 存储为 8 位无符号整数 237,整数 93 满足条件,因为 Math.round(93 * 2.55) 等于 237,因此 alpha 序列化为“0.93”。
但是,如果 alpha 存储为 8 位无符号整数 236,则不存在这样的整数(92 映射到 235,而 94 映射到 240),因此 236 ÷ 0.255 = 925.490196078,alpha 序列化为“0.92549”(不超过 6 位数字,去除尾随零)。
<number> 值以十进制表示,使用 "." 字符作为小数点分隔符。不得省略前导零,尾随零必须省略。
alpha 值保留的精度,以及序列化值中的小数位数,本规范中未定义,但必须至少足以进行整数百分比值的往返。因此,序列化值必须至少包含两位小数(除非已去除尾随零)。值必须向 +∞ 取整,而非截断。
例如,alpha 值为 12.3456789% 时,可以序列化为“0.12”或“0.123”或“0.1234”或“0.12346”(向 +∞ 取整,因为后续数字是 6)或任何相同形式的更长四舍五入序列化。
由于在解析时会对超出有效范围的 <alpha-value> 进行限制, 因此声明值将被限制。 然而,根据 CSS 值 4 § 10.12 范围检查,使用 calc() 指定的 <alpha-value> 在序列化指定形式时不会被限制; 但计算值会被限制。
15.2. 序列化 sRGB 值
以下 sRGB 值的序列化形式:
派生自声明值。
当序列化由作者设置为 CSS 命名颜色、 系统颜色、 已弃用颜色 或 transparent 的属性值时,因此对于声明值, 会保留 ASCII 小写关键字值。 对于计算值和使用值, 使用相应的 sRGB 值。
因此,transparent 的序列化声明值是字符串 "transparent", 而 transparent 的序列化计算值是字符串 "rgba(0, 0, 0, 0)"。
对于所有其他 sRGB 值, 声明值、计算值和使用值 是相应的 sRGB 值。
在序列化期间, 任何缺失值 都会转换为 0。
15.2.1. sRGB 值的 HTML 兼容序列化
如果以下所有条件都为真:
- 色彩空间为 sRGB
- alpha 值为 1
- RGB 分量值在内部表示为 0 到 255(含)之间的整数(即 8 位无符号整数)
- 请求 HTML 兼容序列化
那么相应的 sRGB 值将按如下方式序列化为 6 位十六进制颜色表示法:
一个由七个字符组成的字符串,包含字符“#”,紧随其后的是红色分量、绿色分量和蓝色分量的两位十六进制表示,顺序如此,使用 ASCII 小写十六进制数字。不允许有空格。
context. fillStyle= "rgb(255, 0, 255)" console. log( context. fillStyle); // "#ff00ff"
色彩空间为 sRGB,表示为每个分量 8 位, 数据格式不会产生 none 值,也不支持扩展范围的数值, alpha 为 1。
兼容 HTML 的序列化结果为字符串 "#ff00ff"(不是 "#FF00FF")。
否则,对于 sRGB 使用 sRGB 数值的 CSS 序列化, 其他色彩空间使用对应的序列化方式和 <color> 值。
context. fillStyle= "lab(29% 39 20)" ; console. log( context. fillStyle); // "lab(29 39 20)"
CSS 序列化结果为字符串 "lab(29 39 20)"。
context. fillStyle= "#ff00ffed" ; console. log( context. fillStyle); // "rgba(255, 0, 255, 0.93)"
alpha 不等于 1,因此 CSS 序列化结果为字符串 "rgba(255, 0, 255, 0.93)"。
15.2.2. sRGB 值的 CSS 序列化
对应的 sRGB 数值使用 rgb() 或 rgba() 形式 (取决于(裁剪后的)alpha 是否正好为 1), 函数名必须全部为 ASCII 小写 字母。
为兼容性,sRGB 分量值以 <number> 形式序列化,而不是 <percentage>。 同样为兼容性, 分量值以十进制序列化, 范围为 [0-255],不论实际存储的位深度是多少。
如前所述, 单位 alpha 不会被明确序列化。 另外,为兼容性,如果 alpha 正好为 1, 使用 rgb() 形式, alpha 隐含; 否则,使用 rgba() 形式, alpha 值将被明确写出。
为兼容性, 采用传统的以逗号分隔的写法; 每个逗号后紧跟一个 ASCII 空格。 这也适用于 rgba() 的蓝色分量和 alpha 值之间用逗号(不是斜杠)分隔。
hwb ( 740 deg 20 % 30 % /50 % )
首先会被归一化为
hwb ( 20 20 % 30 % /50 % )
然后被转换为 sRGB 并序列化为
rgba ( 178.5 , 93.5 , 51 , 0.5 )
返回结果的小数精度 参见下文。
注: 与 CSS Color 3 不同, rgb() 函数的参数类型 是 <number>, 而不是 <integer>。 因此如果高于八位精度, 会带有小数部分表示。
sRGB 分量的保留精度, 以及序列化值中的有效数字位数, 本规范未明确定义, 但至少要保证 能够不失真地还原八位数值(round-trip)。 数值必须向 +∞ 舍入, 不允许直接截断。
注: 脚本作者若期望 getComputedStyle 返回的颜色值组件类型为 <integer>, 应升级以支持 <number> 类型。
例如:
rgb ( 146.064 107.457 131.223 )
现在是有效写法,且等价于
rgb ( 57.28 % 42.14 % 51.46 % )
符合作规范的序列化表现形式是 "rgb(146.06, 107.46, 131.2)"。
任一分量值的小数位若全为零必须省略; 若只有小数点且无非零数字,小数点也应省略。 这意味着以整数分量指定的 sRGB 颜色 序列化时会保留向后兼容的整数形式。
15.3. 序列化 Lab 和 LCH 值
lch() 和 lab() 值的序列化形式 派生自计算值,并使用 lab() 或 lch() 形式, 函数名称使用ASCII 小写字母。
分量值以十进制序列化; L、a、b 和 C 分量值 序列化为 <number>, 酌情使用 Lab 百分比参考范围或 LCH 百分比参考范围 执行百分比到数字的转换; 因此 0% L 映射到 0, 100% L 映射到 100。 必须使用单个 ASCII 空格字符 " " 作为分量值之间的分隔符。
任何组件值中的尾随小数部分零必须省略;如果小数部分全为零,小数点也必须省略。
保留 lab() 组件值的精度,即序列化值中的有效数字位数,本规范未定义,但由于广色域,必须足够以进行 0 到 100 之间的 L 值以及 ±127 之间的 a 和 b 值的往返操作,至少需要 16 位精度;这将导致至少有三位小数,除非尾随零已被省略。(建议内部存储为半浮点数或浮点数)。值必须 向 +∞ 取整,而非截断。
注意: 超宽色域空间中的 a 和 b 值可以超出 ±125。例如,所有的 prophoto-rgb 主色和次色都超过了此范围,但在 ±200 之内。
如前所述,单位 alpha 值不会显式序列化。非单位 alpha 值必须显式序列化,并且字符串 " / "(一个 ASCII 空格,然后斜杠,然后另一个空格)必须用于将 b 组件值与 alpha 值分隔开。
以下值的序列化形式为:
lch ( 56.2 % 83.6 357.4 /93 % )
字符串 "lch(56.2 83.6 357.4 / 0.93)",而不是 "lch(56.2% 83.6 357.4 / 0.93)"
15.4. 序列化 Oklab 和 OKLCh 值
oklch() 和 oklab() 值的序列化形式 派生自计算值,并使用 oklab() 或 oklch() 形式, 函数名称使用ASCII 小写字母。
分量值以十进制序列化; L、a、b 和 C 分量值 序列化为 <number>, 酌情使用 Oklab 百分比参考范围或 OKLCh 百分比参考范围 执行百分比到数字的转换; 因此 0% L 映射到 0, 100% L 映射到 1.0。 必须使用单个 ASCII 空格字符 " " 作为分量值之间的分隔符。
以下值的序列化形式为:
oklab ( 54.0 % -0.10 -0.02 )
字符串 "oklab(0.54 -0.1 -0.02)",而不是 "oklab(54 -0.1 -0.02)" 或 "oklab(54% -0.1 -0.02)"
任何组件值中的尾随小数部分零必须省略;如果小数部分全为零,小数点也必须省略。
以下值的序列化形式为:
oklch ( 56.43 % 0.0900 123.40 )
字符串 "oklch(0.5643 0.09 123.4)",而不是 "oklch(0.5643 0.0900 123.40)"。
保留 oklab() 组件值的精度,即序列化值中的有效数字位数,本规范未定义,但由于广色域,必须足够以进行 0 到 1(0% 到 100%)之间的 L 值,以及 ±0.5 之间的 a、b 和 C 值的往返操作,至少需要 16 位精度;这将导致至少有五位小数,除非尾随零已被省略。(建议内部存储为半浮点数或浮点数)。值必须 向 +∞ 取整,而非截断。
注意: 超宽色域空间中的 a、b 和 C 值可以超出 ±0.5。例如,prophoto-rgb 的绿色和蓝色主色的 C 值分别为 0.526 和 1.413,超出了该范围。
如前所述,单位 alpha 值不会显式序列化。非单位 alpha 值必须显式序列化,并且字符串 " / "(一个 ASCII 空格,然后斜杠,然后另一个空格)必须用于将最终的颜色组件值(b 或 C)与 alpha 值分隔开。
15.5. 序列化 color() 函数的值
color() 值的序列化形式来源于 计算值,并使用 color() 形式,函数名和色彩空间名中的字母使用 ASCII 小写。
组件值以十进制形式序列化,作为 <number>。各组件值之间,以及色彩空间名和第一个颜色组件之间,必须使用单个 ASCII 空格字符 " " 作为分隔符。
以下值的序列化形式为:
color ( dIsPlAy-P30.964 0.763 0.787 )
字符串 "color(display-p3 0.96 0.76 0.79)",如果保留两位小数。注意 0.787 四舍五入为 0.79,而不是截断到 0.78。
任何组件值中的尾随小数部分零必须省略;如果小数部分全为零,小数点也必须省略。
以下值的序列化形式为:
color ( rec20200.400 0.660 0.340 )
字符串 "color(rec2020 0.4 0.66 0.34)",而不是 "color(rec2020 0.400 0.660 0.340)"。
如果色彩空间为 sRGB,则在序列化结果中仍需显式指定色彩空间。
对于预定义的色彩空间,往返所需的最低精度如下:
| 色彩空间 | 最小位数 |
|---|---|
| srgb | 10 |
| srgb-linear | 12 |
| display-p3 | 10 |
| display-p3-linear | 12 |
| a98-rgb | 10 |
| prophoto-rgb | 12 |
| rec2020 | 12 |
| xyz,xyz-d50,xyz-d65 | 16 |
(内部存储建议每个分量用16位、半精度或浮点)。 数值必须向 +∞ 舍入, 不允许截断。
注意: 与传统写法如 rgb()、 hsl() 等相比, color(srgb) 要求更高的最小精度。 偏好高精度的样式表作者建议优先使用 color(srgb) 形式。
如前所述, 单位 alpha 不应显式序列化。 非单位 alpha 必须显式序列化, 且要用字符串 " / " (ASCII 空格、斜杠、空格) 分隔最后一个色彩分量和 alpha 值。
下列值的序列化结果为
color ( prophoto-rgb0.2804 0.40283 0.42259 /85 % )
如果保留三位小数,将是字符串 "color(prophoto-rgb 0.28 0.403 0.423 / 0.85)"。
15.6. 序列化其他颜色
这适用于 currentcolor。
该值的序列化形式来源于 计算值,并且颜色名称中的字母使用 ASCII 小写。
currentColor 的序列化形式为字符串 "currentcolor"。
16. 序列化 <opacity-value>
本规则适用于 opacity 属性。
如果指定的不透明度值 与字面 <percentage-token> 匹配(即未使用 calc()), 则应将其序列化为等价的 <number>(0% 对应 0,100% 对应 1)值。 否则,不透明度的指定值 应按语法的标准序列化方式序列化。
这种 <number> 值用十进制表示, 小数点用 “.” 。 不可省略前导零。 必须省略末尾零。
超出 [0,1] 区间的不透明度值 保留原样,不进行截断,在序列化的指定值中体现。
不透明度值的保留精度, 以及序列化时的小数位数, 本规范未明确定义, 但至少要足以 完整还原为整数百分比值。 因此,序列化值必须至少包含 两位小数(除非末尾零已去除)。 数值必须 向 +∞ 舍入,不能直接截断。
17. 默认样式规则
以下样式表是说明性的,而非规范性的。此样式表可作为实现 HTML 文档默认样式的一部分。
/* 桌面用户代理的传统超链接颜色 */ :link{ color : LinkText; } :visited{ color : VisitedText; } :active{ color : ActiveText; }
18. 颜色转换的示例代码
本节不是规范性的。
测试
本节不是规范性的,因此不需要测试。
为了更清晰地表达,使用了一个库进行矩阵乘法。(这比内联所有的乘法和加法更易读)。矩阵采用列主序排列。
// 颜色转换示例代码 // 转换也可以使用 ICC 配置文件和色彩管理系统完成 // 为简明起见,矩阵乘法调用了库(multiply-matrices.js) // 标准白点,用四位 CIE x,y 色度定义 const D50= [ 0.3457 / 0.3585 , 1.00000 , ( 1.0 - 0.3457 - 0.3585 ) / 0.3585 ]; const D65= [ 0.3127 / 0.3290 , 1.00000 , ( 1.0 - 0.3127 - 0.3290 ) / 0.3290 ]; // sRGB 相关函数 function lin_sRGB( RGB) { // 将 sRGB 数值数组转换为线性光(未压缩)形式 // 色域内的取值范围为 [0 - 1] // https://en.wikipedia.org/wiki/SRGB // 拓展传递函数: // 对负值,线性部分沿轴对称延拓, // 然后使用对称的幂函数。 return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); if ( abs<= 0.04045 ) { return val/ 12.92 ; } return sign* ( Math. pow(( abs+ 0.055 ) / 1.055 , 2.4 )); }); } function gam_sRGB( RGB) { // 将线性光 sRGB 数组(范围 0.0-1.0)转换为伽马校正形式 // https://en.wikipedia.org/wiki/SRGB // 拓展传递函数: // 对负值,线性部分沿轴对称延拓, // 然后在该阈值以下使用对称幂函数。 return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); if ( abs> 0.0031308 ) { return sign* ( 1.055 * Math. pow( abs, 1 / 2.4 ) - 0.055 ); } return 12.92 * val; }); } function lin_sRGB_to_XYZ( rgb) { // 将线性光 sRGB 数组转换为 CIE XYZ // 使用 sRGB 自身的白点 D65(不做色度适应) var M= [ [ 506752 / 1228815 , 87881 / 245763 , 12673 / 70218 ], [ 87098 / 409605 , 175762 / 245763 , 12673 / 175545 ], [ 7918 / 409605 , 87881 / 737289 , 1001167 / 1053270 ], ]; >return multiplyMatrices( M, rgb); } function XYZ_to_lin_sRGB( XYZ) { // 将 XYZ 转换为线性光 sRGB var M= [ [ 12831 / 3959 , - 329 / 214 , - 1974 / 3959 ], [ - 851781 / 878810 , 1648619 / 878810 , 36519 / 878810 ], [ 705 / 12673 , - 2585 / 12673 , 705 / 667 ], ]; return multiplyMatrices( M, XYZ); } // display-p3 相关函数 function lin_P3( RGB) { // 将 display-p3 RGB 数组(范围 0.0 - 1.0)转换为线性光形式 return lin_sRGB( RGB); // 与 sRGB 相同 } function gam_P3( RGB) { // 将线性光 display-p3 RGB 数组(范围 0.0-1.0)转换为伽马校正形式 return gam_sRGB( RGB); // 与 sRGB 相同 } function lin_P3_to_XYZ( rgb) { // 将线性光 display-p3 值转换为 CIE XYZ // 使用 D65(不做色度适应) // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html var M= [ [ 608311 / 1250200 , 189793 / 714400 , 198249 / 1000160 ], [ 35783 / 156275 , 247089 / 357200 , 198249 / 2500400 ], [ 0 / 1 , 32229 / 714400 , 5220557 / 5000800 ], ]; return multiplyMatrices( M, rgb); } function XYZ_to_lin_P3( XYZ) { // 将 XYZ 转换为线性光 P3 var M= [ [ 446124 / 178915 , - 333277 / 357830 , - 72051 / 178915 ], [ - 14852 / 17905 , 63121 / 35810 , 423 / 17905 ], [ 11844 / 330415 , - 50337 / 660830 , 316169 / 330415 ], ]; return multiplyMatrices( M, XYZ); } // prophoto-rgb 函数 function lin_ProPhoto( RGB) { // 将 prophoto-rgb 数组转换为线性光(未压缩)形式 // 色域内颜色的取值范围为 [0.0 - 1.0] // 传递曲线为 gamma 1.8,包含小的线性段 // 拓展传递函数 const Et2= 16 / 512 ; return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); if ( abs<= Et2) { return val/ 16 ; } return sign* Math. pow( abs, 1.8 ); }); } function gam_ProPhoto( RGB) { // 将线性光 prophoto-rgb 数组(范围 0.0-1.0)转换为伽马校正形式 // 传递曲线为 gamma 1.8,包含小的线性段 // TODO: 对负值,沿轴反射延拓线性段,然后加上幂函数 const Et= 1 / 512 ; return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); if ( abs>= Et) { return sign* Math. pow( abs, 1 / 1.8 ); } return 16 * val; }); } function lin_ProPhoto_to_XYZ( rgb) { // 将线性光 prophoto-rgb 值转换为 CIE D50 XYZ // 矩阵不能用有理数形式表示,但按 64 位精度计算 // 参见 https://github.com/w3c/csswg-drafts/issues/7675 var M= [ [ 0.79776664490064230 , 0.13518129740053308 , 0.03134773412839220 ], [ 0.28807482881940130 , 0.71183523424187300 , 0.00008993693872564 ], [ 0.00000000000000000 , 0.00000000000000000 , 0.82510460251046020 ] ]; return multiplyMatrices( M, rgb); } function XYZ_to_lin_ProPhoto( XYZ) { // 将 D50 XYZ 转换为线性光 prophoto-rgb var M= [ [ 1.34578688164715830 , - 0.25557208737979464 , - 0.05110186497554526 ], [ - 0.54463070512490190 , 1.50824774284514680 , 0.02052744743642139 ], [ 0.00000000000000000 , 0.00000000000000000 , 1.21196754563894520 ] ]; return multiplyMatrices( M, XYZ); } // a98-rgb 相关函数 function lin_a98rgb( RGB) { // 将 a98-rgb 数组(范围 0.0 - 1.0)转换为线性光形式 // 现在也接受负值 return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); return sign* Math. pow( abs, 563 / 256 ); }); } function gam_a98rgb( RGB) { // 将线性光 a98-rgb 数组(范围 0.0-1.0)转换为伽马校正形式 // 也接受负值 return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); return sign* Math. pow( abs, 256 / 563 ); }); } function lin_a98rgb_to_XYZ( rgb) { // 将线性光 a98-rgb 转换为 CIE XYZ // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html // 比 Adobe RGB 1998 文档第4.3.5.3节具有更高的数值精度 // 以下值由 R G B W 的色度坐标从头推导计算得出 // 参见 matrixmaker.html var M= [ [ 573536 / 994567 , 263643 / 1420810 , 187206 / 994567 ], [ 591459 / 1989134 , 6239551 / 9945670 , 374412 / 4972835 ], [ 53769 / 1989134 , 351524 / 4972835 , 4929758 / 4972835 ], ]; return multiplyMatrices( M, rgb); } function XYZ_to_lin_a98rgb( XYZ) { // 将 XYZ 转换为线性光 a98-rgb var M= [ [ 1829569 / 896150 , - 506331 / 896150 , - 308931 / 896150 ], [ - 851781 / 878810 , 1648619 / 878810 , 36519 / 878810 ], [ 16779 / 1248040 , - 147721 / 1248040 , 1266979 / 1248040 ], ]; return multiplyMatrices( M, XYZ); } // Rec. 2020 相关函数 function lin_2020( RGB) { // 将 rec2020 RGB 数组(范围 0.0 - 1.0)转换为线性光形式 // 参考电光传递函数来自 Rec. ITU-R BT.1886 附录1 // b(黑电平提升)= 0,a(用户增益)= 1 // 在扩展范围上定义,不进行裁剪 return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); >return sign* Math. pow( abs, 2.4 ); }); } function gam_2020( RGB) { // 将线性光 rec2020 RGB 数组(范围 0.0-1.0)转换为伽马校正形式 // 参考电光传递函数来自 Rec. ITU-R BT.1886 附录1 // b(黑电平提升)= 0,a(用户增益)= 1 // 在扩展范围上定义,不进行裁剪 return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); >return sign* Math. pow( abs, 1 / 2.4 ); }); } function lin_2020_to_XYZ( rgb) { // 将线性光 rec2020 值转换为 CIE XYZ // 使用 D65(不做色度适应) var M= [ [ 63426534 / 99577255 , 20160776 / 139408157 , 47086771 / 278816314 ], [ 26158966 / 99577255 , 472592308 / 697040785 , 8267143 / 139408157 ], [ 0 / 1 , 19567812 / 697040785 , 295819943 / 278816314 ], ]; // 实际上 0 是计算得出的 4.994106574466076e-17 return multiplyMatrices( M, rgb); } function XYZ_to_lin_2020( XYZ) { // 将 XYZ 转换为线性光 rec2020 var M= [ [ 30757411 / 17917100 , - 6372589 / 17917100 , - 4539589 / 17917100 ], [ - 19765991 / 29648200 , 47925759 / 29648200 , 467509 / 29648200 ], [ 792561 / 44930125 , - 1921689 / 44930125 , 42328811 / 44930125 ], ]; return multiplyMatrices( M, XYZ); } // 色度适应 function D65_to_D50( XYZ) { // 使用 Bradford 方法从 D65 适应到 D50 // 下列矩阵是三步操作的结果: // - 从 XYZ 转换到视网膜锥体域 // - 将分量按参考白点从一个缩放到另一个 // - 再转换回 XYZ // 参见 https://github.com/LeaVerou/color.js/pull/354/files var M= [ [ 1.0479297925449969 , 0.022946870601609652 , - 0.05019226628920524 ], [ 0.02962780877005599 , 0.9904344267538799 , - 0.017073799063418826 ], [ - 0.009243040646204504 , 0.015055191490298152 , 0.7518742814281371 ] ]; return multiplyMatrices( M, XYZ); } function D50_to_D65( XYZ) { // 使用 Bradford 方法从 D50 适应到 D65 // 参见 https://github.com/LeaVerou/color.js/pull/360/files var M= [ [ 0.955473421488075 , - 0.02309845494876471 , 0.06325924320057072 ], [ - 0.0283697093338637 , 1.0099953980813041 , 0.021041441191917323 ], [ 0.012314014864481998 , - 0.020507649298898964 , 1.330365926242124 ] ]; return multiplyMatrices( M, XYZ); } // CIE Lab 和 LCH function XYZ_to_Lab( XYZ) { // 假定 XYZ 是相对于 D50 的,转换为 CIE Lab // 根据 CIE 标准,现定义为有理分数形式 var ε= 216 / 24389 ; // 6^3/29^3 var κ= 24389 / 27 ; // 29^3/3^3 // 计算 xyz,即相对于参考白点缩放的 XYZ var xyz= XYZ. map(( value, i) => value/ D50[ i]); // 现在计算 f var f= xyz. map( value=> value> ε? Math. cbrt( value) : ( κ* value+ 16 ) / 116 ); return [ ( 116 * f[ 1 ]) - 16 , // L 500 * ( f[ 0 ] - f[ 1 ]), // a 200 * ( f[ 1 ] - f[ 2 ]) // b ]; // L 在 [0,100] 范围。用于 CSS 时乘以 100 并加上百分号 } function Lab_to_XYZ( Lab) { // 将 Lab 转换为 D50 适配的 XYZ // http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html var κ= 24389 / 27 ; // 29^3/3^3 var ε= 216 / 24389 ; // 6^3/29^3 var f= []; // 计算 f,从亮度相关项开始 f[ 1 ] = ( Lab[ 0 ] + 16 ) / 116 ; f[ 0 ] = Lab[ 1 ] / 500 + f[ 1 ]; f[ 2 ] = f[ 1 ] - Lab[ 2 ] / 200 ; // 计算 xyz var xyz= [ Math. pow( f[ 0 ], 3 ) > ε? Math. pow( f[ 0 ], 3 ) : ( 116 * f[ 0 ] - 16 ) / κ, Lab[ 0 ] > κ* ε? Math. pow(( Lab[ 0 ] + 16 ) / 116 , 3 ) : Lab[ 0 ] / κ, Math. pow( f[ 2 ], 3 ) > ε? Math. pow( f[ 2 ], 3 ) : ( 116 * f[ 2 ] - 16 ) / κ]; // 将 xyz 乘以参考白点以计算 XYZ return xyz. map(( value, i) => value* D50[ i]); } function Lab_to_LCH( Lab) { var epsilon= 0.0015 ; var chroma= Math. sqrt( Math. pow( Lab[ 1 ], 2 ) + Math. pow( Lab[ 2 ], 2 )); // 色度 var hue= Math. atan2( Lab[ 2 ], Lab[ 1 ]) * 180 / Math. PI; if ( hue< 0 ) { hue= hue+ 360 ; } if ( chroma<= epsilon) { hue= NaN ; } return [ Lab[ 0 ], // L 保持不变 chroma, // 色度 hue// 色相,度数范围 [0 到 360) ]; } function LCH_to_Lab( LCH) { // 从极坐标形式转换 return [ LCH[ 0 ], // L 保持不变 LCH[ 1 ] * Math. cos( LCH[ 2 ] * Math. PI/ 180 ), // a LCH[ 1 ] * Math. sin( LCH[ 2 ] * Math. PI/ 180 ) // b ]; } // OKLab 与 OKLCH // https://bottosson.github.io/posts/oklab/ // 为了参考白点一致重新计算的 XYZ <-> LMS 矩阵 // 见 https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484 // 以 64 位精度重新计算 // 见 https://github.com/color-js/color.js/pull/357 function XYZ_to_OKLab( XYZ) { // 给定相对于 D65 的 XYZ,转换为 OKLab var XYZtoLMS= [ [ 0.8190224379967030 , 0.3619062600528904 , - 0.1288737815209879 ], [ 0.0329836539323885 , 0.9292868615863434 , 0.0361446663506424 ], [ 0.0481771893596242 , 0.2642395317527308 , 0.6335478284694309 ] ]; var LMStoOKLab= [ [ 0.2104542683093140 , 0.7936177747023054 , - 0.0040720430116193 ], [ 1.9779985324311684 , - 2.4285922420485799 , 0.4505937096174110 ], [ 0.0259040424655478 , 0.7827717124575296 , - 0.8086757549230774 ] ]; var LMS= multiplyMatrices( XYZtoLMS, XYZ); // JavaScript Math.cbrt 返回带符号的立方根 // 如果移植到其它语言请小心 // 尤其不要使用通用的幂函数替代 return multiplyMatrices( LMStoOKLab, LMS. map( c=> Math. cbrt( c))); // L 在 [0,1] 范围。用于 CSS 时乘以 100 并加上百分号 } function OKLab_to_XYZ( OKLab) { // 给定 OKLab,转换为相对于 D65 的 XYZ var LMStoXYZ= [ [ 1.2268798758459243 , - 0.5578149944602171 , 0.2813910456659647 ], [ - 0.0405757452148008 , 1.1122868032803170 , - 0.0717110580655164 ], [ - 0.0763729366746601 , - 0.4214933324022432 , 1.5869240198367816 ] ]; var OKLabtoLMS= [ [ 1.0000000000000000 , 0.3963377773761749 , 0.2158037573099136 ], [ 1.0000000000000000 , - 0.1055613458156586 , - 0.0638541728258133 ], [ 1.0000000000000000 , - 0.0894841775298119 , - 1.2914855480194092 ] ]; var LMSnl= multiplyMatrices( OKLabtoLMS, OKLab); return multiplyMatrices( LMStoXYZ, LMSnl. map( c=> c** 3 )); } function OKLab_to_OKLCH( OKLab) { var epsilon= 0.000004 ; var hue= Math. atan2( OKLab[ 2 ], OKLab[ 1 ]) * 180 / Math. PI; var chroma= Math. sqrt( OKLab[ 1 ] ** 2 + OKLab[ 2 ] ** 2 ); if ( hue< 0 ) { hue= hue+ 360 ; } if ( chroma<= epsilon) { hue= NaN ; } return [ OKLab[ 0 ], // L 保持不变 chroma, hue]; } function OKLCH_to_OKLab( OKLCH) { return [ OKLCH[ 0 ], // L 保持不变 OKLCH[ 1 ] * Math. cos( OKLCH[ 2 ] * Math. PI/ 180 ), // a OKLCH[ 1 ] * Math. sin( OKLCH[ 2 ] * Math. PI/ 180 ) // b ]; } // 预乘 alpha 的转换 function rectangular_premultiply( color, alpha) { // 给定矩形正交色彩空间中的颜色和 alpha 值 // 返回预乘形式 return color. map(( c) => c* alpha) } function rectangular_un_premultiply( color, alpha) { // 给定矩形正交色彩空间中预乘的颜色和 alpha 值 // 返回实际颜色 if ( alpha=== 0 ) { return color; // 避免除零 } return color. map(( c) => c/ alpha) } function polar_premultiply( color, alpha, hueIndex) { // 给定柱坐标/极坐标色彩空间中的颜色和 alpha 值 // 返回预乘形式 // hueIndex 表示颜色数组中哪一项是色相角 // 例如在 OKLCH 中为 2, 在 HSL 中为 0 return color. map(( c, i) => c* ( hueIndex=== i? 1 : alpha)) } function polar_un_premultiply( color, alpha, hueIndex) { // 给定柱坐标/极坐标色彩空间中的颜色和 alpha 值 // 返回实际颜色 // hueIndex 表示颜色数组中哪一项是色相角 // 例如在 OKLCH 中为 2, 在 HSL 中为 0 if ( alpha=== 0 ) { return color; // 避免除零 } return color. map(( c, i) => c/ ( hueIndex=== i? 1 : alpha)) } // 可以方便地定义一些便捷函数,例如 function hsl_premultiply( color, alpha) { return polar_premultiply( color, alpha, 0 ); }
19. ΔE2000和ΔEOK颜色差异的示例代码
本节非规范性。
测试
本节非规范性,不需要测试。
19.1. ΔE2000
最简单的颜色差异指标,ΔE76, 仅仅是在Lab颜色空间中的欧几里得距离。 虽然这作为一个初步近似是可以接受的, 但如印刷和织物染色等对颜色要求较高的行业 很快就开发出了改进的公式。 目前最广泛使用的公式是ΔE2000。 它修正了与ΔE76相比的一些已知的非对称性和非线性。 由于公式复杂, 并且对各种中间计算的符号依赖性很强, 实现常常出错 [Sharma]。
下面的示例代码已通过验证,具有五个有效数字, 使用由[Sharma]发布的成对Lab值和期望的ΔE2000测试套件, 并且是正确的。
// deltaE2000 相较于 deltaE76 和 deltaE94 在统计学上有显著提升 // 并且被 CIE 和 Idealliance 推荐使用 // 尤其适用于色差小于 10 的情况(以 deltaE76 度量) // 但它非常复杂 // 许多实现都有细微误差! /** * @param {number[]} reference - CIE Lab 数组:L 为 0..100,a 和 b 约为 -150..150 * @param {number[]} sample - CIE Lab 数组:L 为 0..100,a 和 b 约为 -150..150 * @return {number} 测量 sample 相对于 reference 的色差 */ function deltaE2000( reference, sample) { // 给定 reference 和 sample 颜色, // 都以 CIE Lab 表示, // 计算 deltaE 2000。 // 此实现假设参数化加权因子 // kL、kC 和 kH //(用于考虑观察环境的影响) // 全都为 1,这是常用情形。 let [ L1, a1, b1] = reference; let [ L2, a2, b2] = sample; let C1= Math. sqrt( a1** 2 + b1** 2 ); let C2= Math. sqrt( a2** 2 + b2** 2 ); let Cbar= ( C1+ C2) / 2 ; // 平均色度 // 从平均色度计算 a 轴非对称因子 // 这使得近中性色的 JND 椭圆变回圆形 let C7= Math. pow( Cbar, 7 ); const Gfactor= Math. pow( 25 , 7 ); let G= 0.5 * ( 1 - Math. sqrt( C7/ ( C7+ Gfactor))); // 通过非对称因子缩放 a 轴 // 顺带一提,这也是为什么没有 Lab2000 色彩空间 let adash1= ( 1 + G) * a1; let adash2= ( 1 + G) * a2; // 用缩放后的 a 和原 b 轴计算新色度 let Cdash1= Math. sqrt( adash1** 2 + b1** 2 ); let Cdash2= Math. sqrt( adash2** 2 + b2** 2 ); // 计算新色相,真实中性色给 0 // 以度数为单位,不用弧度 const π= Math. PI; const r2d= 180 / π; const d2r= π/ 180 ; let h1= ( adash1=== 0 && b1=== 0 ) ? 0 : Math. atan2( b1, adash1); let h2= ( adash2=== 0 && b2=== 0 ) ? 0 : Math. atan2( b2, adash2); if ( h1< 0 ) { h1+= 2 * π; } if ( h2< 0 ) { h2+= 2 * π; } h1*= r2d; h2*= r2d; // 明度和色度的差值,符号有意义 let ΔL= L2- L1; let ΔC= Cdash2- Cdash1; // 色相差,注意正确的符号 let hdiff= h2- h1; let hsum= h1+ h2; let habs= Math. abs( hdiff); let Δh; if ( Cdash1* Cdash2=== 0 ) { Δh= 0 ; } else if ( habs<= 180 ) { Δh= hdiff; } else if ( hdiff> 180 ) { Δh= hdiff- 360 ; } else if ( hdiff< - 180 ) { Δh= hdiff+ 360 ; } else { console. log( "the unthinkable has happened" ); } // 加权后的色相差,色度越大权重越高 let ΔH= 2 * Math. sqrt( Cdash2* Cdash1) * Math. sin( Δh* d2r/ 2 ); // 计算明度和色度的平均值 let Ldash= ( L1+ L2) / 2 ; let Cdash= ( Cdash1+ Cdash2) / 2 ; let Cdash7= Math. pow( Cdash, 7 ); // 补偿 Lab 空间蓝色区域的非线性 // 色相加权因子有四种可能, // 取决于角度,以获得正确符号 let hdash; if ( Cdash1* Cdash2=== 0 ) { hdash= hsum; } else if ( habs<= 180 ) { hdash= hsum/ 2 ; } else if ( hsum< 360 ) { hdash= ( hsum+ 360 ) / 2 ; } else { hdash= ( hsum- 360 ) / 2 ; } // 对 CIELAB 非均匀性的方位修正 // 这些都试图让 JND 椭球更像球 // SL 明度加权因子 // 假设背景 L=50 let lsq= ( Ldash- 50 ) ** 2 ; let SL= 1 + (( 0.015 * lsq) / Math. sqrt( 20 + lsq)); // SC 色度因子,类似于 CMC 和 deltaE 94 的公式 let SC= 1 + 0.045 * Cdash; // 蓝色非线性校正的交叉项 T let T= 1 ; T-= ( 0.17 * Math. cos(( hdash- 30 ) * d2r)); T+= ( 0.24 * Math. cos( 2 * hdash* d2r)); T+= ( 0.32 * Math. cos((( 3 * hdash) + 6 ) * d2r)); T-= ( 0.20 * Math. cos((( 4 * hdash) - 63 ) * d2r)); // SH 色相因子依赖于色度, // 以及经过调整的色相角,类似于 deltaE94。 let SH= 1 + 0.015 * Cdash* T; // RT 色相旋转项补偿了 JND 椭圆和 // Munsell 等色线在中高色度蓝色区域的旋转 //(色相 225 到 315) let Δθ= 30 * Math. exp( - 1 * ((( hdash- 275 ) / 25 ) ** 2 )); let RC= 2 * Math. sqrt( Cdash7/ ( Cdash7+ Gfactor)); let RT= - 1 * Math. sin( 2 * Δθ* d2r) * RC; // 最后逐项取平方和开方得到 deltaE let dE= ( ΔL/ SL) ** 2 ; dE+= ( ΔC/ SC) ** 2 ; dE+= ( ΔH/ SH) ** 2 ; dE+= RT* ( ΔC/ SC) * ( ΔH/ SH); return Math. sqrt( dE); // 成功!!! };
19.2. ΔEOK
由于 Oklab 不存在 CIE Lab 的色相线性、色相均匀性和色度非线性的问题,因此颜色差异度量不需要对它们进行修正,因此在 Oklab 颜色空间中的颜色差异度量就是简单的欧几里得距离。
// 计算 deltaE OK // 简单的平方和的平方根 /** * @param {number[]} reference - OKLab 值数组:L 范围 0..1,a 和 b 范围 -1..1 * @param {number[]} sample - OKLab 值数组:L 范围 0..1,a 和 b 范围 -1..1 * @return {number} 样本颜色与参考颜色的差异度 */ function deltaEOK( reference, sample) { let [ L1, a1, b1] = reference; let [ L2, a2, b2] = sample; let ΔL= L1- L2; let Δa= a1- a2; let Δb= b1- b2; return Math. sqrt( ΔL** 2 + Δa** 2 + Δb** 2 ); }
附录 A:已废弃的 CSS 系统颜色
CSS 的早期版本定义了几个额外的系统颜色。然而,这些颜色关键字已经被废弃,因为它们对于原来的用途(使网站元素看起来像它们的本地操作系统对应部分)已经不够充分,并且会增加安全风险,容易使网页“伪装”成本地操作系统对话框,从而增加指纹识别面,损害用户隐私。
用户代理必须支持这些关键字,并且为了减轻指纹识别,必须将它们映射到下方列出的(未废弃的)系统颜色。作者不得使用这些关键字。
已废弃的系统颜色表示为<deprecated-color>子类型,并定义为:
- ActiveBorder
- 活动窗口边框。与ButtonBorder相同。
- ActiveCaption
- 活动窗口标题。与Canvas相同。
- AppWorkspace
- 多文档界面的背景色。与Canvas相同。
- Background
- 桌面背景。与Canvas相同。
- ButtonHighlight
- 面对光源的 3D 元素边框的颜色,使这些元素通过一层围绕的边框看起来具有 3D 效果。与ButtonFace相同。
- ButtonShadow
- 远离光源的 3D 元素边框的颜色,使这些元素通过一层围绕的边框看起来具有 3D 效果。与ButtonFace相同。
- CaptionText
- 标题、大小框和滚动条箭头框中的文本。与CanvasText相同。
- InactiveBorder
- 非活动窗口边框。与ButtonBorder相同。
- InactiveCaption
- 非活动窗口标题。与Canvas相同。
- InactiveCaptionText
- 非活动标题中的文本颜色。与GrayText相同。
- InfoBackground
- 工具提示控件的背景色。与Canvas相同。
- InfoText
- 工具提示控件的文本颜色。与CanvasText相同。
- Menu
- 菜单背景。与Canvas相同。
- MenuText
- 菜单中的文本。与CanvasText相同。
- Scrollbar
- 滚动条的灰色区域。与Canvas相同。
- ThreeDDarkShadow
- 3D 元素远离光源的两条边框中较暗的一条(通常是外层边框)的颜色,使这些元素看起来具有 3D 效果。与ButtonBorder相同。
- ThreeDFace
- 3D 元素的表面背景颜色,这些元素通过两层同心边框看起来具有 3D 效果。与ButtonFace相同。
- ThreeDHighlight
- 3D 元素面对光源的两条边框中较亮的一条(通常是外层边框)的颜色,使这些元素看起来具有 3D 效果。与ButtonBorder相同。
- ThreeDLightShadow
- 3D 元素面对光源的两条边框中较暗的一条(通常是内层边框)的颜色,使这些元素看起来具有 3D 效果。与ButtonBorder相同。
- ThreeDShadow
- 3D 元素远离光源的两条边框中较亮的一条(通常是内层边框)的颜色,使这些元素看起来具有 3D 效果。与ButtonBorder相同。
- Window
- 窗口背景。与Canvas相同。
- WindowFrame
- 窗口框架。与ButtonBorder相同。
- WindowText
- 窗口中的文本。与CanvasText相同。
测试
- deprecated-sameas-001.html (实时测试) (来源)
- deprecated-sameas-002.html (实时测试) (来源)
- deprecated-sameas-003.html (实时测试) (来源)
- deprecated-sameas-004.html (实时测试) (来源)
- deprecated-sameas-005.html (实时测试) (来源)
- deprecated-sameas-006.html (实时测试) (来源)
- deprecated-sameas-007.html (实时测试) (来源)
- deprecated-sameas-008.html (实时测试) (来源)
- deprecated-sameas-009.html (实时测试) (来源)
- deprecated-sameas-010.html (实时测试) (来源)
- deprecated-sameas-011.html (实时测试) (来源)
- deprecated-sameas-012.html (实时测试) (来源)
- deprecated-sameas-013.html (实时测试) (来源)
- deprecated-sameas-014.html (实时测试) (来源)
- deprecated-sameas-015.html (实时测试) (来源)
- deprecated-sameas-016.html (实时测试) (来源)
- deprecated-sameas-017.html (实时测试) (来源)
- deprecated-sameas-018.html (实时测试) (来源)
- deprecated-sameas-019.html (实时测试) (来源)
- deprecated-sameas-020.html (实时测试) (来源)
- deprecated-sameas-021.html (实时测试) (来源)
- deprecated-sameas-022.html (实时测试) (来源)
- deprecated-sameas-023.html (实时测试) (来源)
附录 B:已废弃的古怪十六进制颜色
当 CSS 在怪癖模式下解析时,<quirky-color>是一种仅在某些属性中有效的<color>类型:
它在包含或引用这些属性的属性中无效,例如background简写属性,或在函数表示法中如color-mix()
此外,虽然<quirky-color>在解析受影响的属性时必须作为<color>有效,但在@supports规则中,它在CSS.supports()方法中无效。
<quirky-color>可以表示为<number-token>,<dimension-token>,或<ident-token>,根据以下规则:
-
如果是<ident-token>,则标记的表示必须包含恰好 3 或 6 个字符,且全部为十六进制数字。它表示具有相同值的<hex-color>。
-
如果是<number-token>,则必须设置其整数标志。
序列化整数的值。如果序列化后的值少于 6 个字符,则在其前面添加“0”字符,直到达到 6 个字符。它表示具有相同值的<hex-color>。
-
如果是<dimension-token>,则必须设置其整数标志。
序列化整数的值,并附加标记单位的表示。如果结果少于 6 个字符,则在其前面添加“0”字符,直到达到 6 个字符。它表示具有相同值的<hex-color>。
(换句话说,怪癖模式允许在没有前导“#”的情况下编写十六进制颜色,但具有奇怪的解析规则。)
测试
奇特的十六进制颜色
致谢
除了那些为 CSS Color 3 做出贡献的人之外,编辑们还要感谢 Emilio Cobos Álvarez、Alexey Ardov、Chris Bai、Amelia Bellamy-Royds、Lars Borg、Mike Bremford、Andreu Botella、Dan Burzo、Max Derhak、fantasai、Simon Fraser、Devon Govett、Phil Green、Dean Jackson、Andreas Kraushaar、Pierre-Anthony Lemieux、Tiaan Louw、Cameron McCormack、Romain Menke、Chris Murphy、Isaac Muse、 Jonathan Neal、Chris Needham、Björn Ottosson、Christoph Päper、Brad Pettit、Xidorn Quan、Craig Revie、 Melanie Richards、Florian Rivoal、Jacob Rus、Joseph Salowey、Simon Sapin、Igor Snitkin、Lea Verou、Mark Watson、James Stuckey Weber、Sam Weinig 和 Natalie Weizenbaum。
变更记录
自 2025年4月24日 候选推荐草案 以来的变更
- 在摘要中补充了关于颜色插值和色域映射的内容。
- 澄清了 CSS 色域映射目标的相关表述。
- 修正了射线追踪算法不会覆盖 end (Issue 10579)
- 新增射线追踪色域映射算法的伪代码 (Issue 10579)
- 新增 EdgeSeeker 和 Ray Trace 色域映射算法。允许三选一色域映射。 (Issue 10579)
- 添加了一个展示 CIE Lab 中虚色的示意图
- 区分了“超出色域但物理可实现颜色”与“虚色”
- 更全面地描述了裁剪,展示了部分能获得可接受结果的情况 (Issue 10579)
- 修正 ΔE2000 示例实现的偏差 (Issue 13322)
- 更新 AccentColor:除非处于 accent-color被强制的配色模式下,否则取值自该属性 (Issue 5900)
- 定义 rec2020 色彩空间采用 display-referred、2.4 gamma (Issue 12574)
- 为预定义色彩空间新增 display-p3-linear (Issue 11250)
- 澄清使用 calc() 时 opacity 序列化的细节 (Issue 10426)
- 为兼容性,传统 sRGB 颜色之间的插值(再次)在 sRGB 空间中进行 (Issue 7949)
- 明确 CIE Lab 空间 a 和 b 实际范围 (Issue 12208)
- 明确 opacity 值不会影响命中测试 (Issue 11339)
自 2024 年 2 月 13 日候选推荐草案以来的变更
- 阐明了在 color 属性内部,使用的是已解析的继承值(而非原始继承值)
- 列出了颜色类别,例如解析为 sRGB 或支持旧版颜色语法的颜色类别
- 添加了色相归一化示例
- 更正了类似分量表,alpha 缺失,但在正文中描述为类似
- 将不透明度值的序列化收集并阐明到一个章节中
- 阐明了围绕 color-interpolation-method 和宿主语法的措辞
- 定义了用于返回缺失色相的 epsilon
- 对具有缺失色相的消色差颜色使用了更精确的定义(足够接近中心轴)
- 统一使用“颜色分量”而非“颜色通道”(两者之前都在使用)。
- 在未定义或解释的情况下使用了相关色温。添加了信息性参考。
- 导出了术语“预乘”,并始终链接到它
- 已弃用和未弃用系统颜色的等效性不再处于风险之中
- 阐明了“解析 CSS <color>”算法的预期用途
- 为 HTML 兼容序列化添加了更正的示例
- 删除了对 HTML 兼容序列化中缺失值的检查,它们将已经被转换为零
- 移动了关于缺失值变为 0 的说明,使其同时适用于 HTML 兼容序列化和 CSS 序列化
- 为 sRGB 添加了 HTML 兼容的十六进制序列化
- 添加了另一个 xyz-d65 和 xyz-d50 示例
- 阐明了 XYZ 中的哪个分量 (Y) 对应于亮度
- 阐明了 CSS 色域映射适用于实际值而非使用值
- 从 hslToRgb 示例代码中删除了色相归一化,因为输入在解析时已经归一化
- 更正了色域映射算法第 4 步的伪代码
- 阐明了插值是组合两种颜色的最常见情况,但不是唯一情况。
- 确保 deltaE 表中文字具有足够的对比度
- 删除了术语 <absolute-color-function> 的其余用法,为保持一致性改用 <absolute-color> function
- 更新了致谢部分
- 添加了色域网格图
- 根据声明值而非指定值描述了 CSSOM 序列化
- 添加了亮度的导出定义
- 添加了 <opacity-value> 的产生式规则
- 阐明了 hslToRgb 的结果何时在 [0,1] 范围内
- 阐明了 RGB 空间一旦线性化就是可加的
自 2022 年 11 月 1 日的候选推荐草案以来的更改
- 添加了序列化 uint8_t alpha 的步骤,从 cssom-1 中移动
- 恢复了解析时对 HSL 负饱和度的钳制为 0,这是 CSS Color 3 的当前互操作行为
- 插值时,始终转换颜色空间,以便无效的组件成为缺失的组件
- 澄清了何时从序列化中省略 alpha 为 1
- 移除了对色相角度的重复约束为 [0,360],因为这已经完成了
- 修正了 ActiveCaption 的描述,它是一个背景
- 区分了不透明度和 alpha。不透明度属性现在使用 opacity-value(其钳制行为与 alpha-value 不同)
- 澄清了在预乘之前进行前向运算
- 更新了色域映射算法
- 修复了一些关于色相插值的问题
- 澄清了 HWB 的白色或黑色达到 100% 并不足以构成无色彩,关键是其总和
- 避免在 RGB 到 HSL 转换中返回负饱和度;调整色相指向“另一侧”
- 对 ProPhoto 使用 64 位精确矩阵,它没有有理数形式
- 重新计算 Oklab 矩阵以达到 64 位精度(与之前 32 位精度下的结果相同)
- 即使目标未被限定,在色域映射中仍然一致地返回目标颜色空间的 GMA 输出
- 添加了解释为什么 Oklab 的一个 JND 为 0.02 而不是 2
- 澄清了解析 sRGB 值不适用于 color() 函数
- 将 alpha 值定义上移至不透明度属性,澄清不透明度指定值不被钳制
- 系统颜色现在明确允许伪装,以保护隐私
- 修正了 D50 到 D65 的逆色度适应矩阵
- 一致区分线性 Bradford 和原始、更复杂的 Bradford 色度适应算法
- 在色域映射算法中,返回剪裁后的结果,避免不必要的步骤
- 将色度适应矩阵更新为更高精度
- 添加了“解析 css 颜色”的算法,以便非 CSS 规范使用颜色时不必重新发明机制
- 澄清几何色域映射不能将色度投射回原始颜色之外
- 在色域映射讨论中使用术语“几何”而不是“分析”
- 将 HSL 的叙述与语法保持一致(百分比和数字均可接受)
- 修正了 LCH alpha 插值示例,错误地未预乘色相角度
- 修正了 sRGB 和 display-p3 传递函数。(仅当一个分量具有精确值 10.31475 / 255 时才会影响结果,这在每分量 8 或 10 位的情况下是不可能的)
- 澄清了系统颜色的指定值仍然是它们本身
- 添加了对 PNG cICP 块标记图像的提及
- 描述了传递 0/360 时色相增加和减少的行为
- 将 HSL 中无力的描述与其他极坐标颜色模型对齐
- 明确定义了颜色插值的操作顺序
- 添加了关于 calc() 中退化数值常量的提及
- 澄清了 sRGB 中 calc() 具有早期解析和钳制结果的行为
- 澄清了 HWB 色相具有与 HSL 色相相同的缺点
- 添加了亮度与明度的比较和图示
- 添加了色相插值关键字的描述和示例
- 对无色 HWB 颜色使用规范化叙述
- 修正了色相插值角度范围;[0,360) 而不是 [0,360]
- 表达了当 L=0% 或 100% 时显示为黑或白是由于色域映射。移除了错误的无力声明
- 移除了令人困惑的“表示黑色”和“表示白色”的评论
- 澄清了对手 a 和 b 是类比的
- 使用参考范围而不是叙述性描述来定义 RGB 组件,以保持一致性
- 明确参考了百分比转换为数字时 Lab、LCH、Oklab、OKLCh 序列化的百分比参考范围
- 要求 Oklab 插值,移除之前的“可以”,并描述了显式退出
- 将 Lab、LCH、Oklab 和 OKLCh 教程部分标记为非规范性。将一些定义移出非规范部分
- 澄清了插值时,在颜色空间转换之前进行类比组件的检查
- 从 CSS Color 5 回移了 hwb() 语法更改和参考范围
- 定义前向运算必须在无力操作之前进行
- 澄清了在传统 rgb() 语法中必须是全数字或全百分比的颜色组件
- 澄清了对于传统语法,颜色组件必须是全百分比或全数字
- 添加了在 calc() 中指定超出范围的 alpha 的示例
- 将带修剪后尾随零的颜色序列化示例放置到相关文本
- 澄清了 currentColor 的解析
- 更新了致谢部分
- 停止声称无色颜色具有缺失的 a、b 或色度
- 将 HSL 和 HWB 更改为无界色域,以促进来回转换
- 定义 HSL 的百分比参考范围
- 现代颜色语法 hsl() 和 hsla() 允许混合数字和百分比分量
- 现代颜色语法 rgb() 和 rgba() 允许混合数字和百分比分量
- 定义术语“现代颜色语法”(“传统颜色语法”已定义)
- 一致使用术语“类比组件”
- 更改为允许所有预定义的色彩空间进行插值
- 澄清了对于 color(),需要三个参数(RGB 或 XYZ)
- 澄清了命名颜色、系统颜色和透明的序列化
- 定义 Lab、LCH、Oklab、OKLCh 的指定值
- 定义其他 sRGB 颜色的指定值
- 定义命名颜色和系统颜色的指定值
- 在解析值时间钳制 alpha、明度、色度和色相
- 移除对高光白和 CIE 明度的提及
- 不再要求保留指定的色相;钳制到 [0, 360]
- 在示例中保持明度和数字的序列化一致性
- 轻微的拼写错误和编辑性澄清
自 2022 年 7 月 5 日的候选推荐草案以来的更改
- 移除了色相插值的“指定”值
- 更精确地定义了色相插值角度,保持 360 度的差异
- 添加了预乘运算中携带前向 alpha 的示例
- 澄清了 L=100% 时 a,b 和 C,h 无效,表示白色
- 移除了对 L=400 的随意提及,它适用于 hdr-CIELAB 而非 CIE Lab
- 一致地使用 Oklab 和 OKLCh 的大小写
- 将有效颜色、无效颜色、超出色域和在色域内的定义移动到术语部分
- 修正了“更长”色相插值的定义
- 进一步澄清了主机语法的概念
- 改进了颜色样本的可访问性
- 明确指出传统形式不支持“none”
- 从色相生成中移除了“none”,因为它在传统语法中不允许
- 移除了一些与 CMYK 和 CMYKOGV 相关的残余引用,移动到 CSS Color 5
- 澄清了插值颜色中缺失的值是如何前向传递的
- 更新了 xyz-params 的语法,使其接受数字和百分比,以与叙述保持一致
- 确保所有示例和图示都有 ID,自引用链接
- 澄清了对实现者来说阅读色域映射介绍的重要性
- 移除了剩余的自定义色彩空间提及(该功能已移至 CSS Color 5)
- 重构了 <color> 和 <alpha-value> 的语法
- 编辑性重构以获得更好的阅读顺序
- 更新了色域映射算法的伪代码,移除不必要的 deltaE 调用
自 2022 年 6 月 28 日的工作草案以来的更改
- 更新了候选推荐的状态
自 2022 年 4 月 28 日的工作草案以来的更改
- 将不透明度属性移动到模块顶部,紧邻颜色属性,进入详细内容之前
- 改进了对 color 属性的描述,特别是其对其他属性的影响
- 修正了等于模 360 颜色的更长色相调整方程
- 添加了两个新的系统颜色:AccentColor 和 AccentColorText
- 在新部分中描述了整体的颜色空间转换步骤
- 考虑了 none alpha 在预乘和反预乘中的影响
自 2021 年 12 月 15 日的工作草案以来的更改
- 使系统颜色完全解析,但禁止在强制颜色模式中更改它们
- 移除了对 color() 函数中参数数量不正确的宽容处理
- 将 CIE Lightness 和 OK Lightness 的序列化更改为数字而非百分比
- 将已废弃的系统颜色等价标记为风险项
- 为 CIE 和 OK L,a,b,C 的百分比值添加了参考范围
- 指出有用于执行和撤销预乘运算的示例代码,适用于矩形和极坐标颜色空间
- 为色域映射叙述以及伪代码添加了超出范围的钳制
- 添加了 ProPhoto RGB / ROMM 的规范性参考
- 修正了 sRGB 和 Display P3 参考围绕的黑点值
- 添加了 Display P3 的规范性参考
- 避免了在色域减少中出现无限循环,对比白色或比黑色更暗的颜色
- 澄清了 none 值的序列化
- 澄清了 Oklab 中非传统颜色的插值选择加入
- 定义了预乘运算的工作原理,涉及 none 值
- 澄清了在 RGB 中缺失的值序列化为 0
- 澄清了与 none 值一起使用 calc() 的行为
- 系统颜色中拼写错误和大小写不一致的问题
- 添加了 SelectedItem 和 SelectedItemText 的示例
- 明确提到遗留颜色的存在与否
- 添加了 CIE XYZ 的规范性参考
- 添加了 HWB 和 HSL 的规范性参考
- 澄清了 hwb() 不是传统语法,因此不支持旧的逗号分隔形式
- 澄清了只有遗留颜色会进行色域映射,其他颜色是无界的
- 使用不同术语,分光光度计和分光辐射计
- 修复了一些小拼写错误,并进行了语法改进
自 2021 年 6 月 1 日的工作草案以来的更改
- 添加了色域映射部分,并定义了 CSS 色域映射算法为 OKLCh 中的色度缩减,使用局部 MINDE
- color(xyz ...) 的计算值为 color(xyz-d65 ...)
- 将 srgb-linear 添加到插值颜色空间中
- 更新了来自 Colors 3 的更改部分
- 添加了解析 Oklab 和 OKLCh 值的部分
- 添加了 srgb-linear 颜色空间
- 根据 CSSWG 决议将 @color-profile 和 device-cmyk 移至 5 级
- 定义了插值颜色空间
- 澄清了矩阵是行优先的,并链接到矩阵乘法库
- 将旧的安全与隐私部分拆分为单独的部分
- 定义了怪癖模式下的古怪十六进制颜色
- 移除了 device-cmyk 中的后备颜色
- 未声明默认值的主机语法现在默认使用 Oklab
- 添加了 deltaE OK 的示例代码
- 添加了 OKlab 和 OKLCh 的示例转换代码
- 添加了 oklab() 和 oklch() 函数 添加了 Oklab 和 OKLCh 的描述
- 添加了 CIE LCH 的缺陷描述
- 允许颜色的所有组件通过 none 关键字“缺失”,定义了组件在某些情况下何时“无效”并自动变为缺失,并将所有对“NaN”组件的引用修正为使用“缺失”概念
- 定义了明确的 x,y 白点值,并在整个过程中保持一致
- 定义了主机语法的术语
- 定义了解决覆盖颜色上下文的背景
- 添加了一对新的系统颜色
- 修正了 HSL 和 HWB 的示例代码
- 用无错误版本替换了 HSL 值表
- 根据 WG 决议添加 Lea Verou 为共同编辑
- 澄清了色相角度是无界的
- 修正了 MarkText 示例
- 添加了图示,修正了示例
- 一些编辑性澄清
- 修正了一些小拼写错误和标记错误
自 2020 年 11 月 12 日的工作草案以来的更改
- 指出在接近中性的 Lab 值转换为 LCH 时的不确定色相问题
- 澄清了 RGB 和 Lab 互换中的哪些步骤是线性组合
- 在 @color-profile 中添加了组件描述符,用于 CSS Color 5
- 所有预定义的 RGB 色彩空间均定义为扩展范围
- 澄清了在颜色插值之前没有色域映射或色域裁剪步骤
- 澄清了传统 sRGB 语法的插值
- 从 color() 中移除了 lab 选项
- 列出了在预定义色彩空间之间互换的步骤
- 一致使用“色彩空间”这一术语(两个词)
- 提供了有关选择用于混合的色彩空间的更多指导
- 重新计算了一个示例以提高精度
- 添加了色相插值示例
- 通过移除后备选项简化了 color() 语法
- 澄清了可以从 @color-profile 链接的 ICC 配置文件类型
- 移除了对罕见 ICC 命名颜色的支持
- 提高了标准白点色度精度
- 移除了对一个预定义色彩空间描述中的商标
- 重新措辞使插值在插值空间方面更加通用
- 修正了可访问性考虑部分
- 澄清了 color() 的色彩空间参数是必需的,即使是 sRGB
- 澄清了 currentColor 不仅限于 sRGB
- 对 sRGB 到 XYZ 到 sRGB 矩阵进行了小的修正,以提高往返精度
- 澄清了 rec2020 传递函数,并引用了正确的 ITU Rec BT.2020-2 参考
- 修正了后备示例,以使用正确的语法
- 不强制非传统颜色在伽马编码空间中进行插值
- 定义了预乘 alpha 插值
- 开始处理到 currentColor 的插值
- 定义了包含 NaN 的色相插值
- 使颜色插值更加通用
- 定义插值为 Lab 中,覆盖为 LCG
- 对色相插值进行了修正
- 定义了色相角度插值
- 添加了插值部分
- 修正了一些示例中的语法
- 澄清了 color() 中允许百分比的组件
- 更改了 lch() 的序列化方式,不再作为 lab() 序列化
- 对于 color() 中的非传统 sRGB,组件精度最低为 10 位
- color() 中的色彩空间不再是可选的
- 在 lab() 和 color(lab) 之间保持一致的最低精度
- 澄清了 color() 函数的后备过程:第一个有效的在色域内的颜色,否则第一个有效颜色,然后映射色域,否则为透明黑
- 澄清了不透明度属性与具有不透明度的颜色之间的差异,特别是在渲染重叠文本字形时
- 添加了 ΔE2000 的示例代码(经过验证)
- 添加了之前未定义的术语“色度”的定义,并给出了示例;定义了色度图
- 添加了颜色加法性的解释和示例
- 为 WPT 测试添加了源链接
- 导出颜色和有效颜色的定义,以供其他规范引用
- 定义序列化时每个组件的最低位数
- 更新了“适用于”定义(CSS 的普遍更改)
- 为预定义色彩空间添加了图像状态(显示参考或场景参考)
- 列出了白点相关色温(例如 D65),以便于与色度坐标区分
- 澄清了四舍五入的方向为 +∞
- 修正了拼写错误、标记修正、链接修正
自 2019 年 11 月 5 日的工作草案以来的更改
- 导出一些术语以供其他规范使用
- 将 WCAG 2.0 要求更新为 2.1
- 完整指定序列化中使用的 Unicode 字符
- 定义特殊命名颜色的序列化
- 定义 device-cmyk() 的序列化
- 定义 color() 的序列化
- 以最大程度兼容网络的方式完全定义 RGB 的序列化
- 定义 Lab 和 LCH 的序列化
- 完全定义 alpha 值的序列化
- 一致性检查,以避免意外的 RFC2119
- 为所有示例添加 ID 以便引用
- 将已解析颜色和序列化颜色部分分开
- (安全性)ICC 配置文件不包含可执行代码
- 定义对已配置颜色的超出范围含义
- 澄清了超出范围的钳制
- 添加了指定值的示例
- 澄清了计算值
- 通过对已废弃的系统颜色进行强制映射来抵抗指纹识别
- 添加了关于标准化 X11 颜色的历史和原因的解释性注释
- 修正了 hwb 示例代码
- 为 MacBeth 色块添加了 DeltaE2000 值的表
- 添加了关于 ICC 配置文件互联网媒体类型的注释
- 添加了对 PNG sRGB 块的参考
- 澄清了 CMYK 到 Lab 的互换
- 澄清了 RGB 到 Lab 的互换
- 更多对 HSL 和 LCH 的比较
- 更多对 Rec BT.2020 色彩空间的描述
- 更新了对 prophoto-rgb 的描述
- 移除了值定义部分中重复的“关键字”
- 添加了无效颜色的示例
- 添加了包含多个后备的示例
- 修复了一些拼写错误和标记修正
- 澄清了未声明自定义色彩空间的处理
- 澄清了一些示例和解释性说明
- 处理有效和无效 ICC 配置文件的处理
- 定义了对具有显式标记色彩空间的图像的处理
- 定义了 4k、SDR 视频的色彩空间
- 声明用户对比度设置必须优先
- 澄清了系统颜色在强制颜色模式之外的含义
- 更新了默认样式规则
- 在 color() 中添加了 CIE XYZ 色彩空间
- 更清楚地说明了色相角度,明确允许 NaN
- 改进了系统颜色配对部分,要求 AA 可访问对比度
- 警告了重叠字形和不透明度属性之间的交互
- 修正了颜色定义中的语法
- 改进了对 Highlight/HighlightText 的描述
- 修正了 prophoto-rgb 的传递函数
- 为 prophoto-rgb 原色提供了更高的精度
- 开始定义“无法显示”的概念
- 移除了有关画布表面的段落
- 添加了 buttonborder、mark 和 marktext 系统颜色
- 添加了反向转换,sRGB 到 HWB
- 澄清了极坐标空间是圆柱形的,而非球形的
- 添加了可访问性考虑部分
- 开始描述色度缩减色域映射,而不是按分量剪裁
- 修正了 rec2020 的白色色度
- 通过 @color-profile 使 device-cmyk 可用;更新了 CMYK 到颜色的算法,仅在最后手段时使用简单转换
- 添加了面向打印的 CMYK 和 KCMYOGV 示例
- 用户定义的色彩空间现在使用虚线标识符,使预定义色彩空间可扩展且无冲突
- 在 color() 函数中添加了 lab 选项
- 添加了 CIE Lab 的规范性参考
- 阐明了 prophoto-rgb 使用 D50 白点,因此不需要适应
- 澄清了在 LCH 中增加角度的方向
- 澄清了颜色名称对 ASCII 不区分大小写
- “color”属性的初始值现在为 CanvasText
- 根据 CSS WG 决议移除了令人困惑的 gray() 函数
- 将零散的定义收集到新的颜色术语部分
- 添加了有用的图示和更多的示例
- 一些小的编辑澄清、拼写检查、修复拼写错误、bikeshed 标记修正
自 2016 年 7 月 5 日的工作草案以来的更改
- 将 Lab 和 LCH 中的明度更改为百分比,以提高与 CSS 的兼容性
- 明确了颜色值的钳制
- 现在允许使用百分比透明度
- 定义术语 sRGB 和线性光 sRGB,供其他规范使用
- 添加了新的 CSS 系统颜色列表;将 Text 重命名为 CanvasText
- 使系统颜色关键字计算为它们自身
- 为系统颜色添加计算/使用条目
- 重写了未废弃系统颜色的介绍,使其使用集中于强制颜色模式而非通用使用
- 在预定义色彩空间中使用一致的连字符
- 恢复了关于非不透明元素在没有定位时仍然绘制在图层上的文本
- "color" 属性的初始值现在为黑色
- 澄清了 LCH 中的色相是模 360 度(现已撤销此更改)
- 澄清了 LCH 和 Lab 中 L 的允许范围及 L=100 的含义
- 更新了用于视频的色彩空间的参考
- 添加了 prophoto-rgb 预定义色彩空间
- 修正了 display-p3 的黑白亮度水平
- 澄清了 display-p3 的传递函数
- 添加了 a98-rgb 色彩空间,修正了原始色度的表格
- 澄清了 currentColor 的计算值不是解析后的颜色
- 更新了示例中的语法以符合最新规范
- 移除了 color-mod() 函数
- 从属性定义表中删除了“媒体”项
- 导出并一致使用“透明黑”和“不透明黑”
- 澄清了计算值(如百分比)
- 澄清了颜色组件所需的精度和四舍五入行为
- 澄清了“color”属性对颜色字体字形没有影响(除非特别引用,例如使用 currentColor)
- 澄清了颜色值如何解析
- 澄清了 HSL、HWB 和命名颜色解析为 sRGB
- 简化了从 device-cmyk 到 sRGB 的转换
- 将以前使用逗号的颜色语法描述为“遗留的”;将示例更改为不带逗号的形式
- 移除了要求显示的颜色必须限制在设备色域内的多余要求(似乎没有其他选项!)
- 将 P3 重命名为 display-p3;避免声称它是 DCI P3,因为它们并不相同
- 改进了对“color()”函数参数的描述
- 禁止在“@color-profile”标识符中使用预定义的色彩空间
- 为“color”、“color-adjust”和“opacity”属性定义添加规范顺序
- 将 alpha 合成定义从 SVG11 切换到 CSS 合成
- 澄清示例转换代码是非规范性的
- 添加了安全和隐私考虑
- 更新了多个参考文献至最新版本
- 将内联问题转换为 GitHub 问题的链接
- 一些小的编辑澄清、格式和标记改进
来自 Colors 3 的更改
与 CSS Color 3 相比,主要的变化是 CSS 颜色不再局限于 sRGB 的窄色域。
为了支持这一点,添加了几个全新的功能:
其他技术变更:
- <color> 的序列化现在在此处指定,而不是在 CSS 对象模型中指定
- hwb() 函数,用于以 HWB 表示法指定 sRGB 颜色。
- 添加了命名颜色 rebeccapurple。
此外,还进行了一些语法更改:
- rgb() 和 rgba() 函数现在接受 <number>,而不是 <integer>。
- hsl() 和 hsla() 函数现在对于色相值同时接受 <angle> 以及 <number>。
- rgb() 和 rgba(), 以及 hsl() 和 hsla() 现在互为别名 (它们都具有可选透明度参数)。
- rgb()、rgba()、 hsl() 和 hsla() 均新增了一种新语法, 由以空格分隔的参数和可选的斜杠分隔透明度组成。 所有颜色函数现在都采用该形式的语法, 以符合 CSS 的 函数式符号设计原则。
- 所有 <alpha-value> 的用法现在都可接受 <percentage> 以及 <number>。
- 新增了 4 位和 8 位十六进制颜色,以指定透明度。
- 新增了 none 值,用于表示无效的组件。
20. 安全性考虑
系统颜色,如果它们实际上对应于用户的系统颜色,则会带来安全风险,因为它们使恶意软件网站更容易创建看起来像是来自系统的用户界面。然而,由于现在有几个系统颜色被定义为“通用”,因此认为此风险已得到缓解。
21. 隐私性考虑
本规范定义了“系统”颜色,理论上可能会暴露用户操作系统设置的详细信息,这是一种指纹识别风险。
22. 可访问性考虑
本规范鼓励作者不要仅使用颜色作为区分特征。
本规范鼓励浏览器确保特定系统颜色前景/背景对之间的足够对比度。曾考虑过使用具有特定 AA 或 AAA 对比度的更严格要求,但由于浏览器通常只是传递操作系统做出的颜色选择,或由用户选择(用户可能有特定要求,包括对偏头痛或癫痫发作患者降低对比度),CSSWG 无法要求特定的对比度水平。