新的 CSS Color Module 规范引入了多种新的颜色表示法. 可以支持多种色彩空间和颜色模型. 这解锁了很多的玩法. 比如: 基于一个颜色生成更深或更浅的颜色; 根据背景自适应文本色; 使用广色域颜色等等.
CSS Color Module Level 4 规范
引入了新的颜色表示法, 同时引入了多种色彩空间, 不再仅限于sRGB, 这些方法现代浏览器均已支持:
再补充一点, 这些新方法中:
CSS Color Module Level 5 规范
CSS Color Module Level 6 规范
在详细介绍这些现代新方法之前有必要对一些术语进行解释:
名词解释:
颜色模型是指颜色与坐标系之间的映射和编码方式, 它定义维度分量与色彩空间的关系. 一个颜色模型就会有一个对应的色彩空间.
色彩空间是某一颜色模型所涵盖的颜色的定义和命名. 每个颜色空间都由数学模型和关联的规则集定义. 色彩空间是表示颜色的三维网格, 色彩空间中的每个颜色都由三个通道分量(维度)来表示. 每个颜色空间都有一个定义的色域。
色域指的是它可以表示的特定颜色的范围, 通常指设备可以显示的颜色范围. 如 sRGB, P3, Rec2020 等
可以看出三者有一些共性的东西, 通常来说, 当上下文中使用颜色空间时强调的是它的颜色模型和算法. 当使用色域时强调的是能不能显示某些颜色
比如, 以前用的最多的rgb方法, 带和不带alpha通道是不同的方法: 不带alpha通道的是: rgb(r, g, b), 而带alpha通道的是: rgba(r, g, b, a)
现在可以统一使用: rgb(R G B [/ A]), alpha通道值是可选的. 注意为了区分旧方法, 新方法不使用逗号分隔分量, 而是用空格替代.
上面只是拿rgb方法举了个例子, 其实Level 4 中的所有新方法都支持这种表示法. 如: oklch(L C H [/A])
语法: rgb(from <color> R G B[ / A]), hsl(from <color> H S L [/A]), oklch(from <color> L C H [/A]), ...
相对颜色是指从一个指定颜色的色彩空间转换到目标色彩空间, 通过对目标色彩空间中的维度变量进行微调后的结果作为输出.
这听起来比较绕, 简单点说就是可以根据原色, 对维度变量进行微调后输出. 主要特性:
这3个特性解锁了一些原本只能通过js才能实现的一些功能.
例子1: 鼠标覆盖按钮时加深背景色:
方法1: 使用Level 5 规范中的相对颜色表示法:
.btn { --btn-bg: blue; background-color: var(--btn-bg);}.btn:hover { background-color: oklch(from var(--btn-bg) calc(l - 0.1) c h);}
这个例子中--btn-bg自定义属性可以更改为任意颜色, 本例中使用了oklch作为目标色彩空间, 因为oklch可以做到调整亮度而不会影响色相.
从这个例子中可以看出, CSS自定义属性与相对颜色的结合使用, 可以创造出很多的新玩法.
方法2: 使用Level 5 规范中的color-mix()方法
.btn { --btn-bg: blue; background-color: var(--btn-bg);}.btn:hover { background-color: color-mix(in oklch, var(--btn-bg), black 10%);}
color-mix()方法的意思是将颜色1和颜色2先转换到in关键字指定的目标色彩空间, 然后按百分比混合它们后输出.由于black只有L分量, 因此混合只影响了L分量, 因此就得到了不改变色相的情况下加深了颜色.
例子2: 根据不同背景色自适应高对比度的文本色
这个场景需要一种方式确定高对比度的算法模型. 通用的是WCAG 2.1, 但它不太准确, 还有一种是APCA, 它相对准确性更高, 参考性更大. 在APCA算法下, 采用oklch颜色模型下L分量在72%左右是一个比较好的对比度分界线. 72%以上采用黑色文本, 72%以下采用白色文本.
好了, 有了这个基础, 现在可以使用纯CSS实现自适应高对比度的文本色:
.btn { --btn-bg: blue; background-color: var(--btn-bg); color: oklch(from var(--btn-bg) clamp(0, calc((0.72 - l) * 10000), 1) 0 0);}
这个例子中--bg自定义属性可以更改为任意颜色, 按钮文本都可以自适应的高对比度颜色. 本例中使用了oklch作为目标色彩空间, 因为oklch可以做到亮度是可预测性.
这里稍微解释这句:clamp(0, calc((0.72 - l)* 10000), 1), 意思是背景色的l维度分量 > 0.72说明背景是浅色的, 那么文本色的L分量就取0即黑色, 否则就说明背景是深色的,L分量就取1即白色. 如果不想纯白或纯黑, 适当调整各分量以及L的上下界即可.
这个例子还可以使用CSS Color Module Level 6中的color-contrast()实现相同的效果, 但目前还没有浏览器支持, 留着将来备用:
.btn { --btn-bg: blue; background-color: var(--btn-bg); color: color-contrast(var(--btn-bg) vs white,black);}
color-contrast()的意思是选择vs关键字之后与第一个参数指定的颜色对比度最高的颜色作为输出.
现代网页中推荐使用oklch颜色模型, 使用 OKLCH 的好处:
OKLCH 颜色由亮度(明度)、色度(饱和度或纯度)、色相三个维度组成, 这也是人类认知里的颜色的三个基本属性.
详细分析请看这篇文章: OKLCH in CSS: why we moved from RGB and HSL—Martian Chronicles, Evil Martians’ team blog
使用这个 colorjs.io npm包即可. 它完全支持CSS Color Module Level 4 和 Level 5 的规范
我们的正式开源轻量级的基于Tailwindcss的React 组件库中的颜色选取组件正在重构中