是时候介绍这几个全新的CSS颜色函数了

这篇文章发布于 2023年02月19日,星期日,22:10,归类于 CSS相关。 阅读 20390 次, 今日 1 次 一条评论

 

调色板占位图CSS颜色

今天打开caniuse查了下,几个全新的颜色函数Chrome浏览器也支持了,这可是为数不多的落后Safari浏览器支持数年(2023年 vs 2021年)的CSS新特性了。

Chrome浏览器支持LCH

与此同时,Firefox浏览器也已经开启“实验支持”,说明这几个颜色函数被所有现代浏览器支持已经是板上钉钉的事情了,这就意味着时机成熟,可以好好介绍这几个全新的CSS颜色函数了。

一、最先支持的hwb()色值

hwb()色值是这批颜色函数(CSS Level 4 Color Module)中最早支持的,兼容性如下图所示:

hwb()颜色模型

HWB颜色模型是RGB颜色模型中点的圆柱坐标表示,类似于HSL和HSV。它是由HSV的创建者阿尔维·雷·史密斯于1996年开发的,以解决HSV的一些问题,相对而言,HWB对人类而言要更加直观,计算速度也更快一些。

此颜色模型使用的时候先选择一个主色,然后再和白色和(或)黑色“混合”以产生所需的颜色。其中,第一个坐标H(色调)与HSL和HSV中的色调坐标相同,而后面的W和B分别代表白度和黑度,范围为0–100%(或0–1)。

下图示意的就是不同H、W、B值下的色块显示图。

色块显示示意图

由于HWB更符合人类的直观认知,因此,HWB模型的颜色更容易脑补出来。

例如 hwb(0 0% 30%),就是红色加入30%的黑色,效果就是偏深一点的红色。

实际渲染效果如下所示(实时渲染,若无效果,多半非原站):

案例演示

为了方便大家体验HWB颜色效果,我做了个演示页面,您可以狠狠地点击这里:CSS HWB()颜色函数渲染demo

拖动滑块,可以看到对应的颜色变化效果。

如下GIF录屏所示:

hwb颜色变化示意

颜色转换

下面展示下如何使用JS实现 RGB 和 HWB 之间的颜色转换(出自这里)。

// RGB [0, 255]
// HWB [0, 1]
function rgb2hwb(r, g, b) {
  
  r /= 255;
  g /= 255;
  b /= 255;
  
  var f, i,
      w = Math.min(r, g, b);
      v = Math.max(r, g, b);
      black = 1 - v;
  
  if (v === w) return {h: 0, w: w, b: black};
  f = r === w ? g - b : (g === w ? b - r : r - g);
  i = r === w ? 3 : (g === w ? 5 : 1);

  return {h: (i - f / (v - w)) / 6, w: w, b: black}
}

// HWB [0, 1]
// RGB [0, 255]
function hwb2rgb(h, w, b) {
  
  h *= 6;
  
  var v = 1 - b, n, f, i;
  if (!h) return {r:v, g:v, b:v};
  i = h|0;
  f = h - i;
  if (i & 1) f = 1 - f;
  n = w + f * (v - w);
  v = (v * 255)|0;
  n = (n * 255)|0;
  w = (w * 255)|0;

  switch(i) {
    case 6:
    case 0: return {r:v, g:n, b: w};
    case 1: return {r:n, g:v, b: w};
    case 2: return {r:w, g:v, b: n};
    case 3: return {r:w, g:n, b: v};
    case 4: return {r:n, g:w, b: v};
    case 5: return {r:v, g:w, b: n};
  }
}

//zxx: 传统色值,如rgb, hsl #RRGGBB之间的颜色转换JS可以访问我之前这篇文章:“JS HEX十六进制与RGB, HSL颜色的相互转换”。

二、lch()和lab()函数

lch()和lab()颜色函数都是基于CIE LAB颜色空间定义的,是一种更符合人类感知的颜色表示方式,这两种颜色函数提供比通常RGB颜色空间更宽广的颜色范围。

lch()函数

LCH函数三个字母分别表示:

