1. 简介
本节不具有规范性。
测试
本节为非规范性内容,无需测试。
本模块描述了 CSS 属性,允许作者指定元素文本内容的前景色和不透明度。本模块还详细描述了 CSS <color> 值类型。
它不仅定义了 CSS1、CSS2 和 CSS Color 3 中已有的颜色相关属性和值,还定义了新的属性和值。
特别是,它允许在 sRGB 之外的 颜色空间 中指定颜色;此前,即使显示设备支持,也无法在 CSS 中使用 sRGB 色域之外更饱和的颜色。
提供了 草案实施报告。
1.1. 值定义
本规范遵循 [CSS2] 中的 CSS 属性定义约定,并使用 [CSS-VALUES-3] 中的 值定义语法。本规范中未定义的值类型在 CSS 值与单位 [CSS-VALUES-3] 中定义。与其他 CSS 模块组合可能会扩展这些值类型的定义。
除了定义中列出的属性特定值外,本规范中定义的所有属性也都接受 CSS 全局关键字 作为其属性值。为了可读性,未明确重复列出。
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.6295 0.9657 0.3633 );
加法颜色空间意味着坐标系在光强度上是线性的。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 中的颜色要么是下文针对每种语法形式描述的无效颜色,要么是有效颜色。
任何不是无效颜色的颜色都是有效颜色。
颜色可能是有效颜色,但仍超出输出设备(屏幕、投影仪或打印机)可产生的颜色范围
它被称为超出色域。
每个有效颜色要么对于特定输出设备(屏幕或打印机)是色域内的,要么是超出色域的。
因为,用 display-p3 表示,一个或多个坐标要么大于 1.0,要么小于 0.0color ( prophoto-rgb0.88 0.45 0.10 )
这种颜色是有效的,例如可以用作渐变停止点,但需要进行 CSS 色域映射以进行显示,从而产生一种看起来相似但彩度更低(饱和度更低)的颜色。color ( display-p31.0844 0.43 0.1 )
3. 在 CSS 中应用颜色
3.1. 无障碍访问与通过颜色传达信息
测试
本节提供作者指南,无需测试。
虽然颜色可以为文档增加重要信息并提高可读性,但颜色本身不应是传达重要信息的唯一手段。作者在文档中使用颜色时应考虑 W3C 网络内容无障碍指南 [WCAG21]。
3.2. 前景色:color 属性
| 名称 | color |
|---|---|
| 值 | <color>(颜色) |
| 初始值 | CanvasText |
| 应用于 | 所有元素和文本 |
| 可继承 | 是 |
| 百分比 | 不适用 |
| 计算值 | 计算出的颜色,参见 解析颜色值 |
| 规范顺序 | 按语法 |
| 动画类型 | 按计算值类型 |
测试
此属性指定元素的主要前景色。它被用作其文本内容的填充颜色,并指定 currentcolor 解析为的 使用值,这允许对此外观颜色的间接引用,并影响其他各种颜色属性的初始值,例如 border-color 和 text-emphasis-color。
- <color>(颜色)
- 将主要前景色设置为指定的 <color>。
em{ color : lime; } /* color keyword */ em{ color : rgb ( 0 255 0 ); } /* RGB range 0-255 */ em{ color : rgb ( 0 % 100 % 0 % ); } /* RGB range 0%-100% */ em{ color : color ( sRGB0 1 0 ); } /* sRGB range 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 (实时测试) (源)
- <opacity-value>
- 应用于元素的不透明度。所得的不透明度应用于整个元素,而不是特定的颜色。
超出范围 [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 属性。
如果盒子的 opacity 小于 1,它为其子元素形成一个 堆叠上下文。(这防止了其内容与外部内容在 Z 轴上交错。)
此外,如果 z-index 属性应用于该盒子,则 auto 值在该元素中被视为 0;否则,它被绘制在与其父堆叠上下文中的定位元素相同的层上,堆叠级别为 0(就好像它是一个 z-index:0 的定位元素)。
有关堆叠上下文的更多信息,请参见 [CSS2] 的 第 9.9 节 和 附录 E。
这些关于 Z 顺序的规则不适用于 SVG 元素,因为 SVG 有其自己的 渲染模型 ([SVG11],第 3 章)。
opacity 属性的值不影响命中测试。
3.4. 带标签图像的颜色空间
带标签图像是根据图像格式定义,显式分配了颜色配置文件的图像。这通常通过包含国际色彩联盟 (ICC) 配置文件 [ICC] 来完成。
例如 JPEG [JPEG]、PNG [PNG] 和 TIFF [TIFF] 都规定了一种嵌入 ICC 配置文件的方法。
图像格式也可以使用其他等效的方法,通常是为了简洁。
例如,PNG 规定了一种方法(sRGB 数据块),在不包含 sRGB ICC 配置文件的情况下,显式将图像标记为处于 sRGB 颜色空间中。
同样,PNG 规定了一种紧凑的方法(cICP 数据块),在不包含 ICC 配置文件的情况下,显式将图像标记为各种 SDR 或 HDR 颜色空间之一,例如 Display P3 或 BT.2100 HLG。
带标签的 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 以下,它是建议 ITU-R BT.601 [ITU-R-BT.601]
-
在 720p 时,它是 SMPTE ST 296(与 709 相同的比色法) [SMPTE296]
-
在 1080p 时,它是建议 ITU-R BT.709 [ITU-R-BT.709]
-
在 4k (UHDTV) 及以上,对于 SDR 视频,它是 ITU-R BT.2020 [Rec.2020]
4. 表示颜色:<color> 类型
测试
本节描述一种类型,它主要在其使用的地方进行测试。
CSS 中的颜色表示为颜色分量列表,有时也称为“通道”,代表颜色空间中的轴。每个分量都有一个最小值和最大值,并且可以取这两个值之间的任何值。此外,每种颜色都伴随一个Alpha 分量,表示它的透明度,从而表示可以通过颜色看到背景的多少。
CSS 有几种指定颜色值的语法
-
sRGB 十六进制颜色表示法,它以十六进制表示 RGB 和 Alpha 分量
-
各种 颜色函数,它们可以使用多种颜色空间和坐标系来表示颜色
-
常量 命名颜色 关键字
-
变量 <system-color> 关键字和 currentColor 关键字。
颜色函数使用 CSS 函数表示法,通过指定其分量坐标,在多种 颜色空间 中表示颜色。其中一些使用圆柱极坐标颜色模型,通过 <hue> 角度、表示亮度(黑到白)的中心轴和表示饱和度或彩度(颜色离中性灰有多远)的半径来指定颜色。其他的使用矩形正交颜色模型,使用三个正交分量轴指定颜色。
Level 4 中可用的颜色函数是
-
rgb() 及其 rgba() 别名,它们(像 十六进制颜色表示法 一样)直接通过红/绿/蓝/Alpha 分量指定 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> 分量是最容易变为 无力(powerless) 的分量;任何足够接近中心消色差轴的颜色,其色相分量都是 无力 的。
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 (在线测试) (源码)
关于在结合两种颜色(如颜色插值)的情况下处理 缺失分量,请参阅 § 13.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 颜色
sRGB 颜色空间中的 CSS 颜色由三个值(红、绿、蓝)的三元组表示,用于标识 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 在其各自的章节中进行了特殊定义。)
下表通过在其他颜色语法中给出等效的数字规范,定义了所有不透明的命名颜色。
| 命名 | Numeric(数值) | 颜色名称 | 十六进制 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. 系统颜色
通常,<system-color> 关键字反映了用户、浏览器或操作系统做出的 默认 颜色选择。因此,它们通常用于浏览器的默认样式表中。
为了保持易读性,<system-color> 关键字也会响应 使用的颜色方案。
易读的链接文本
不可读的链接文本
易读的链接文本
然而,在 强制颜色模式(forced colors mode) 下,页面上的大多数颜色被强制转换为用户选择的受限调色板,请参阅 CSS 颜色调整 1 § 5.2 强制颜色模式调色板。<system-color> 关键字公开了这些用户选择的颜色,以便页面的其余部分可以与此受限调色板集成。
当 forced-colors 媒体特性 处于活动状态 时,作者 应当 在 CSS 颜色调整 1 § 3.1 受强制颜色模式影响的属性 中列出的属性之外的属性中使用 <system-color> 关键字作为颜色值,以确保整个页面的易读性和一致性,并避免用户强制选择的颜色与页面选择的颜色发生不协调的混合。
测试
当 <system-color> 关键字的值来自浏览器(而不是操作系统默认值或用户选择)时,浏览器应确保 匹配的前景/背景对 至少达到 WCAG AA 对比度。然而,用户偏好(对于更高或更低的对比度),无论是设置为浏览器偏好、用户样式表,还是通过更改操作系统默认值,都必须优先于此要求。
作者 可以 在任何时候使用这些关键字,但 应当 注意使用 匹配的背景-前景对 中的颜色以确保适当的对比度,因为跨非匹配对(例如 Canvas 和 ButtonText)的任何特定对比度关系都无法保证。
<system-color> 关键字定义如下
- AccentColor
- 强调用户界面控件的背景。
- AccentColorText
- 强调用户界面控件的文本。
- ActiveText
- 活动链接中的文本。对于浅色背景,传统上为红色。
- ButtonBorder
- 按钮的基本边框颜色。
- ButtonFace
- 按钮的表面背景颜色。
- ButtonText
- 按钮上的文本。
- Canvas
- 应用程序内容或文档的背景。
- CanvasText
- 应用程序内容或文档中的文本。
- 字段
- 输入字段的背景。
- FieldText
- 输入字段中的文本。
- GrayText
- 禁用文本。(通常为灰色,但不一定。)
- Highlight
- 选定文本的背景,例如来自 ::selection。
- HighlightText
- 选定文本的文本。
- LinkText
- 非活动、未访问链接中的文本。对于浅色背景,传统上为蓝色。
- Mark
- 已特别标记的文本的背景(例如由 HTML
mark元素)。 - MarkText
- 已特别标记的文本(例如由 HTML
mark元素)。 - SelectedItem
- 选定项目的背景,例如选定的复选框。
- SelectedItemText
- 选定项目的文本。
- VisitedText
- 已访问链接中的文本。对于浅色背景,传统上为紫色。
测试
注意:与所有其他 关键字 一样,这些名称是 ASCII 大小写不敏感 的。它们在此处以混合大小写显示以方便阅读。
对于没有特定系统 UI 概念的系统,指定的值应映射到存在的最密切相关的系统颜色值。以下 系统颜色配对 预期会形成易读的背景-前景颜色
-
Canvas 背景与 CanvasText、LinkText、VisitedText、ActiveText 前景。
-
Canvas 背景与 ButtonBorder 边框和相邻颜色 Canvas
-
ButtonFace 背景与 ButtonText 前景。
-
ButtonFace 或 Field 背景与 ButtonBorder 边框和相邻颜色 Canvas'
-
Highlight 背景与 HighlightText 前景。
-
SelectedItem 背景与 SelectedItemText 前景。
-
AccentColor 背景与 AccentColorText 前景。
此外,预期 GrayText 在任何背景上都是可读的,尽管可能对比度较低。
为了保持与小部件 强调色(accent color) 样式的一致性,AccentColor 从 accent-color 获取其值,除非启用了 强制颜色模式。AccentColorText 从 AccentColor 的对比前景颜色中获取其值,如小部件 强调色 样式所述。
Canvas 搭配 CanvasText: CanvasText
Canvas 搭配 LinkText: LinkText
Canvas 搭配 VisitedText: VisitedText
Canvas 搭配 ActiveText: ActiveText
Canvas 搭配 GrayText: GrayText
Canvas 搭配 ButtonBorder 和相邻 Canvas: CanvasTextAdjacent
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 定义了额外的 <system-color>,此后已被弃用。这些已记录在 附录 A:已弃用的 CSS 系统颜色 中。
注意:<system-color> 会带来一些隐私和安全风险,如 § 22 隐私考虑 和 § 21 安全考虑 中所述。
为了减轻指纹识别等隐私和安全风险,用户代理可以选择为系统颜色的使用值返回固定值,这些值不反映用户做出的定制或主题选择。
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 的生成更容易。但后来所有的表示属性都从连字符形式更改为 camelCase(驼峰式),因为 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,则色相分量即为 无力 的。
HSL 相对于 RGB 的优势在于它更直观:人们可以猜测他们想要的颜色,然后进行微调。
hsl ( 120 deg 100 % 50 % ) lime greenhsl ( 120 deg 100 % 25 % ) dark greenhsl ( 120 deg 100 % 75 % ) light greenhsl ( 120 deg 75 % 85 % ) pastel green
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]。
此代码假设已经对负饱和度应用了解析时的钳制(clamping)。
/** * @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(Hue-Whiteness-Blackness,色相-白度-黑度)[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 的值是相同的,且值为 白度 / (白度 + 黑度)。
非彩色的 HWB 颜色不再包含任何选定色相的痕迹。在这种情况下,色相分量是无作用的(powerless)。
第四个参数指定颜色的 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° 红色 | ||||||
|---|---|---|---|---|---|---|
| 白\黑 | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 30° 红黄色(橙色) | ||||||
|---|---|---|---|---|---|---|
| 白\黑 | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 60° 黄色 | ||||||
|---|---|---|---|---|---|---|
| 白\黑 | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 90° 黄绿色 | ||||||
|---|---|---|---|---|---|---|
| 白\黑 | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 120° 绿色 | ||||||
|---|---|---|---|---|---|---|
| 白\黑 | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 150° 绿青色 | ||||||
|---|---|---|---|---|---|---|
| 白\黑 | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 180° 青色 | ||||||
|---|---|---|---|---|---|---|
| 白\黑 | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 210° 青蓝色 | ||||||
|---|---|---|---|---|---|---|
| 白\黑 | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 240° 蓝色 | ||||||
|---|---|---|---|---|---|---|
| 白\黑 | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 270° 蓝洋红色 | ||||||
|---|---|---|---|---|---|---|
| 白\黑 | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 300° 洋红色 | ||||||
|---|---|---|---|---|---|---|
| 白\黑 | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 330° 洋红红色 | ||||||
|---|---|---|---|---|---|---|
| 白\黑 | 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 颜色时的测量白点。
从使用其他白点指定的颜色进行转换称为色适应变换(chromatic adaptation transform),它模拟了当我们适应新照明条件时人类视觉系统的变化。线性 Bradford 算法 [ICC](原始 Bradford 算法 [Bradford-CAT] 的简化版本)是工业标准的色适应变换,由于只是简单的矩阵乘法,计算起来非常容易。
CIE LCH 具有与 Lab 相同的 L 轴,但使用极坐标 C(色度,Chroma)和 H(色相,Hue),使其成为一个极坐标柱面坐标系。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 模型的发展旨在为 RGB 提供类似于 LCH 给 Lab 带来的易用性好处,但其准确性明显较低。
尽管 CIE Lab 和 LCH 的应用广泛,但已知存在一些问题。特别是:
- 色相线性
- 在蓝色区域(LCH 色相在 270° 和 330° 之间),视觉色相与 LCH 的预测结果存在偏差。绘制一组具有相同色相但色度不同的蓝色,本应位于从中性轴出发的一条直线上,却形成了一条曲线。换句话说,当饱和蓝色的色度逐渐降低时,它会明显地变得偏紫。
- 色相均匀性
- 虽然 LCH 中的色相总体上是均匀分布的(远优于 HSL 或 HWB),但均匀性并不完美。
- 高色度差异的过度预测
- 对于高色度颜色,色度变化比对中性颜色更容易被察觉。
这些缺陷影响了诸如创建均匀间隔的渐变、将颜色从一个色空间映射到更小的色空间以及计算两种颜色之间的视觉差异等应用。
为了弥补这一点,用于预测两种颜色之间视觉差异(delta E)的公式随着时间的推移变得更加精确(但也变得更加复杂,难以计算)。目前的工业标准公式 delta E 2000 在缓解部分 Lab 和 LCH 问题方面效果良好。示例实现见 § 20.1 ΔE2000。
然而,这并不能解决色相弯曲问题。
9.2. Oklab 和 OkLCh
本节不具有规范性。
测试
本节为非规范性内容,无需测试。
最近,开发了一种改进的类 Lab 空间 Oklab [Oklab]。相应的极坐标形式称为 OkLCh。它通过对大量视觉相似颜色数据集进行数值优化而产生,与 CIE LCH 相比,改善了色相线性、色相均匀性和色度均匀性。
像 CIE Lab 一样,它有一个中央亮度 L 轴,通常写为 [0,1] 范围内的无单位数字;为了与 CSS 的其余部分兼容,可以写为百分比。100% 表示 L 值为 1.0。L=0% 或 0.0 是深黑(完全无光),而 L=100% 或 1.0 是漫反射白。
注意:与假设适应漫反射白的 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 空间中是简单的距离(平方和的平方根)。虽然简单,但在 § 20.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> 分量,由斜杠分隔,代表透明度分量。
如果 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。它的解释类似于 hsl() 的 <hue> 参数,但由于它们在感知上是均匀分布的,因此不会以相同的方式将色相映射到角度。相反,0deg 指向正“a”轴(朝向紫红色)(360deg、720deg 等也是如此);90deg 指向正“b”轴(朝向芥末黄),180deg 指向负“a”轴(朝向绿青色),270deg 指向负“b”轴(朝向天蓝色)。
有一个可选的第四个 <alpha-value> 分量,由斜杠分隔,代表透明度分量。
如果 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 不存在 Web 兼容性问题,它们是本规范版本中新增的内容,因此 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> 分量,由斜杠分隔,代表透明度分量。
如果 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。它的解释类似于 hsl() 和 lch() 的 <hue> 参数,但不会以相同的方式将色相映射到角度。0deg 指向正“a”轴(朝向紫红色)(360deg、720deg 等也是如此);90deg 指向正“b”轴(朝向芥末黄),180deg 指向负“a”轴(朝向绿青色),270deg 指向负“b”轴(朝向天蓝色)。
有一个可选的第四个 <alpha-value> 分量,由斜杠分隔,代表透明度分量。
如果 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 不存在 Web 兼容性问题,它们是本规范版本中新增的内容,因此 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 | display-p3-linear | 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> 或两者。
-
色空间采用的三个参数值(RGB 或 XYZ 值)。
色域外的颜色其分量值小于 0 或 0%,或大于 1 或 100%。这些并非无效,并保留用于中间计算;相反,为了显示,它们会在实际值确定时,使用相对色度意图(relative colorimetric intent)进行CSS 色域映射,将值(在显示器色空间中)带入 0/0% 到 1/100% 的范围内。
-
一个可选的斜杠分隔的 <alpha-value>。
color() 不存在 Web 兼容性问题,它是本规范版本中新增的内容,因此 color() 不支持使用逗号分隔所有参数的旧版颜色语法。在此函数中使用逗号是错误的。
如果指定的颜色可以显示(也就是说,它不是无效颜色且不是色域外),那么这就是 color() 函数的实际值。
如果指定的颜色是有效颜色但无法显示,则其实际值源自指定的颜色,并为显示进行CSS 色域映射。
在 LCH 中,该颜色为color ( rec20200.42053 0.979780 0.00579 );
在 display-p3 中,该颜色为lch ( 85.9017 % 166.116 138.207 );
并且在 display-p3 中属于色域外(红色和蓝色为负,绿色大于 1)。如果你有 display-p3 屏幕,该颜色color ( display-p3-0.350289 1.00707 -0.144209 );
- valid (有效的)
- 在色域内(对于 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 图像状态 显示参考(display-referred) 百分比 R、G 和 B 的允许值 百分比参考范围 对于 R、G、B:0% = 0.0,100% = 1.0
c 是伽马编码的红、绿或蓝分量。cl 是相应的线性光分量。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 )); } LCH 中 sRGB 色空间的视觉化。显示了原色和二次色。
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 图像状态 显示参考(display-referred) 百分比 R、G 和 B 的允许值 百分比参考范围 对于 R、G、B:0% = 0.0,100% = 1.0 cl
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 图像状态 显示参考(display-referred) 百分比 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 (在线测试) (源代码)
- 2d.color.space.p3.fillText.shadow.html (在线测试) (源代码)
- 2d.color.space.p3.strokeText.html (在线测试) (源代码)
- 2d.color.space.p3.to.p3.html (在线测试) (源代码)
- 2d.color.space.p3.to.srgb.html (在线测试) (源代码)
- 2d.color.space.p3.toBlob.p3.canvas.html (在线测试) (源代码)
- 2d.color.space.p3.toBlob.with.putImageData.html (在线测试) (源代码)
- 2d.color.space.p3.toDataURL.jpeg.p3.canvas.html (在线测试) (源代码)
- 2d.color.space.p3.toDataURL.p3.canvas.html (在线测试) (源代码)
- 2d.color.space.p3.toDataURL.with.putImageData.html (在线测试) (源代码)
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 | |
| 图像状态 | 显示参考(display-referred) | |
| 百分比 | R、G 和 B 的允许值 | |
| 百分比参考范围 | 对于 R、G、B:0% = 0.0,100% = 1.0 | |
cl= c;
c 是红、绿或蓝分量。cl 是相应的线性光分量,它们是一致的。
为了避免条带伪影,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 图像状态 显示参考(display-referred) 百分比 R、G 和 B 的允许值 百分比参考范围 对于 R、G、B:0% = 0.0,100% = 1.0 以 LCH 表示的 A98 色彩空间可视化。显示了原色和二次色(但在 sRGB 中,并非正确的颜色)。作为对比,sRGB 的原色和二次色也以虚线圆圈显示。a98 原色具有更高的饱和度(Chroma),尤其是黄色、绿色和青色。
测试
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 黑色亮度 见正文 图像状态 显示参考(display-referred) 百分比 R、G 和 B 的允许值 百分比参考范围 对于 R、G、B:0% = 0.0,100% = 1.0
c 是伽马编码的红、绿或蓝分量。cl 是相应的线性光分量。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 ); } 以 LCH 表示的 prophoto-rgb 色彩空间可视化。显示了原色和二次色(但在 sRGB 中,并非正确的颜色)。作为对比,sRGB 的原色和二次色也以虚线圆圈显示。prophoto-rgb 的原色和二次色具有更高的饱和度,但这种超广色域的很大一部分并不对应于物理上可实现的颜色。
测试
10.8. 预定义 ITU-R BT.2020-2 色彩空间:rec2020 关键字
- rec2020
- rec2020 [Rec.2020] 色彩空间接受三个数值参数,分别表示颜色的红、绿、蓝分量。色域内的颜色,其所有三个分量都在 [0, 1] 范围内(在视频术语中为“全范围”)。ITU Reference 2020 用于超高清、4k 和 8k 电视。
这些原色在物理上是可以实现的,但很难实现,因为它们非常接近光谱轨迹。
当前的显示器无法重现 rec2020 的全色域。随着显示器的改进,预计覆盖范围会随时间增加。
它具有以下特性:
x y 红色色度 0.708 0.292 绿色色度 0.170 0.797 蓝色色度 0.131 0.046 白色色度 D65 传递函数 伽马 2.40,来自 [REC_BT.1886] 图像状态 显示参考(display-referred) 百分比 R、G 和 B 的允许值 百分比参考范围 对于 R、G、B:0% = 0.0,100% = 1.0 以 LCH 表示的 rec2020 色彩空间可视化。显示了原色和二次色(但在 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
- 如果需要,使用线性 Bradford 变换将 D65 白点(由 sRGB、display-p3、a98-rgb 和 rec2020 使用)转换为 Lab 中使用的 D50 白点。prophoto-rgb 已经具有 D50 白点。
- 将经过 D50 适应的 XYZ 转换为 Lab
转换为 Oklab 类似,但色度适应步骤仅对 prophoto-rgb 是必需的。
- 从伽马编码的 RGB 转换为线性光 RGB(撤销伽马编码)
- 从线性 RGB 转换为 CIE XYZ
- 如果需要,使用线性 Bradford 变换将 D50 白点(由 prophoto-rgb 使用)转换为 Oklab 中使用的 D65 白点。
- 将经过 D65 适应的 XYZ 转换为 Oklab
这些转换的示例 JavaScript 代码位于 § 19 色彩转换示例代码中。
10.11. 将 Lab 或 Oklab 转换为预定义的 RGB 色彩空间
从 Lab 转换为诸如 display-p3 或 rec2020 等预定义空间也需要多个步骤,并且同样,实际上除最后一步外,所有步骤都是线性计算,可以合并。
- 将 Lab 转换为 (经过 D50 适应的) XYZ
- 如果需要,使用线性 Bradford 变换将 D50 白点(由 Lab 使用)转换为 sRGB 和大多数其他 RGB 空间中使用的 D65 白点。prophoto-rgb 不需要此步骤。
- 从 (经过 D65 适应的) CIE XYZ 转换为线性 RGB
- 从线性光 RGB 转换为 RGB(执行伽马编码)
从 Oklab 转换类似,但色度适应步骤仅对 prophoto-rgb 是必需的。
- 将 Oklab 转换为 (经过 D65 适应的) XYZ
- 如果需要,使用线性 Bradford 变换将 D65 白点(由 Oklab 使用)转换为 prophoto-rgb 中使用的 D50 白点。
- 从 (经过 D65 适应的) CIE XYZ 转换为线性 RGB
- 从线性光 RGB 转换为 RGB(执行伽马编码)
这些转换的示例 JavaScript 代码位于 § 19 色彩转换示例代码中。
实现者可以选择以其他方式实现这些步骤(例如,使用具有相对比色渲染意图的 ICC 配置文件),前提是对于源色域和目标色域内的颜色,结果相同。
10.12. 在预定义 RGB 色彩空间之间转换
从一种预定义 RGB 色彩空间转换到另一种需要多个步骤,其中一个步骤仅在白点不同时需要。要从 src 转换为 dest
- 从伽马编码的 srcRGB 转换为线性光 srcRGB(撤销伽马编码)
- 从线性 srcRGB 转换为 CIE XYZ
- 如果 src 和 dest 具有不同的白点,使用线性 Bradford 变换将 XYZ 值从 srcWhite 转换为 destWhite。
- 从 CIE XYZ 转换为线性 destRGB
- 从线性光 destRGB 转换为 destRGB(执行伽马编码)
预定义 RGB 色彩空间转换的示例 JavaScript 代码位于 § 19 色彩转换示例代码中。
10.13. 简单的 Alpha 合成
在进行绘制时,实现必须根据 [Compositing] 中 第 5.1 节 简单 alpha 合成 的规则处理 alpha。
11. 颜色转换
测试
本节提供后续使用的算法,无需测试。
颜色可以从一个色彩空间转换到另一个,只要没有色域映射,并且每个色彩空间都能表示超出色域的颜色(对于 RGB 空间,这意味着传递函数定义在扩展范围内),那么(受限于数值精度和舍入误差)这两种颜色将看起来相同,并代表相同的颜色感觉。
- 将 src 中的任何 无效(powerless)分量更改为 缺失分量
- 如果 src 处于 圆柱极坐标色彩表示中,将 col1 转换为相应的 矩形正交色彩表示,并令其为新的 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> 值
当两个 <color> 值使用以下算法比较为相等时,它们是 等价颜色。此比较被用于例如 style() 容器查询 [CSS-CONDITIONAL-5] 和 CSS 过渡 [CSS-TRANSITIONS-1],以确定颜色值是否发生了变化。
给定两个 <color> 值 C1 和 C2,当且仅当以下算法返回 true 时,它们是 等价颜色
- 对于 C1 和 C2 中的每一个,将任何 无效分量转换为 缺失分量。
- 如果 C1 和 C2 共享相同的 <color-space>
- 逐个比较它们的分量,包括 alpha 通道。缺失分量仅等于另一个 缺失分量。如果两个数值分量的差值不超过小的实现定义的 ε,则认为它们相等。
- 当且仅当所有分量比较结果相等时,返回 true。
- 否则,C1 和 C2 处于不同的 <color-space> 中。如果任一颜色具有至少一个 缺失分量,则返回 false。
- 否则,两种颜色都没有任何 缺失分量。将 C1 和 C2 都转换为 oklab,当且仅当转换后颜色的所有分量(包括 alpha)比较结果相等时返回 true,使用标准化 Oklab ε 0.00001。
注意: 以不同 <color-space> 表示但比色法完全相同的两种颜色(例如 red 和 color(srgb 1 0 0))根据此算法的第 4 步是 等价颜色,因为它们会转换为相同的 oklab 值。
出于此比较的目的,rgb()、rgba()、hsl()、hsla()、hwb()、十六进制颜色、命名颜色 和 系统颜色 都被视为处于 srgb <color-space> 中。
13. 颜色插值
颜色插值发生在渐变、合成、滤镜、过渡、动画以及颜色混合和颜色修改函数中。
两个 <color> 值之间的插值通过执行以下步骤完成
- 检查两种颜色是否存在 同类分量(analogous components) 和 同类集(analogous sets),这些将被 携带向前(carried forward)
- 为转换准备两种颜色。这会将任何 无效(powerless) 分量更改为 缺失 值
- 将它们都转换为给定的色彩空间,下文将其称为 插值色彩空间。
- (如果需要)将 携带向前 的值重新插入到转换后的颜色中
- (如果需要)修复色相,具体取决于所选的 <hue-interpolation-method>
- 将颜色分量更改为 预乘(premultiplied) 形式
- 线性地分别插值颜色计算值中的每个分量
- 撤销 预乘
可以插值到 currentcolor 或从中进行插值。为此目的使用的数值是使用值(used value)。
13.1. 插值色彩空间
CSS 中的各种特性依赖于颜色插值。
混合或以其他方式组合颜色会根据所使用的 插值色彩空间 而产生不同的结果。因此,不同的色彩空间可能更适合每种插值用例。
-
在某些情况下,需要物理混合两种彩色光的结果。在这种情况下,CIE XYZ、display-p3-linear 或 srgb-linear 色彩空间是合适的,因为它们与光强度呈线性关系。
-
最后,与遗留 Web 内容的兼容性可能是最重要的考虑因素。这里选择的是既非线性光也非感知均匀的 sRGB 色彩空间,尽管它会产生较差的结果(过度暗淡或灰暗的混合)。
这些特性统称为 宿主语法(host syntax)。
为了允许宿主语法指示 插值色彩空间,本规范导出了一个 color-interpolation-method 产品。它本身不被本规范使用,仅供其他规范使用;例如请参见 CSS Images 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 中通过具有相同名称的函数语法,或者(如果没有此函数)通过 color() 函数中的对应 <ident> 表示。
测试
- 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。
对于 <polar-color-space>,如果未指定 <hue-interpolation-method>,则默认为 shorter。
然而,用户代理 必须 在伽马编码的 sRGB 空间中处理遗留 sRGB 颜色格式(十六进制颜色、命名颜色、rgb()、hsl() 或 hwb() 以及等效的包含 alpha 的形式)之间的插值。这提供了 Web 兼容性;遗留 sRGB 内容默认在 sRGB 空间中插值。
这也意味着作者可以通过对至少一种颜色使用非遗留的 color(srgb r g b) 形式,或者显式指定 插值色彩空间,来选择加入更好的插值,即使是在 sRGB 颜色之间。
如果待插值的颜色超出了 插值色彩空间 的色域,那么一旦转换为该空间,它们将包含范围外的值。
这些不会被裁剪;数值必须按原样进行插值。
13.2. 缺失分量的插值
在将两种颜色转换为 插值色彩空间 的过程中,任何 缺失分量 都将替换为值 0。
因此,插值两种颜色的第一阶段是分类输入颜色中的任何 缺失分量,并将它们与 插值色彩空间 的分量进行比较。如果发现任何作为 缺失分量 的 同类分量,它们将被 携带向前,并在预乘之前、线性插值发生之前重新插入到转换后的颜色中。
类似地,如果原始颜色中 同类集(定义如下)中的每个分量都是 缺失分量,它们都会被 携带向前 并重新插入到 插值色彩空间 的相应 同类集 中。
Alpha 是其自身的同类分量(alpha 与 alpha 是同类的),因此 缺失 alpha 的 携带向前 方式与任何其他 缺失分量 完全相同。
同类分量 如下
| 类别 | 组件 |
|---|---|
| 红色 | r,x |
| 绿色 | g,y |
| 蓝色 | b,z |
| 亮度(Lightness) | L |
| 彩色度(Colorfulness) | C, S |
| 色相(Hue) | H |
| 对立色 a | a |
| 对立色 b | b |
| Alpha | alpha |
注意: 出于此分类的目的,XYZ 空间被视为超饱和 RGB 空间。此外,尽管饱和度(Saturation)依赖于亮度,但在此处与 Chroma 归为同一类别。HWB 的白度(Whiteness)和黑度(Blackness)分量在其他色彩空间中没有对应物。
此外,对于任何两个色彩空间,移除所有 同类分量 后剩余的分量构成一个 同类集(analogous set)。
注意: 由于当没有单独的 同类分量 时,所有颜色分量的完整集合就是剩余的 同类集,因此所有颜色分量都 缺失 的颜色在 插值色彩空间 中也将使所有颜色分量 缺失。
lab ( 50 % none none) 转换为 LCH 进行插值时,亮度(Lightness)是单独 同类 的。剩余分量(Lab 中的 a 和 b;LCH 中的 C 和 H)形成一个 同类集。由于 a 和 b 都是 缺失 的,C 和 H 都作为 缺失 携带向前,得到 lch ( 50 % none none) 而不是 lch ( 50 % 0 0 ) 。类似地,转换到 OKLab 进行插值的 会产生 ,因为这三个颜色分量形成了一个 同类集(sRGB 和 OKLab 之间没有单独的 同类分量)。
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 )
如果携带向前的 缺失分量 是 alpha,颜色必须使用此携带向前的值进行 预乘,而不是使用颜色转换产生的零值。
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]。
如果两种颜色都 缺少 给定分量,则插值颜色也将 缺少 该分量。
13.3. 使用 Alpha 插值
当待插值的颜色不是完全不透明时,它们首先按如下方式 预乘(premultiplied)
-
如果 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)。
线性插值这些颜色的中点,沿 shorter(较短)色相弧(默认)将是 [29.4365% 40.563 31.82],当撤销预乘时,其 alpha 值为 0.5,即 lch(58.873% 81.126 31.82) / 0.5)。
有关极坐标和矩形色彩空间的 alpha 预乘和撤销预乘的 JavaScript 示例代码,请参见 § 19 色彩转换示例代码。
13.4. 色相插值
对于具有色相角的颜色函数(LCH、HSL、HWB 等),有多种插值方式。由于大于 360° 的弧很少是预期的,因此色相角在插值之前会被修正,使得分量插值在小于 360°(通常小于 180°)的范围内进行。
宿主语法可以为色相插值指定以下任一算法(以下角度以度为单位,但无论其如何指定,逻辑都是相同的)。指定色相插值策略已经是 <color-interpolation-method> 语法的一部分,通过 <hue-interpolation-method> 标记指定。
除非另有说明,如果宿主语法未选择特定的色相插值算法,则默认为 shorter。
注意: 提醒一下,如果插值颜色不在指定的插值色彩空间中,那么转换它们会将任何 无力分量 (powerless components) 变成 缺失分量 (missing components)。
13.4.1. shorter
色相角经过插值,取起始色相和结束色相之间较短的那条弧。
角度经过调整,使得 θ₂ - θ₁ ∈ [-180, 180]。伪代码 JavaScript 为
if( θ₂ - θ₁ >180 ) { θ₁ +=360 ; } else if( θ₂ - θ₁ <-180 ) { θ₂ +=360 ; }
13.4.2. longer
色相角经过插值,取起始色相和结束色相之间较长的那条弧。
角度经过调整,使得 θ₂ - θ₁ ∈ {(-360, -180], [180, 360)}。伪代码 JavaScript 为
if( 0 < θ₂ - θ₁ <180 ) { θ₁ +=360 ; } else if( -180 < θ₂ - θ₁ <=0 ) { θ₂ +=360 ; }
13.4.3. increasing
色相角经过插值,使得从第一种颜色过渡到第二种颜色时,角度始终增加。如果角度增加到 360,它会被重置为零,然后继续增加。
根据两个角度之间的差异,这看起来要么与 shorter(较短)相同,要么与 longer(较长)相同。但是,如果正在对其中一个色相角进行动画处理,且色相角差值经过 180 度,插值将不会翻转到另一条弧线。
然而,如果第二种颜色的色相被动画处理为 oklch(0.7 0.1 230),插值的中点将是 (30 + 230) * 0.5 = 130 度,继续沿相同的递增方向进行,得到另一种绿色 oklch(0.6 0.1 130),而不是在动画过程中途翻转到对角颜色。
角度经过调整,使得 θ₂ - θ₁ ∈ [0, 360)。伪代码 JavaScript 为
if( θ₂ < θ₁) { θ₂ +=360 ; }
13.4.4. decreasing
色相角经过插值,使得从第一种颜色过渡到第二种颜色时,角度始终减少。如果角度减少到 0,它会被重置为 360,然后继续减少。
根据两个角度之间的差异,这看起来要么与 shorter(较短)相同,要么与 longer(较长)相同。但是,如果正在对其中一个色相角进行动画处理,且色相角差值经过 180 度,插值将不会翻转到另一条弧线。
然而,如果第二种颜色的色相被动画处理为 oklch(0.7 0.1 230),插值的中点将是 (30 + 360 + 230) * 0.5 = 310 度,继续沿相同的递减方向进行,得到另一种紫色 oklch(0.6 0.1 310),而不是在动画过程中途翻转到对角颜色。
角度经过调整,使得 θ₂ - θ₁ ∈ (-360, 0]。伪代码 JavaScript 为
if( θ₁ < θ₂) { θ₁ +=360 ; }
14. 色域映射
14.1. 色域映射简介
注意: 本节为文档中其他地方描述的具体要求提供了重要的上下文。
本节为非规范性内容
测试
本节为非规范性内容,无需测试。
当源色彩空间中的颜色转换为具有更小色域的目标色彩空间时,某些颜色会超出目标色域。
对于中间色彩计算,这些超出色域的值会被保留。但是,如果目标是显示设备(屏幕或打印机),则必须将超出色域的值转换为色域内的颜色。
色域映射是寻找一种视觉外观变化最不令人反感的色域内颜色的过程。
一些超出色域的颜色对应于现实世界的颜色(它们可以在物理上再现),而另一些是虚构的颜色(它们位于光谱轨迹之外,因此需要超过 100% 的单一波长),无法在物理上实现。这些颜色往往来自诸如“使该颜色饱和度提高 100 倍”之类的计算。
这四个角中的三个位于光谱轨迹之外,因此对应于虚构的颜色。
14.1.1. 剪切 (Clipping)
最简单且最不可取的方法是将分量值直接剪切到可显示范围内。
由于该方法的主要动机是速度,因此剪切通常在伽马编码值上执行,而不是将它们转换为线性光。
这会改变三种原色的比例(对于 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 色彩空间后,负的蓝色值显示该颜色超出色域:,在线性光下是 。
将伽马编码的 p3 颜色剪切到 p3 色域,得到 ,在线性光下是 ,作为比较,它是 。
这是一个不错的结果;色相角和亮度几乎没有变化,但色度有所降低,正如预期的那样。
在线性红、绿、蓝分量的百分比方面,红色和绿色相同,而蓝色高出 -1.46%。
color ( prophoto-rgb 0.2 1.0 0.1 ) ,它是 oklch ( 85.07 % 0.4873 151.4 ) 转换为 p3 色彩空间后,该颜色严重超出色域:,在线性光下是 。
将伽马编码的 p3 颜色剪切到 p3 色域,得到 ,在线性光下同样是 (完全为 0 或 1 的分量值不受伽马编码的影响),作为比较,它是 。
效果不太好,但在视觉上仍可接受。在这里色相受到的影响较大,有 5.8° 的变化。
在线性红、绿、蓝分量的百分比方面,红色高出 57%,绿色降低了 6.7%,蓝色高出 23%。
14.1.2. 最接近颜色 (MINDE)
一种更好的方法是在感知均匀的色彩空间中,通过寻找最近的色域内颜色(所谓的最小 ΔE 或 MINDE)来进行映射。显然,该技术的成功取决于色域映射色彩空间的均匀程度以及所使用的 deltaE 函数的预测准确性。
然而,进行色域映射时,色相的变化是特别令人反感的;色度的变化更可容忍,亮度的微小变化也可以接受,特别是如果替代方案是更大的色度降低的话。MINDE 在每个维度上相等地加权变化,因此效果并非最佳。
14.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 )
14.1.4. 过度色度降低
此外,对于某些颜色,这种简单的 MINDE 方法会产生次优结果,主要是像黄色和青色这样非常亮的颜色,如果色域边界的上边缘很平坦,甚至是轻微的凹面。恒定亮度线可能会刚好从色域边界上方掠过,在这些情况下导致色度过低。
色彩空间的选择会影响色域映射颜色的可接受性。
color ( display-p3 1 1 0 ) 在 CIE LCH 色彩空间中逐渐降低了色度。color ( display-p3 1 1 0 ) 也逐渐降低了色度,但这次是在 OkLCh 色彩空间中。14.1.5. 局部剪切的色度降低
简单的色度降低算法可以改进:在每一步,计算当前映射颜色与该颜色的剪切版本之间的色差。如果当前颜色在色域边界之外,但它与剪切版本之间的色差低于恰可察觉差异 (JND) 的阈值,则将颜色的剪切版本作为映射结果返回。实际上,这在每个阶段都进行 MINDE 映射,但受限使得色相和亮度的变化非常小,因此无法察觉。
color ( display-p3 1 1 0 ) 在 CIE LCH 色彩空间中逐渐降低色度,并进行了局部剪切修正。color ( display-p3 1 1 0 ) 也逐渐降低了色度,但这次是在 OkLCh 色彩空间中,并进行了局部剪切修正。14.1.6. 感知均匀性的偏差:色相曲率
即使使用 deltaE2000 距离度量,在 CIE LCH 色彩空间中进行色域映射,已知对于色相范围 270° 到 330° 的颜色,会产生具有明显色相偏移的次优结果。
使用 OkLCh 色彩空间和 deltaEOK 距离度量可以在所有色相角下避免此问题。
14.2. CSS 色域映射到 RGB 目标
测试
颜色的实际值不会暴露给脚本,这使得在自动化方式下进行测试变得困难。
三种 CSS 色域映射算法 适用于超出 RGB 显示器色域的单个标准动态范围 (SDR) CSS 颜色,因此需要进行 css 色域映射。
实现可以根据其质量和运行时效率权衡选择这三种算法中的任何一种,并且必须在 CSS 要求进行色域映射的任何地方使用其所选算法。
它们都实现了相对比色意图,因此目标色域内的颜色保持不变。
注意: 其他情况,特别是映射到最大黑电平显著高于零的打印机色域时,将需要不同的算法来对齐相应的黑点和白点,这将导致在降低色度时,极亮和极暗颜色的亮度发生变化。
注意: 这些算法用于单个、独特的颜色;对于彩色图像,其中相邻像素之间的关系很重要且目的是保留细节和纹理,感知渲染意图更合适,在这种情况下,目标色域内的颜色可能会改变。
所有三种 CSS 色域映射算法都旨在 OkLCh 色彩空间中进行恒定亮度、恒定色相的色度降低。
对于在亮度轴上超出范围的颜色,如果亮度大于或等于 1.0,则在目标色彩空间中返回白色,而如果亮度小于或等于 0.0,则在目标色彩空间中返回黑色。
14.2.1. 带有局部 MINDE 的二分查找色域映射
对于这种二分查找算法,所使用的色差公式是 deltaEOK。使用了 local-MINDE 改进。在搜索的每一步,计算当前映射颜色与该颜色的剪切版本之间的 deltaEOK。
如果当前颜色超出色域边界,但它与剪切版本之间的 deltaEOK 低于恰可察觉差异 (JND) 的阈值,则将剪切版本作为映射结果返回。这在产生无明显的色相偏移方面效果良好,并避免了在凹形色域表面附近过度的色度降低,但计算可能密集。
对于 OkLCh 色彩空间,一个 JND 是 0.02 的 OkLCh 差异。
注意: 在亮度分量范围为 0 到 100 的 CIE Lab 色彩空间中,使用 deltaE2000,一个 JND 为 2。由于 Oklab 和 OkLCh 中的亮度范围为 0 到 1,使用 deltaEOK,一个 JND 小 100 倍。
注意: 出于实验和比较实现的目的,带有局部 MINDE 的二分查找算法的实现可在 Coloraide 库(Python 版)[Coloraide-MINDE] 和 color.js 库(JavaScript 版)[colorjs-MINDE] 中找到。
14.2.2. 带有局部 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 的色域内,则返回 true。对于 HSL 和 HWB,如果颜色在 sRGB 的色域内,则返回 true。
- 如果 inGamut(origin_OkLCh) 为 true,将 origin_OkLCh 转换为 destination 并将其作为色域映射后的颜色返回
- 否则,设 delta(one, two) 为一个函数,返回颜色 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 为 0
- 设置 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 作为色域映射后的颜色
14.2.3. EdgeSeeker 色域映射
EdgeSeeker 算法是一种基于几何和查找表的方法,最初由 Alexey Ardov 为 color.js 库开发 [colorjs-EdgeSeeker]。
对于任何给定的色相,色域边界切片表示为一条弯曲的顶部部分和一条线性的底部部分,在色相的最高色度点连接。
为了初始化该算法,对于给定的目标 RGB 空间,构建一个包含每个色相切片上最高色度 Oklch 颜色的查找表 (LUT)。然后使用最接近的 LUT 值之间的线性插值来估计每个要色域映射颜色的精确色相的最高色度颜色。
然后计算恒定亮度射线与色域边界的交点,这对于边界的下部(线性)部分很快,对于上部(弯曲)部分也相当快。
这给出了很好的结果,但代价是 LUT 的内存开销。
14.2.4. EdgeSeeker 色域映射的伪代码示例
14.2.5. 射线追踪色域映射
射线追踪算法是一种用于 RGB 色域映射的几何方法,用于在保持亮度不变的情况下快速降低色度。它最初由 Isaac Muse 为 Coloraide Python 库开发 [Coloraide-Ray-Trace]。
要映射的颜色首先被转换为 Oklch,然后生成该颜色的消色差版本,它将成为中性轴锚点。这两个颜色然后被转换为目标 RGB 空间的线性光版本。
因为色域边界现在是一个轴对齐的立方体,所以寻找交点更快。
一条射线从 RGB 立方体的内部,从锚点投射到当前颜色。然后找到这条路径与 RGB 色域表面的交点;这是色域映射颜色的第一近似值。
由于 RGB 空间不是感知均匀的,因此恒定色相、恒定亮度射线实际上是 RGB 空间中的一条曲线路径。
第一近似值被转换回 Oklch,通过将该点投影回色度降低路径上,来纠正感知色彩空间中的颜色,从而校正颜色的色相和亮度。校正后的颜色成为新的当前颜色,并且应该是降低色度线上更接近的颜色。
此过程重复(最多再重复三次),每次都在路径上找到更好、更接近的颜色。最后,使用简单的剪切来解决浮点数学错误。
结果与使用低 JND 的带有局部 MINDE 的二分查找相当,但解析速度快得多,并且在更可预测、一致的时间内完成。
图片版权所有 Isaac Muse。
注意: 出于实验和比较实现的目的,射线追踪的实现可在 Coloraide 库(Python 版)[Coloraide-Ray-Trace] 和 color.js 库(JavaScript 版)[colorjs-RayTrace] 中找到。
14.2.6. 射线追踪色域映射的伪代码示例
- 如果 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
- for (i=0; i<4; i++)
- if (i > 0)
- 设 current_OkLCh 为 origin_rgb 转换为 OkLCh 后的结果
- 设 current_OkLCh 的亮度为 l_origin
- 设 current_OkLCh 的色相为 h_origin 3
- 设 origin_rgb 为 current_OkLCh 转换为 destination 的线性光形式后的结果
- 投射射线 从 start = anchor 到 end = origin_rgb,并设 intersection 为该射线与色域边界的交点
- 如果未找到交点,设 origin_rgb 为 last 并退出循环 5
- 如果 (i > 0) AND (origin_rgb 的每个分量都在 low 和 high 之间),则设 anchor 为 origin_rgb 4
- 设 origin_rgb 为 intersection
- 设 last 为 intersection
- if (i > 0)
- 设 clip(color) 为一个函数,将 color 转换为 destination,将每个分量钳制到该分量的参考范围边界内,并返回结果
- 设置 clipped 为 clip(current)
- 返回 clipped 作为色域映射后的颜色
- 设 bmin 和 bmax 分别为具有色域下界和上界的 3 元素数组 6
- 设 tfar 为无穷大(或某个非常大的数字)
- 设 tnear 为负无穷大(或某个非常大的负数)
- 设 direction 为一个 3 元素数组
- for (i = 0; i < 3; i++)
- 设 a 为 start [i]
- 设 b 为 end [i]
- 设 d 为 b - a
- 设 direction [i] 为 d
- if 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)
- else if (a < bmin[i] or a > bmax[i])
- 返回 未找到交点
- if (tnear > tfar or tfar < 0)
- 返回 未找到交点
- if tnear < 0
- 设 tnear 为 tfar 7
- if tnear 是无限的(或匹配初始的非常大值)
- 返回 未找到交点
- for (i = 0; i < 3; i++)
- 设 result [i] 为 start [i] + direction [i] * tnear
- 返回 result
14.2.6.1. 射线追踪算法的脚注
- 假设最小值为 0,且所有通道具有相同的最小值。该值相对于单位类型应较小。64 位可以轻松达到 1e-14,但实际上 1e-6 就足够了。
- 1.0 表示色域内的最大通道值,且假设所有通道具有相同的最大值。
- 如果 current 颜色已偏离,这将把它放回色度降低曲线上。
- 这意味着 origin_rgb 在色域表面之下,因此我们将其用作更接近色域表面的锚点。
- 这是针对特定感知映射空间由于颜色极其广泛(超出可见光谱)而完全崩溃的灾难性故障提供的。预计 CSS 中的非虚构颜色永远不会触发此情况。
- 对于典型的 RGB 空间,其中色域边界对于每个分量为 0 和 1,这简化为一个单一的常数,而不是 3 元素数组。
- 倾向于在 start -> end 方向上的第一个交点。
15. 解析 <color> 值
除非特定属性另有说明,指定 (specified) 的颜色被解析为 计算 (computed) 颜色,然后进一步解析为如下所述的 使用 (used) 颜色。
<color> 的 解析值 (resolved value) 是其 使用值 (used value)。
测试
15.1. 解析 sRGB 值
这适用于
它不适用于
-
使用 srgb 或 srgb-linear 色彩空间的 color() 值。
如果 sRGB 颜色是由作者明确指定为 命名颜色 或 系统颜色,则 声明值 (declared value) 是该被转换为 ASCII 小写 的命名或系统颜色。计算值和使用值是对应的 sRGB 颜色,与指定的 alpha 分量配对(在钳制到 [0, 1] 后,未指定时默认为不透明)。
否则,声明值、计算值和使用值是对应的 sRGB 颜色,与指定的 alpha 分量配对(在钳制到 [0, 1] 后,未指定时默认为不透明)。
出于历史原因,当 sRGB 颜色中的 calc() 解析为单个值时,声明值序列化时不带 "calc(" ")" 包装。
同样出于历史原因,当 calc() 简化为单个值时,颜色值被钳制到 [0.0, 255.0]。
这种钳制也处理了诸如 Infinity、-Infinity 和 NaN 之类的值,它们将分别钳制为 255、0 和 0。
测试
15.2. 解析 Lab 和 LCH 值
声明值、计算值和使用值是对应的 CIE Lab 或 LCH 颜色(在 L、C 和 H 钳制后),与指定的 alpha 分量配对(作为 <number>,而非 <percentage>;未指定时默认为不透明)。
尽管 a、b 和 C 的值理论上是无界的,但可能存在 实现定义的接近无穷大的值限制。
15.3. 解析 Oklab 和 OkLCh 值
声明值、计算值和使用值是对应的 Oklab 或 OkLCh 颜色(在 L、C 和 H 钳制后),与指定的 alpha 分量配对(作为 <number>,而非 <percentage>;未指定时默认为不透明)。
尽管 a、b 和 C 的值理论上是无界的,但可能存在 实现定义的接近无穷大的值限制。
15.4. 解析 color() 函数的值
声明值、计算值和使用值是指定 色彩空间 中的颜色,与指定的 alpha 分量配对(作为 <number>,而非 <percentage>;未指定时默认为不透明)。
对于在 xyz 色彩空间(它是 xyz-d65 色彩空间的别名)中指定的颜色,计算值和使用值位于 xyz-d65 色彩空间中。
尽管 r、g、b、x、y 和 z 的值理论上是无界的,但可能存在 实现定义的接近无穷大的值限制。
15.5. 解析其他颜色
这适用于 系统颜色(包括 <deprecated-color>)、transparent 和 currentcolor。
每个 <system-color> 关键字和 <deprecated-color> 关键字的声明值是其自身。计算值是其色彩空间中的对应颜色。然而,此类颜色不得被 强制颜色模式 (forced colors mode) 更改。
< button style = "color: ButtonText; background: ButtonFace" ></ button >
color 属性的声明值为 "ButtonText",而计算值可能是(例如) rgb(0, 0, 0)。
transparent 的声明值为 "transparent",而计算值和使用值是 透明黑色 (transparent black)。
currentcolor 关键字计算为自身。
在 color 属性中,currentcolor 的使用值是解析后的 继承值。在任何其他属性中,其使用值是相同元素上 color 属性的使用值。
注意: 这意味着如果 currentcolor 值被继承,它是作为关键字继承的,而不是作为 color 属性的值继承的,因此后代将使用它们自己的 color 属性来解析它。
< div > < p > Assume this example text is long enough to wrap on multiple lines.</ p > </ div >
和此 css
div{ color : forestgreen; text-shadow : currentColor; } p{ color : mediumseagreen; } p::firstline{ color : yellowgreen; }
第一行片段上继承属性 text-shadow 的使用值将是 yellowgreen。
测试
16. 序列化 <color> 值
本节更新并替换了 CSS 对象模型第 序列化 CSS 值 节中与序列化 <color> 值相关的部分。
在本节中,规范中使用的字符串及对应的字符如下。
| 字符串 (String) | 字符 |
|---|---|
| " " | 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 |
字符串 "." 应作为十进制分隔符,无论区域设置如何,且不得有千位分隔符。
对于支持 缺失分量 (missing color components) 的语法形式,值 none(等价于 NONE, nOnE 等)应以全小写形式序列化为字符串 "none"。
16.1. 序列化 alpha 值
这适用于任何可以接受可选 alpha 值的 <color> 值。它不适用于 opacity 属性。
如果 alpha 值在钳制到 [0, 1] 范围后为 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> 值以十进制表示,以 "." 字符作为十进制分隔符。前导零不得省略。末尾零必须省略。
例如,70% 的 alpha 值将被序列化为字符串 "0.7",它在十进制分隔符之前有一个前导零,"." 作为十进制分隔符(即使当前区域设置会使用其他字符,例如 ","),并且 "7" 之后的所有数字都为 "0" 且被省略。
alpha 值被保留的精度(以及序列化值中的小数位数)未在本规范中定义,但必须至少足以往返转换整数百分比值。因此,序列化值必须至少包含两位小数(除非末尾零已被删除)。值必须 向 +∞ 取整,而不是截断。
例如,12.3456789% 的 alpha 值可以被序列化为字符串 "0.12" 或 "0.123" 或 "0.1234" 或 "0.12346"(因为后面的数字是 6,所以将 5 的值向 +∞ 取整)或任何相同形式的更长的、取整后的序列化。
由于在有效范围之外指定的 <alpha-value> 在解析时被钳制,因此声明值将被钳制。但是,根据 CSS Values 4 § 10.12 范围检查,使用 calc() 指定的 <alpha-value> 在指定形式序列化时不被钳制;但计算值会被钳制。
16.2. 序列化 sRGB 值
以下 sRGB 值的序列化形式
源自 声明值。
因此,当序列化由作者设置为 CSS 命名颜色、系统颜色、deprecated-color 或 transparent 的属性值时,对于 声明值,保留 ASCII 小写 关键字值。对于计算值和使用值,使用相应的 sRGB 值。
因此,transparent 的序列化声明值是字符串 "transparent",而 transparent 的序列化计算值是字符串 "rgba(0, 0, 0, 0)"。
对于所有其他 sRGB 值,声明值、计算值和使用值是对应的 sRGB 值。
在序列化过程中,如果所选的序列化形式(如带逗号分隔符的 传统颜色语法,或 sRGB 值的 HTML 兼容序列化)无法表示 none 关键字,则任何 缺失 值都会被转换为 0。当至少有一个分量是 缺失 的,且该值可以用支持 none 的形式序列化时,会根据 § 16.2.2 CSS sRGB 值序列化 中描述的那样选择形式,以便 缺失分量 被保留为 none。
16.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,使用 CSS sRGB 值序列化,对于其他色彩空间,使用 <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)"。
16.2.2. CSS sRGB 值序列化
如果该值没有 缺失分量,则相应的 sRGB 值使用 rgb() 或 rgba() 形式(取决于(钳制后的)alpha 是否精确为 1),函数名称均使用 ASCII 小写。
为了兼容性,sRGB 分量值以 <number> 形式而非 <percentage> 序列化。同样出于兼容性,分量值以十进制形式序列化,范围为 [0-255],无论它们存储时的位深度如何。
如前所述,单位 alpha 值不会被显式序列化。同样出于兼容性,如果 alpha 精确为 1,则使用带有隐含 alpha 的 rgb() 形式;否则,使用带有显式 alpha 值的 rgba() 形式。
为了兼容性,使用带有逗号分隔符的传统形式;每个逗号后恰好有一个 ASCII 空格。这包括用于将 rgba() 的蓝色分量与 alpha 值分隔开的逗号(而非斜线)。
然而,带有逗号分隔符的 传统颜色语法 无法表示 none。如果该值至少有一个 缺失分量,则基于 声明值 的颜色函数,选择序列化形式以将这些分量作为 none 关键字保留。
-
对于 rgb() 和 rgba() 值(列表中唯一其语法接受 none 的 sRGB 形式;十六进制颜色、命名颜色、系统颜色、弃用颜色 和 transparent 没有参数语法,因此永远不会有 缺失分量),该值被序列化为 color() 函数,位于 srgb 色彩空间中,而不是现代以空格分隔的 rgb() 形式,即使该形式也会接受 none:"color(srgb" 后面跟一个空格,后面跟以空格分隔的三个非 alpha 分量列表(序列化为 [0, 1] 参考范围内的 <number>,如果 缺失 则为 none),后面(仅在 alpha 非 1 或 缺失 时)跟 " / " 和 alpha 分量(按照 alpha 规则 序列化,如果 缺失 则为 none),最后跟 ")"。
-
对于 hsl() 和 hsla() 值,该值使用现代(以空格分隔)hsl() 语法序列化,在存在 alpha 分量时其前有斜线。函数名称为 "hsl"(以 ASCII 小写 表示),无论该值是否使用 hsla() 别名编写。色相序列化为以度为单位的规范化 <number>,饱和度和亮度序列化为 <percentage>,alpha(仅在非 1 或 缺失 时包括)按照 alpha 规则 序列化;任何 缺失分量 序列化为 none 关键字。
-
对于 hwb() 值,该值使用现代(以空格分隔)hwb() 语法序列化,在存在 alpha 分量时其前有斜线。函数名称为 "hwb"(以 ASCII 小写 表示)。色相序列化为以度为单位的规范化 <number>,白度和黑度序列化为 <percentage>,alpha(仅在非 1 或 缺失 时包括)按照 alpha 规则 序列化;任何 缺失分量 序列化为 none 关键字。
注意: 这意味着包含 none 的 hsl() 或 hwb() 值通过其自身的颜色函数序列化进行往返,而不是降级为 rgba()(其传统形式无法表示 none),而包含 none 的 rgb() 值则通过 color(srgb …) 序列化。现代以空格分隔的 rgb() 形式本身可以表示 none,但 sRGB CSS 序列化 使用 color(srgb …) 来保持一致性,正如所有其他 色彩空间 以其非传统形式序列化一样。这与 CSS Color 5 § 11.2 序列化原点颜色 中定义的相对颜色语法行为一致。
hwb ( 740 deg 20 % 30 % /50 % )
首先会被规范化为
hwb ( 20 20 % 30 % /50 % )
然后转换为 sRGB 并序列化为
rgba ( 178.5 , 93.5 , 51 , 0.5 )
返回结果的精度在下文中有描述。
hwb ( 20 none30 % / none)
包含缺失颜色分量(白度和 alpha 均为 none),因此它不会通过 rgba() 进行序列化。相反,它使用现代的 hwb() 语法序列化为
hwb ( 20 none30 % / none)
保留每个 none 值。
注意:与 CSS Color 3 不同,rgb() 函数的参数类型为 <number>,而非 <integer>。因此,任何高于 8 位的精度都将通过小数部分来表示。
sRGB 分量值的保留精度(即序列化值中的有效位数)在本规范中未作定义,但必须至少足以保证 8 位值的往返转换。值必须向 +∞ 取整,而非截断。
注意:对于期望 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 颜色将以向后兼容的整数值进行序列化。
16.3. 序列化 Lab 和 LCH 值
lch() 和 lab() 值的序列化形式源自计算值,并使用 lab() 或 lch() 形式,函数名使用 ASCII 小写字母。
分量值以 10 进制序列化;L、a、b 和 C 分量值序列化为 <number>,根据需要使用 Lab 百分比参考范围或 LCH 百分比参考范围进行百分比到数字的转换;因此 0% L 映射为 0,100% L 映射为 100。必须使用单个 ASCII 空格字符 " " 作为分量值之间的分隔符。
任何分量值末尾的小数零必须省略;如果小数部分全为零,则小数点也必须省略。
lab() 分量值的保留精度(即序列化值中的有效位数)在本规范中未作定义,但由于其宽色域特性,必须至少足以保证 L 值在 0 到 100 之间、a 和 b 值在 ±127 之间以至少 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)"
16.4. 序列化 Oklab 和 OkLCh 值
oklch() 和 oklab() 值的序列化形式源自计算值,并使用 oklab() 或 oklch() 形式,函数名使用 ASCII 小写字母。
分量值以 10 进制序列化;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() 分量值的保留精度(即序列化值中的有效位数)在本规范中未作定义,但由于其宽色域特性,必须至少足以保证 L 值在 0 到 1(0% 到 100%)之间、a、b 和 C 值在 ±0.5 之间以至少 16 位精度进行往返转换;除非末尾的零已被省略,否则这将导致至少保留五位小数。(建议内部存储使用半精度浮点数或单精度浮点数)。值必须向 +∞ 取整,而非截断。
注意:在超宽色域空间中,a、b 和 C 值可能会超出 ±0.5。例如,prophoto-rgb 的绿色和蓝色原色超过了此范围,其 C 值分别为 0.526 和 1.413。
如前所述,单位 alpha 值不会被显式序列化。非单位 alpha 值必须显式序列化,并且必须使用字符串 " / "(一个 ASCII 空格,后跟正斜杠,再后跟一个空格)将最后一个颜色分量(b 或 C)值与 alpha 值分隔开。
16.5. 序列化 color() 函数值
color() 值的序列化形式源自计算值,并使用 color() 形式,函数名和色彩空间名称使用 ASCII 小写字母。
分量值以 10 进制序列化为 <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)"。
16.6. 序列化其他颜色
这适用于 currentcolor。
该值的序列化形式源自计算值,并使用 ASCII 小写字母表示颜色名称。
currentColor 的序列化形式为字符串 "currentcolor"。
17. 序列化 <opacity-value>
这适用于 opacity 属性。
如果透明度值的指定值与字面上的 <percentage-token> 匹配(即不使用 calc()),则应将其序列化为等效的 <number>(0% 映射为 0,100% 映射为 1)值。否则,透明度值的指定值应根据该语法的标准序列化规则进行序列化。
此 <number> 值以 10 进制表示,使用 "." 字符作为小数分隔符。前导零不得省略。末尾的零必须省略。
在序列化指定值时,超出 [0,1] 范围的透明度值会被保留,不会被截断。
透明度值的保留精度(即序列化值中的小数位数)在本规范中未作定义,但必须至少足以保证整数百分比值的往返转换。因此,序列化值必须至少包含两位小数(除非末尾的零已被移除)。值必须向 +∞ 取整,而非截断。
18. 默认样式规则
以下样式表仅供参考,不具规范性。实现可以将此样式表用作其 HTML 文档默认样式的一部分。
/* traditional desktop user agent colors for hyperlinks */ :link{ color : LinkText; } :visited{ color : VisitedText; } :active{ color : ActiveText; }
19. 颜色转换示例代码
本节不具有规范性。
测试
本节为非规范性内容,无需测试。
为了清晰起见,这里使用一个库进行矩阵乘法。(这比内联所有的乘法和加法更具可读性)。矩阵采用列优先顺序。
// Sample code for color conversions // Conversion can also be done using ICC profiles and a Color Management System // For clarity, a library is used for matrix multiplication (multiply-matrices.js) // standard white points, defined by 4-figure CIE x,y chromaticities 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-related functions function lin_sRGB( RGB) { // convert an array of sRGB values // where in-gamut values are in the range [0 - 1] // to linear light (un-companded) form. // https://en.wikipedia.org/wiki/SRGB // Extended transfer function: // for negative values, linear portion is extended on reflection of axis, // then reflected power function is used. 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) { // convert an array of linear-light sRGB values in the range 0.0-1.0 // to gamma corrected form // https://en.wikipedia.org/wiki/SRGB // Extended transfer function: // For negative values, linear portion extends on reflection // of axis, then uses reflected pow below that 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) { // convert an array of linear-light sRGB values to CIE XYZ // using sRGB's own white, D65 (no chromatic adaptation) 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) { // convert XYZ to linear-light 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-related functions function lin_P3( RGB) { // convert an array of display-p3 RGB values in the range 0.0 - 1.0 // to linear light (un-companded) form. return lin_sRGB( RGB); // same as sRGB } function gam_P3( RGB) { // convert an array of linear-light display-p3 RGB in the range 0.0-1.0 // to gamma corrected form return gam_sRGB( RGB); // same as sRGB } function lin_P3_to_XYZ( rgb) { // convert an array of linear-light display-p3 values to CIE XYZ // using D65 (no chromatic adaptation) // 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) { // convert XYZ to linear-light 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 functions function lin_ProPhoto( RGB) { // convert an array of prophoto-rgb values // where in-gamut colors are in the range [0.0 - 1.0] // to linear light (un-companded) form. // Transfer curve is gamma 1.8 with a small linear portion // Extended transfer function 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) { // convert an array of linear-light prophoto-rgb in the range 0.0-1.0 // to gamma corrected form // Transfer curve is gamma 1.8 with a small linear portion // TODO for negative values, extend linear portion on reflection of axis, then add pow below that 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) { // convert an array of linear-light prophoto-rgb values to CIE D50 XYZ // matrix cannot be expressed in rational form, but is calculated to 64 bit accuracy // see 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) { // convert D50 XYZ to linear-light 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 functions function lin_a98rgb( RGB) { // convert an array of a98-rgb values in the range 0.0 - 1.0 // to linear light (un-companded) form. // negative values are also now accepted 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) { // convert an array of linear-light a98-rgb in the range 0.0-1.0 // to gamma corrected form // negative values are also now accepted 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) { // convert an array of linear-light a98-rgb values to CIE XYZ // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html // has greater numerical precision than section 4.3.5.3 of // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf // but the values below were calculated from first principles // from the chromaticity coordinates of R G B W // see 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) { // convert XYZ to linear-light 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-related functions function lin_2020( RGB) { // convert an array of rec2020 RGB values in the range 0.0 - 1.0 // to linear light (un-companded) form. // Reference electro-optical transfer function from Rec. ITU-R BT.1886 Annex 1 // with b (black lift) = 0 and a (user gain) = 1 // defined over the extended range, not clamped 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) { // convert an array of linear-light rec2020 RGB in the range 0.0-1.0 // to gamma corrected form // Reference electro-optical transfer function from Rec. ITU-R BT.1886 Annex 1 // with b (black lift) = 0 and a (user gain) = 1 // defined over the extended range, not clamped 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) { // convert an array of linear-light rec2020 values to CIE XYZ // using D65 (no chromatic adaptation) var M= [ [ 63426534 / 99577255 , 20160776 / 139408157 , 47086771 / 278816314 ], [ 26158966 / 99577255 , 472592308 / 697040785 , 8267143 / 139408157 ], [ 0 / 1 , 19567812 / 697040785 , 295819943 / 278816314 ], ]; // 0 is actually calculated as 4.994106574466076e-17 return multiplyMatrices( M, rgb); } function XYZ_to_lin_2020( XYZ) { // convert XYZ to linear-light 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); } // Chromatic adaptation function D65_to_D50( XYZ) { // Bradford chromatic adaptation from D65 to D50 // The matrix below is the result of three operations: // - convert from XYZ to retinal cone domain // - scale components from one reference white to another // - convert back to XYZ // see 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 chromatic adaptation from D50 to D65 // See 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 and LCH function XYZ_to_Lab( XYZ) { // Assuming XYZ is relative to D50, convert to CIE Lab // from CIE standard, which now defines these as a rational fraction var ε= 216 / 24389 ; // 6^3/29^3 var κ= 24389 / 27 ; // 29^3/3^3 // compute xyz, which is XYZ scaled relative to reference white var xyz= XYZ. map(( value, i) => value/ D50[ i]); // now compute 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 in range [0,100]. For use in CSS, add a percent } function Lab_to_XYZ( Lab) { // Convert Lab to D50-adapted 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= []; // compute f, starting with the luminance-related term f[ 1 ] = ( Lab[ 0 ] + 16 ) / 116 ; f[ 0 ] = Lab[ 1 ] / 500 + f[ 1 ]; f[ 2 ] = f[ 1 ] - Lab[ 2 ] / 200 ; // compute 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 ) / κ]; // Compute XYZ by scaling xyz by reference white 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 )); // Chroma 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 is still L chroma, // Chroma hue// Hue, in degrees [0 to 360) ]; } function LCH_to_Lab( LCH) { // Convert from polar form return [ LCH[ 0 ], // L is still L LCH[ 1 ] * Math. cos( LCH[ 2 ] * Math. PI/ 180 ), // a LCH[ 1 ] * Math. sin( LCH[ 2 ] * Math. PI/ 180 ) // b ]; } // OKLab and OKLCH // https://bottosson.github.io/posts/oklab/ // XYZ <-> LMS matrices recalculated for consistent reference white // see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484 // recalculated for 64bit precision // see https://github.com/color-js/color.js/pull/357 function XYZ_to_OKLab( XYZ) { // Given XYZ relative to D65, convert to 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 returns a sign-matched cube root // beware if porting to other languages // especially if tempted to use a general power function return multiplyMatrices( LMStoOKLab, LMS. map( c=> Math. cbrt( c))); // L in range [0,1]. For use in CSS, multiply by 100 and add a percent } function OKLab_to_XYZ( OKLab) { // Given OKLab, convert to XYZ relative to D65 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 is still L chroma, hue]; } function OKLCH_to_OKLab( OKLCH) { return [ OKLCH[ 0 ], // L is still L OKLCH[ 1 ] * Math. cos( OKLCH[ 2 ] * Math. PI/ 180 ), // a OKLCH[ 1 ] * Math. sin( OKLCH[ 2 ] * Math. PI/ 180 ) // b ]; } // Premultiplied alpha conversions function rectangular_premultiply( color, alpha) { // given a color in a rectangular orthogonal colorspace // and an alpha value // return the premultiplied form return color. map(( c) => c* alpha) } function rectangular_un_premultiply( color, alpha) { // given a premultiplied color in a rectangular orthogonal colorspace // and an alpha value // return the actual color if ( alpha=== 0 ) { return color; // avoid divide by zero } return color. map(( c) => c/ alpha) } function polar_premultiply( color, alpha, hueIndex) { // given a color in a cylindicalpolar colorspace // and an alpha value // return the premultiplied form. // the index says which entry in the color array corresponds to hue angle // for example, in OKLCH it would be 2 // while in HSL it would be 0 return color. map(( c, i) => c* ( hueIndex=== i? 1 : alpha)) } function polar_un_premultiply( color, alpha, hueIndex) { // given a color in a cylindicalpolar colorspace // and an alpha value // return the actual color. // the hueIndex says which entry in the color array corresponds to hue angle // for example, in OKLCH it would be 2 // while in HSL it would be 0 if ( alpha=== 0 ) { return color; // avoid divide by zero } return color. map(( c, i) => c/ ( hueIndex=== i? 1 : alpha)) } // Convenience functions can easily be defined, such as function hsl_premultiply( color, alpha) { return polar_premultiply( color, alpha, 0 ); }
20. ΔE2000 和 ΔEOK 色差示例代码
本节不具有规范性。
测试
本节为非规范性内容,无需测试。
20.1. ΔE2000
最简单的色差度量 ΔE76 仅仅是 Lab 色彩空间中的欧几里得距离。虽然这是一个很好的初步近似值,但印刷和织物染色等色彩关键行业很快开发出了改进的公式。目前,最广泛使用的公式是 ΔE2000。它修正了 ΔE76 中已知的许多不对称性和非线性问题。由于公式复杂,且关键依赖于各种中间计算的符号,因此实现往往容易出错 [Sharma]。
下方的示例代码已针对 [Sharma] 发布的一组 Lab 配对值和预期的 ΔE2000 测试套件,通过了五位有效数字的验证,结果是正确的。
// deltaE2000 is a statistically significant improvement // over deltaE76 and deltaE94, // and is recommended by the CIE and Idealliance // especially for color differences less than 10 deltaE76 // but is wicked complicated // and many implementations have small errors! /** * @param {number[]} reference - Array of CIE Lab values: L as 0..100, a and b as around -150..150 * @param {number[]} sample - Array of CIE Lab values: L as 0..100, a and b as around -150..150 * @return {number} How different a color sample is from reference */ function deltaE2000( reference, sample) { // Given a reference and a sample color, // both in CIE Lab, // calculate deltaE 2000. // This implementation assumes the parametric // weighting factors kL, kC and kH // (for the influence of viewing conditions) // are all 1, as seems typical. 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 ; // mean Chroma // calculate a-axis asymmetry factor from mean Chroma // this turns JND ellipses for near-neutral colors back into circles let C7= Math. pow( Cbar, 7 ); const Gfactor= Math. pow( 25 , 7 ); let G= 0.5 * ( 1 - Math. sqrt( C7/ ( C7+ Gfactor))); // scale a axes by asymmetry factor // this by the way is why there is no Lab2000 color space let adash1= ( 1 + G) * a1; let adash2= ( 1 + G) * a2; // calculate new Chroma from scaled a and original b axes let Cdash1= Math. sqrt( adash1** 2 + b1** 2 ); let Cdash2= Math. sqrt( adash2** 2 + b2** 2 ); // calculate new hues, with zero hue for true neutrals // and in degrees, not radians 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; // Lightness and Chroma differences; sign matters let ΔL= L2- L1; let ΔC= Cdash2- Cdash1; // Hue difference, taking care to get the sign correct 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" ); } // weighted Hue difference, more for larger Chroma let ΔH= 2 * Math. sqrt( Cdash2* Cdash1) * Math. sin( Δh* d2r/ 2 ); // calculate mean Lightness and Chroma let Ldash= ( L1+ L2) / 2 ; let Cdash= ( Cdash1+ Cdash2) / 2 ; let Cdash7= Math. pow( Cdash, 7 ); // Compensate for non-linearity in the blue region of Lab. // Four possibilities for hue weighting factor, // depending on the angles, to get the correct sign 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 ; } // positional corrections to the lack of uniformity of CIELAB // These are all trying to make JND ellipsoids more like spheres // SL Lightness crispening factor // a background with L=50 is assumed let lsq= ( Ldash- 50 ) ** 2 ; let SL= 1 + (( 0.015 * lsq) / Math. sqrt( 20 + lsq)); // SC Chroma factor, similar to those in CMC and deltaE 94 formulae let SC= 1 + 0.045 * Cdash; // Cross term T for blue non-linearity 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 Hue factor depends on Chroma, // as well as adjusted hue angle like deltaE94. let SH= 1 + 0.015 * Cdash* T; // RT Hue rotation term compensates for rotation of JND ellipses // and Munsell constant hue lines // in the medium-high Chroma blue region // (Hue 225 to 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; // Finally calculate the deltaE, term by term as root sum of squares let dE= ( ΔL/ SL) ** 2 ; dE+= ( ΔC/ SC) ** 2 ; dE+= ( ΔH/ SH) ** 2 ; dE+= RT* ( ΔC/ SC) * ( ΔH/ SH); return Math. sqrt( dE); // Yay!!! };
20.2. ΔEOK
由于 Oklab 不存在 CIE Lab 的色相线性度、色相均匀性和色度非线性问题,因此其色差度量无需进行修正,即为 Oklab 色彩空间中的欧几里得距离。
// Calculate deltaE OK // simple root sum of squares /** * @param {number[]} reference - Array of OKLab values: L as 0..1, a and b as -1..1 * @param {number[]} sample - Array of OKLab values: L as 0..1, a and b as -1..1 * @return {number} How different a color sample is from reference */ 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 定义了若干额外的系统颜色。然而,这些颜色关键字已被弃用,因为它们不足以实现最初的目的(使网站元素看起来像原生的 OS 对应元素),并且通过使网页更容易“欺骗”原生 OS 对话框构成了安全风险,还增加了指纹识别表面,从而损害了用户隐私。
用户代理必须支持这些关键字,为了减轻指纹识别风险,必须将它们映射到下文中列出的(未弃用的)系统颜色。作者不得使用这些关键字。
已弃用的系统颜色由 <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 在怪异模式 (quirks mode)下被解析时,<quirky-color> 是一种仅在特定属性中有效的 <color> 类型
它在包含或引用这些属性的属性(如 background 简写属性)中,或在函数表示法(如 color-mix())内均无效。
此外,虽然在解析 @supports 规则中的受影响属性时,<quirky-color> 必须作为 <color> 有效,但当这些属性在 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。
变更 (Changes)
自 2025 年 4 月 24 日候选推荐草案以来的变更
- 对于 Oklab 中的颜色比较,将 ε 标准化为 0.00001(问题 13157)
- 添加了一个新章节,定义了两个 <color> 值何时为等效颜色,涵盖了同色彩空间分量比较、缺失分量的处理,以及通过 oklab 进行跨色彩空间比较。(问题 13157)
- 在主要颜色插值章节中澄清:如果未指定色相插值方法,则默认采用“较短”插值。(这一点在色相插值章节中已有说明)。(问题 13788)
- 扩展了类比分量的概念,将其涵盖为类比分量集,以尽量减少 none → 0 的转换(问题 10210)
- 将颜色转换拆分为两个阶段(问题 10211)
- 澄清了系统颜色如何响应所使用的配色方案(问题 13719)
- 更新摘要,提及颜色插值和色域映射。
- 澄清了关于 CSS 色域映射目标的措辞
- 修正了光线追踪算法,不再覆盖 end(问题 10579)
- 添加了光线追踪色域映射算法的伪代码(问题 10579)
- 添加了 EdgeSeeker 和光线追踪色域映射算法。允许选择三种 GMA(问题 10579)
- 添加了显示 CIE Lab 中虚构颜色的图表
- 区分了色域外但物理上可实现的颜色与虚构颜色
- 对裁剪的描述更加平衡,展示了一些产生可接受结果的情况(问题 10579)
- 修复了 ΔE2000 示例实现中的差异(问题 13322)
- 更新 AccentColor,除非处于强制颜色模式,否则其值取自 accent-color(问题 5900)
- 定义 rec2020 色彩空间使用显示参考的 2.4 Gamma 值(问题 12574)
- 将 display-p3-linear 添加到预定义色彩空间(问题 11250)
- 澄清了使用 calc() 序列化透明度值的方法(问题 10426)
- 为了兼容性,传统 sRGB 颜色之间的插值(再次)发生在 sRGB 空间中(问题 7949)
- 澄清了现实世界中 CIE Lab 的 a 和 b 范围(问题 12208)
- 澄清了透明度值不会影响点击测试(问题 11339)
自 2024 年 2 月 13 日候选推荐草案以来的变更
- 澄清了在 color 属性内部,使用的是解析后的继承值(而非原始继承值)
- 列出了颜色类别,例如那些解析为 sRGB 或支持传统颜色语法的颜色
- 添加了色相标准化示例
- 更正了类比分量表,之前漏掉了 alpha,但文中已将其描述为类比分量
- 将透明度值的序列化整理并澄清到一个章节中
- 澄清了关于 color-interpolation-method 和宿主语法的措辞
- 定义了用于返回缺失色相的 epsilon
- 对缺失色相的消色差颜色使用了更精确的定义(足够接近中心轴)
- 一致使用“颜色分量”而不是“颜色通道”(此前两者混用)。
- 相关色温在使用前未定义或解释。添加了参考资料。
- 导出了“预乘 (premultiplied)”术语,并保持了链接的一致性
- 已弃用系统颜色与未弃用系统颜色的等价性不再被视为有风险
- 澄清了“解析 CSS <color>”算法的预期用途
- 添加了 HTML 兼容序列化的更正示例
- 移除了对 HTML 兼容序列化缺失值的检查,它们已被转换为零
- 移动了关于缺失值变为 0 的注释,使其适用于 HTML 兼容和 CSS 两种序列化
- 添加了 sRGB 的 HTML 兼容十六进制序列化
- 添加了另一个 xyz-d65 和 xyz-d50 示例
- 明确了 XYZ 中的哪个分量 (Y) 对应亮度
- 澄清了 CSS 色域映射应用于实际值而非使用值
- 从 hslToRgb 示例代码中删除了色相标准化,因为输入已在解析时标准化
- 更正了色域映射算法第 4 步的伪代码
- 澄清了插值是结合两种颜色最常见的情况,但不是唯一的情况。
- 确保 ΔE 表中文字有足够的对比度
- 删除了剩余的 <absolute-color-function> 术语,为保持一致,使用 <absolute-color> 函数代替
- 更新了致谢章节
- 添加了色域网格图
- 以声明值而非指定值的方式描述了 CSSOM 序列化
- 添加了亮度 (luminance) 的导出定义
- 添加了 <opacity-value> 的产生规则
- 澄清了 hslToRgb 的结果何时会在 [0,1] 范围内
- 澄清了 RGB 空间一旦线性化即为加性的
自 2022 年 11 月 1 日候选推荐草案以来的变更
- 添加了序列化 uint8_t alpha 的步骤,从 cssom-1 移入
- 恢复了 HSL 负饱和度在解析时的截断为 0 的行为,这是 CSS Color 3 的当前互操作行为
- 插值时总是转换色彩空间,使得无效分量变为缺失
- 澄清了何时在序列化中省略 alpha 1
- 删除了将色相角限制在 [0,360] 的冗余约束,因为这一步已经完成。
- 更正了 ActiveCaption 的描述,它是一个背景。
- 消除透明度 (opacity) 和 alpha 的歧义。Opacity 属性现在使用 opacity-value(其与 alpha-value 的截断行为不同)
- 澄清了进位发生在预乘之前
- 更新了色域映射算法
- 修复了几个关于色相插值的问题
- 澄清了 HWB 白色或黑色达到 100% 不足以作为消色差颜色的判据;总和才是关键。
- 避免在 rgb 转 hsl 转换中返回负饱和度;改为调整色相指向“另一侧”
- 对 ProPhoto 使用 64 位精确矩阵,它没有有理数形式
- 为 64 位精度重新计算了 Oklab 矩阵(返回结果与之前 32 位精度时相同)
- 始终在目标色彩空间返回 GMA 的输出,即使因为目标无界而未执行映射
- 添加了为何 Oklab 的一个 JND 是 0.02 而不是 2 的解释
- 澄清了解析 sRGB 值不适用于 color() 函数
- 将 alpha 值定义上移至 opacity 属性,澄清了 opacity 指定值不会被截断。
- 系统颜色现在显式允许欺骗,以保护隐私
- 更正了 D50 到 D65 的逆色度自适应矩阵
- 始终区分线性 Bradford 与原始、更复杂的 Bradford 色度自适应算法
- 在色域映射算法中,将 clipped 作为色域映射结果返回,避免不必要的步骤
- 更新了色度自适应矩阵以提高精度
- 添加了“解析 css 颜色”算法,这样使用颜色的非 CSS 规范就不必在这里重复发明机制了。
- 澄清了几何色域映射不得将色度投影回原始颜色之外
- 在色域映射讨论中使用术语“几何 (geometric)”而非“分析 (analytical)”
- 将 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() 语法中,必须全是数字或全是百分比的才是颜色分量
- 澄清了传统语法中颜色分量必须全是百分比或全是数字
- 添加了超出范围 alpha 的指定值示例,包括使用和不使用 calc() 的情况
- 将带有修剪尾随零的序列化颜色示例放置在相关文本附近
- 澄清了示例,使用了 text-shadow 的值
- 澄清了如何解析 currentColor
- 更新了致谢
- 不再宣称消色差颜色具有缺失的 a、b 或色度
- HSL 和 HWB 更改为无界色域,以促进往返转换
- 定义了 HSL 的百分比参考范围
- 现代颜色语法 hsl() 和 hsla() 允许混合数字和百分比分量
- 现代颜色语法 rgb() 和 rgba() 允许混合数字和百分比分量
- 定义术语“现代颜色语法”(传统颜色语法已定义)。
- 始终使用术语“类比分量”
- 更改为允许所有预定义色彩空间进行插值
- 澄清了对于 color(),需要三个参数(RGB 或 XYZ)
- 澄清了命名颜色、系统颜色和 transparent 的序列化
- 定义了 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> 的语法
- 为了更好的阅读顺序进行编辑性重构。
- 更新了色域映射算法的伪代码,移除不必要的 ΔE 调用
自 2022 年 6 月 28 日工作草案以来的变更
- 更新了候选推荐的状态
自 2022 年 4 月 28 日工作草案以来的变更
- 将 opacity 属性移至模块顶部,放在 color 属性旁边,详细说明之前。
- 改进了 color 属性的描述,特别是对其他属性的影响
- 更正了较长色相调整方程,适用于等模 360 度的颜色
- 添加了两种新的系统颜色:AccentColor 和 AccentColorText
- 在新章节中描述了整体色彩空间转换步骤
- 在预乘和去预乘中考虑了 alpha 值为 none 的情况
自 2021 年 12 月 15 日工作草案以来的变更
- 使系统颜色完全解析,但禁止在强制颜色模式下修改它们
- 删除了对 color() 函数中错误参数数量的宽容
- 将 CIE 明度和 OK 明度的序列化改为数字而非百分比。
- 将已弃用的系统颜色等价性标记为有风险
- 为 CIE 和 OK L,a,b,C 的百分比值添加了参考范围
- 指出存在用于执行和撤销预乘的示例代码,适用于矩形和极坐标色彩空间。
- 在色域映射措辞和伪代码中添加了超出范围的截断
- 添加了 ProPhoto RGB / ROMM 的规范引用
- 更正了参考环境的 sRGB 和 Display P3 黑点值
- 添加了 Display P3 的规范引用
- 避免了在色域缩减中,出现比白色更白或比黑色更黑的颜色时的无限循环
- 澄清了 none 值的序列化
- 澄清了非传统颜色在 Oklab 中插值的选择退出
- 定义了预乘如何与 none 值协同工作
- 澄清了 rgb 中的缺失值序列化为 0
- 澄清了 calc() 与 none 值的结合使用
- 拼写错误,系统颜色大小写不一致
- 添加了 SelectedItem 与 SelectedItemText 的示例
- 显式注明了传统颜色的存在与否
- 添加了 CIE XYZ 的规范引用
- 添加了 HWB 和 HSL 的规范引用
- 澄清了 hwb() 不是传统语法,因此不支持旧的逗号分隔语法形式
- 澄清了只有传统颜色才会进行色域映射,其他颜色是无界的
- 使用不同的术语:分光光度计 (spectrophotometer) 和分光辐射度计 (spectroradiometer)
- 修复了各种细微拼写错误,并进行了语法改进
自 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
- 添加了 ΔE OK 的示例代码
- 添加了 OKlab 和 OkLCh 的转换示例代码
- 添加了 oklab() 和 oklch() 函数 添加了 Oklab 和 OkLCh 的描述
- 添加了 CIE LCH 缺陷的描述
- 允许颜色的所有分量通过 none 关键字“缺失”,定义了分量何时“无效”并自动变为缺失的情况,并将所有引用“NaN”分量的部分修正为使用“缺失”概念。
- 定义了显式的 x,y 白点值,并在全文中保持一致
- 定义了术语“宿主语法”
- 定义了解析 override-color 颜色的上下文
- 添加了一对新的系统颜色
- 更正了 HSL 和 HWB 示例代码
- 用无错误版本替换了 HSL 值表
- 根据 WG 决议将 Lea Verou 添加为共同编辑
- 澄清了色相角是无界的
- MarkText 示例已更正
- 添加了图表,更正了示例
- 一些编辑性澄清
- 更正了细微拼写错误,标记更正
自 2020 年 11 月 12 日工作草案以来的变更
- 指出近中性 Lab 值转换为 LCH 时的色相不确定性问题
- 澄清了 RGB Lab 互转换中哪些步骤是线性组合
- 为 @color-profile 添加了 components 描述符,供 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 标准
- 更正了使用正确语法的回退示例
- 不要强迫非传统颜色在 Gamma 编码空间中进行插值
- 定义预乘 alpha 插值
- 开始解决 currentColor 的插值问题
- 定义带有 NaN 的色相插值
- 概括颜色插值
- 定义在 Lab 中进行插值,并可覆盖为 LCG
- 色相插值的更正
- 定义色相角插值
- 添加插值章节
- 更正了部分示例中的语法
- 澄清了 color() 中究竟哪些分量允许使用百分比
- 更改为将 lch() 序列化为它自身,而不是序列化为 lab()
- color() 中非传统 sRGB 每个分量至少 10 位精度
- color() 中色彩空间不再可选
- lab() 和 color(lab) 之间一致的最低精度
- 澄清了 color() 函数的回退过程——第一个有效的色域内颜色,否则是第一个有效颜色(并进行色域映射),否则为透明黑色
- 澄清了 opacity 属性与带有 opacity 的颜色之间的区别,特别是在渲染重叠文本字形时
- 添加了 ΔE2000 的示例(但已验证正确)代码
- 添加了先前未定义的术语“色度”的定义,并附带示例;定义色度图。
- 添加了颜色加性的解释及示例
- 添加了 WPT 测试的源代码链接
- 导出颜色及有效颜色的定义,供其他规范引用
- 定义每个分量的最少位数,用于序列化
- 更新了“适用于”定义(CSS 范围内的更改)
- 为预定义色彩空间添加了图像状态(显示参考或场景参考)
- 为了清晰起见,列出了白点相关色温(例如 D65)及色度坐标
- 澄清了舍入是向 +∞ 方向
- 修正了拼写错误、标记更正、链接修复
自 2019 年 11 月 5 日工作草案以来的变更
- 导出一些术语供其他规范使用
- 将要求从 WCAG 2.0 更新为 2.1
- 完全指定用于序列化的 Unicode 字符
- 定义特殊命名颜色的序列化
- 定义 device-cmyk() 的序列化
- 定义 color() 的序列化
- 以最大的 Web 兼容方式完全定义 RGB 序列化
- 定义 Lab 和 LCH 的序列化
- 完全定义 alpha 值的序列化
- 进行一致性检查以避免意外的 RFC2119
- 为所有示例添加 ID,以便引用
- 分离已解析颜色和序列化颜色章节
- (安全)ICC 配置文件没有可执行代码
- 定义配置颜色中“超出范围”的含义
- 澄清超出范围的截断
- 添加指定值的示例
- 澄清计算值
- 抵御指纹识别,对已弃用的系统颜色强制执行映射
- 添加了关于标准化 X11 颜色的历史和原因的说明性注释
- 更正 hwb 示例代码
- 添加 MacBeth 补丁的 DeltaE2000 值表
- 添加关于 ICC 配置文件 Internet 媒体类型的注释
- 添加 PNG sRGB 块的引用
- 澄清 CMYK 到 Lab 的互转换
- 澄清 RGB 到 Lab 的互转换
- 更多 HSL 与 LCH 的比较
- Rec BT.2020 色彩空间的更多描述
- 更新 prophoto-rgb 的描述
- 从值定义章节中删除了重复的“关键字”
- 添加了无效颜色的示例
- 添加带有多个回退的示例
- 各种拼写错误和标记修复
- 澄清对未声明的自定义色彩空间的处理
- 澄清部分示例和解释性说明
- 对有效和无效 ICC 配置文件的处理
- 定义对带有显式标记色彩空间的图像的处理
- 定义 4k、SDR 视频的色彩空间
- 声明用户对比度设置必须具有优先权
- 澄清强制颜色模式之外系统颜色的含义
- 更新默认样式规则
- 将 CIE XYZ 色彩空间添加到 color() 中
- 更清晰的色相角,明确允许 NaN
- 改进系统颜色配对章节,要求 AA 可访问对比度
- 警告重叠字形与不透明度属性之间的交互
- 修正颜色定义中的语法
- 改进 Highlight/HighlightText 的描述
- 修正 prophoto-rgb 传递函数
- 提高 prophoto-rgb 原色的精度
- 开始定义“无法显示(can’t be displayed)”
- 移除了关于画布表面的段落
- 添加了 buttonborder、mark 和 marktext 系统颜色
- 添加了逆转换,即 sRGB 到 HWB
- 澄清极坐标空间是圆柱形的,而不是球形的
- 添加了“辅助功能注意事项”章节
- 开始描述色度缩减色域映射,而不是按分量剪裁
- 修正 rec2020 的白点色度
- 使 device-cmyk 可通过 @color-profile 使用;更新 CMYK 到颜色的算法,仅在万不得已时使用朴素转换
- 添加了面向打印的 CMYK 和 KCMYOGV 示例
- 用户定义的颜色空间现在使用 dashed-ident,使得预定义的颜色空间可扩展且不会冲突
- 向 color() 函数添加了 lab 选项
- 为 CIE Lab 添加了规范性引用
- 澄清 prophoto-rgb 使用 D50 白点,因此不需要适配
- 澄清 LCH 中角度增加的方向
- 澄清颜色名称是不区分 ASCII 大小写的
- “color”属性的初始值现在为 CanvasText
- 根据 CSS 工作组决议移除了令人困惑的 gray() 函数
- 将分散的定义收集到新的 颜色术语 章节
- 添加了有用的图表和更多示例
- 细微的编辑澄清、拼写检查、修正错别字、Bikeshed 标记修复
自 2016年7月5日工作草案 以来的变更
- 将 Lab 和 LCH 中的亮度更改为百分比,以实现 CSS 兼容性
- 澄清了颜色值的剪裁(Clamping)
- 现在允许百分比形式的不透明度
- 定义了 sRGB 和线性光 sRGB 术语,供其他规范使用
- 添加了新的 CSS 系统颜色列表;将 Text 重命名为 CanvasText
- 使系统颜色关键字计算为其自身
- 为系统颜色添加了计算/使用(computed/used)条目
- 重写非弃用系统颜色的介绍,将其使用重点放在强制颜色(forced-colors)模式,而非通用用法
- 预定义颜色空间的一致连字符用法
- 恢复关于非不透明元素即使在未定位时也会在层上绘制的文本
- “color”属性的初始值现在为黑色
- 澄清 LCH 中的色相为模 360deg(该变更现已撤回)
- 澄清 LCH 和 Lab 中 L 的允许范围以及 L=100 的含义
- 更新视频中使用的颜色空间参考
- 添加 prophoto-rgb 预定义颜色空间
- 修正 display-p3 的黑白亮度级别
- 澄清 display-p3 传递函数
- 添加 a98-rgb 颜色空间,修正原色色度表
- 澄清 currentColor 的计算值并非解析后的颜色
- 更新语法示例以符合最新规范
- 移除 color-mod() 函数
- 从属性定义表中删除“媒体(media)”
- 导出并一致使用“透明黑(transparent black)”和“不透明黑(opaque black)”
- 澄清计算值(如百分比)
- 澄清颜色分量所需的精度和舍入行为
- 澄清“color”属性对彩色字体字形没有影响(除非明确引用,例如使用 currentColor)
- 澄清颜色值如何解析
- 澄清 HSL、HWB 和命名颜色解析为 sRGB
- 简化从 device-cmyk 到 sRGB 的转换
- 将以前使用逗号的颜色语法描述为“旧版”;将示例更改为无逗号形式
- 移除关于显示颜色必须限制在设备色域内的多余要求(好像还有其他选择一样!)
- 将 P3 重命名为 display-p3;避免声称这是 DCI P3,因为两者并不相同
- 改进了“color()”函数参数的描述
- 禁止在“@color-profile”标识符中使用预定义空间
- 在“color”、“color-adjust”和“opacity”属性定义中添加规范顺序
- 将 Alpha 合成的定义从 SVG11 切换为 CSS Compositing
- 澄清示例转换代码是非规范性的
- 添加安全和隐私注意事项
- 将几个参考资料更新为最新版本
- 将内联问题转换为 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() 现在互为别名(它们都有可选的 Alpha)。
- rgb()、rgba()、hsl() 和 hsla() 都获得了一种新语法,由空格分隔的参数和可选的斜杠分隔的不透明度组成。所有的颜色函数现在都使用这种语法形式,以符合 CSS 的函数式标记设计原则。
- 所有对 <alpha-value> 的使用现在都接受 <percentage> 以及 <number>。
- 增加了 4 位和 8 位十六进制颜色,用于指定透明度。
- 添加了 none 值,以表示无影响的分量。
21. 安全注意事项
如果系统颜色确实对应于用户的系统颜色,则会构成安全风险,因为它们使恶意网站更容易创建看起来像系统自身的界面。然而,由于现在定义了多种“通用”系统颜色,这种风险被认为已得到缓解。
22. 隐私注意事项
本规范定义了“系统”颜色,理论上这些颜色可能会暴露用户操作系统设置的细节,这是一种指纹识别风险。
23. 辅助功能注意事项
本规范 鼓励作者不要仅使用颜色 作为区分特征。
本规范 鼓励浏览器确保特定的系统颜色前景/背景对具有足够的对比度。CSSWG 曾考虑提出带有特定 AA 或 AAA 对比度要求的更硬性规定,但由于浏览器通常只是传递操作系统所做出的选择,或者由用户选择(用户可能有特定要求,包括针对偏头痛或癫痫患者的低对比度需求),CSSWG 无法强制要求特定的对比度水平。