vitoliu
前端开发工程师
vitoliu 2022-12-30
在前端开发中,色彩信息非常重要,它可以影响用户视觉,来表达数据的大小、操作的优先级等等。按照惯例,我们先来看几个需求:
色彩当然要从三原色开始说起 R红 G绿 B蓝 (A透明),将三原色各种组合也就有了各种颜色。对于屏幕这种发光的场景通常是“加色模式”,对于颜料这种是“减色模式”。
我们接触的各种彩色屏幕,其实就是由更小的三原色发光材料来控制每个像素的颜色的。
所以通常用红、绿、蓝来表示颜色,也就是 RGB。虽然RGB不能表示肉眼所见的全部颜色,但也足够丰富了,一般的显示器、彩色打印机、扫描仪等都支持它。web开发也离不开他,如:#0064ff 、rgb(0, 100, 255)、rgba(0, 100, 255, 1),都是我们常用的表示颜色的方式。 但是 RGB 是理想化的色彩表示方式,我们只能大致的判断出它偏向红色、绿色还是蓝色,或者颜色立方体的大致位置,除此之外就没有其它信息了,也就很难有办法动态生成一组对比鲜明的颜色。因此,在需要动态构建视觉颜色效果的时候,我们很少直接选用 RGB 色值,而是使用其他色彩表示形式。这其中比较常用的就是HSL、HSV色彩表示方式。
类似的还有HSB、HSI,HSV = HSB,HSL ≈ HSI,是一种将RGB色彩模型中的点在圆柱坐标系中的表示法。 转换方法:
目前,浏览器 css 早已支持HSL的色彩表达。
表示方式为:
/* hsl( 色相hue<0~360>, 饱和度saturation<0%~100%>, 亮度lightness<0%~100%> ) */
background: hsl(10,30%,30%);
color: hsla(360,100%,100%,1);
借助 HSL,就可以很容易生成颜色梯度:
相邻的颜色的颜色梯度,只需要将色相递增或递减即可
色相间隔15,饱和度和梯度都是50%:hsl(n*15, 50%, 50%)
亮度颜色梯度,只需要将亮度递增或递减即可
hsl(120/240, 50%, 25+n*5%)
但细心的你一定发现了,在色相梯度中,绿色附近的颜色比较接近,而其他颜色则跨度较大。而且相同亮度情况下,绿色要比蓝紫色看起来要亮上一些,这是因为人眼对不同频率的光的敏感度不同造成的。 因此,HSL依然不完美,于是一套针对人类知觉标准的色彩模型就诞生了:CIELAB
CIELCHuv、 CIELCHab是同一个以人类感知为主的色彩模型,只是表示方式不同。
不规则的色彩空间
目前,仅 Safari 在 15 及以上版本的 css(css-level 4) 才支持 lch()
、lab()
以 lab
为例:
/*lab( 亮度<0%~100%> a<-125~125> b<-125~125> ), a/b表示:Lab颜色空间中沿“a”和“b”轴的距离 */
background: lab(45.90% 25.22 -84.96); /* 中间没有逗号 */
lab(59% ${-125+i*10} ${-125+j*10})
可以看到在亮度一致的情况下,各个颜色的感观亮度也一致,且颜色过渡均匀,更适合需要动态生成颜色的场景。
色彩空间的发展远远不止上述提到的这些,以知名的 Color.js 颜色转换库支持的色彩空间为例,就支持了数十种,这个库提供了非常直观的 API 设计,可以很方便进行颜色转换,有兴趣的自行了解。
Color.js Supported Color Spaces
https://github1s.com/ecomfe/zrender/blob/HEAD/src/tool/color.ts
有了上述这些色彩空间,和颜色的表示方法,处理颜色渐变肯定不成问题了。至于显示清晰的文字,只需要根据在 CIELAB 模型(HSL 也行)下的亮度,取个相反的即可。各种色彩空间实际都是,在各种场景、需求背景下诞生下的工具,只要工具选对了,问题就能迎刃而解啦。