L: 明度(Lightness),0%~100%
C: 彩度(Chroma),0~ ∞
H: ⾊相(Hue),0~360(隐藏单位是角度单位deg)

LCH颜色示意

如果要判断一个水果是否新鲜诱人,则最适合的颜色函数就是lch()函数,因为明度、彩度对应的就是水果表面是否反光,颜色是否饱满等。

使用示意:

lch(29.2345% 44.2 27);
lch(52.2345% 72.2 56.2);
lch(52.2345% 72.2 56.2 / .5);

对应的颜色分别如下所示(不支持的浏览器背景灰色):

lab()函数

LAB函数三个字母分别表示:

L: 明度(Lightness),0%~100%
A: 颜⾊通道,从深绿⾊(低亮度)到灰⾊(中亮度)再到亮粉红⾊(⾼亮度),是Lab颜色空间中沿a轴的距离。
B: 颜⾊通道,从亮蓝⾊(低亮度)到灰⾊(中亮度)再到⻩⾊(⾼亮度),Lab颜色空间中沿b轴的距离(见下图示意)。

lab颜色空间示意

Lab颜色空间最大的优点是其可以在不同的软件中使用同一种量化颜色,也就是Lab颜色空间与设备无关,这在印刷中非常受用,可以抹消印刷中的颜色偏差,从而实现设计同步。

使用示意:

lab(29.2345% 39.3825 20.0664);
lab(52.2345% 40.1645 59.9971);
lab(52.2345% 40.1645 59.9971 / .5);

对应的颜色分别如下所示(实时渲染,若无效果,多半非原站):

LAB历史小背景

1900年代,理查德·亨特发明了LAB色彩空间。尽管它能够消除颜色的微小变化并保持均匀性,但它从未被接受为标准。

几年后,CIE推出了一个名为CIElab的实验室的更新版本。它发音为c-lab,但也被称为lab或L*A*B*。

CIElab是无许可证和版权的,因此您可以在任何设备上使用它。

颜色转换

LAB颜色和LCH颜色之间的转换其实还挺简单的,因为至少L是一样的,不变,下面就是代码示意:

function lab2lch(labL, labA, labB) {
    const [ lchC, lchH ] = [
        Math.sqrt(Math.pow(labA, 2) + Math.pow(labB, 2)), // 转换为 chroma
        (Math.atan2(labB, labA)) * 180 / Math.PI // 转换为 hue,角度值
    ];
    return [ labL, lchC, lchH ];
}

function lch2lab(lchL, lchC, lchH) {
    const [ labA, labB ] = [
        lchC * Math.cos(lchH * Math.PI / 180),
        lchC * Math.sin(lchH * Math.PI / 180)
    ];
    return [ lchL, labA, labB ];
}

console.log(lab2lch(0.292345, 39.3825, 20.0664));
console.log(lch2lab(0.292345, 44.2, 27));

输出结果是:

输出结果示意

符合预期。

三、指定颜色空间函数color()

CSS color()函数允许浏览器在显示任何的颜色空间,例如P3颜色空间,它可以显示默认sRGB颜色空间之外的颜色。

其语法如下,第一个参数就是用来指定所使用的颜色空间的。

color( [ [ | ]? [ + ] [ /  ]? ] )

简化下就是:

color(颜色空间 颜色数值 / 透明度);

支持的颜色空间包括下面这些:

display-p3
srgb
rec2020
prophoto-rgb
srgb-linear
a98-rgb

下面通过一个实例看下各自支持的效果,下面是演示代码:

<ul>
    <li class="color1">第1项 - display-p3</li>
    <li class="color2">第2项 - rec2020</li>
    <li class="color3">第3项 - xyz-d50</li>
    <li class="color4">第4项 - srgb</li>
    <li class="color5">第5项 - prophoto-rgb</li>
</ul>
.color1 {
    color: color(display-p3 1 0.5 0);
}
.color2 {
    color: color(rec2020 0.42053 0.979780 0.00579);
}
.color3 {
    color: color(xyz-d50 0.2005 0.14089 0.4472);
}
.color4 {
    color: color(srgb 0.691 0.139 0.259);
}
.color5 {
    color: color(prophoto-rgb 0.691 0.139 0.259);
}

结果在浏览器中(注意自己的Chrome浏览器版本,需要Chrome 111+)每个列表都有了颜色变化(如果浏览器不支持,会是默认的黑色):

color()函数效果示意

眼见为实,您可以狠狠地点击这里:CSS color()函数与颜色空间demo

颜色空间的自定义

除了浏览器内置的这些经典的颜色空间,我们还可以自已颜色空间,这个是使用@color-profile规则实现的,使用示意(案例源自MDN文档):

@color-profile --swop5c {
  src: url("https://example.org/SWOP2006_Coated5v2.icc");
}
.header {
  background-color: color(--swop5c 0% 70% 20% 0%);
}

颜色空间的检测

颜色空间是否被当前浏览器支持可以使用color-gamut查询实现,使用示意:

@media (color-gamut: srgb) {
  p {
    background: #f5f3f9;
  }
}

此查询语句目前所有现代浏览器都支持。

color-gamut兼容性

兼容性

color()函数Firefox目前似乎还没有支持,Chrome已经完全支持了。

color()函数兼容性

四、颜色混合函数color-mix()

color-mix()函数可以让两个颜色进行指定比例的混合。

使用示意:

color-mix(in lch, purple 40%, gold);
color-mix(in srgb, #34c9eb 20%, white);

实时渲染效果如下所示(如果背景灰色则说明浏览器并不支持):

我们日常开发,就使用in srgb就可以了,最常用,上手成本低。

此颜色函数我期盼已久,挺实用的,我过段时间,等Safari和Firefox浏览器也完全支持的时候(目前是实验支持),会专门详细介绍下。

color-mix兼容性示意

五、了解oklch()和oklab()函数

oklch()和oklab()函数目前仅Safari15.4+支持,因此,大家暂时先了解下即可。

oklch()颜色空间和lch()函数区别在于,oklch()的C(彩度)和H(色调)使用的是极坐标系。

其中第二个值C的它的最小值为0,而最大值理论上是无限的(但实际上不超过0.4)。

使用示意:

oklch(40.1% 0.123 21.57)
oklch(59.69% 0.156 49.77)
oklch(59.69% 0.156 49.77 / .5)

oklab()函数

oklab()函数表示的颜色使用的是oklab颜色空间,它试图模拟人眼如何感知颜色。

oklab()在oklab颜色空间的a轴和b轴上使用的是笛卡尔坐标系。如果您想要极坐标系、或者使用彩度和色调表示颜色,请使用oklch()函数。

使用示意:

/* oklab(lightness a-axis b-axis) */
oklab(40.1% 0.1143 0.045);
oklab(59.69% 0.1007 0.1191);

/* oklab(lightness a-axis b-axis / Alpha) */
oklab(59.69% 0.1007 0.1191 / 0.5);

六、关于颜色更多知识

除了以前这些颜色函数,CSS颜色规范level4中还有几个新特性浏览器很早就支持了,例如#RRGGBBAA色值表示,以及更加自由的rgb和hsl颜色表示方法,详见之前写的这篇文章:“快速学习CSS Color Level 4的色值新语法”。

本文所介绍的这些时间函数,除了hwb()还有点眼缘,color-mix()函数值得期待外,其他几个颜色函数,我相信大家日常开发都是没多少机会接触的。

就我个人感觉,相比颜色函数,CSS新支持的那些数学函数要实用的多,例如exp(),round(), sin(), hypot(), abs() 等,很多,十来个有的,我查了下,Safari和Firefox111已经都支持,Chrome111也开始支持部分数学函数。

CSS果然是越来越强了,能做的事情也越来越多的。

不过短期还是看不到CSS地位的崛起,因为转变是需要时间的,人都是有惯性的,以前JS能够搞定的且运行良好的事情,是很难有动力去换成一个全新的未知的可能有风险的新事物的。

……这需要时间。

好,以上就是本文的全部内容了,博闻强识,拓展视野。

?❤️????

(本篇完)

分享到:


发表评论(目前一条评论)

  1. quehei说道:

    好的 博闻强识,拓展视野