色彩空间

本文从前端工程师的角度深入探讨色彩空间,涵盖named-color、CMYK、RGB、HSL、HSB/HSV以及CIE Lab/CIE Lch模型。通过实例分析,解释了各种色彩模型的特性和转换,帮助读者更好地理解和应用色彩理论。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在前面

  • 提到色彩,即使是刚有辨知能力的小朋友,也能说上几句~

  • 那我们前端工程师,无论工作还是生活,每天都在与各种色彩打交道,那便更有必要系统地了解关于色彩方面的知识

  • 本文将从前端角度,聊聊色彩空间

  • 根据 CSS Color Module Level 4 标准

    <color> = <hex-color> | <named-color> | currentcolor | transparent
              <rgb()> | <rgba()> | <hsl()> | <hsla()> | <hwb()> |
              <lab()> | <lch()> | <gray()> |
              <color()> | <device-cmyk()> |
              <system-color>
    

named-color

transparent

currentcolor

system-color

减色法混色模型 CMYK 与 加色法混色模型 RGB

减色法混色模型 CMYK

  • C - Cyan - 青色
  • M - Magenta - 红色
  • Y - Yellow - 黄色
  • K - blacK - 黑色(防止与 RGB 的 B 冲突)
  • 上过美术课,应该听过“红黄蓝”三原色的说法,但这和 CMYK 不太一样,实际上,颜料显示颜色的原理是它吸收了所有别的颜色的光,只反射一种颜色,所以颜料三原色其实是红、绿、蓝的补色,也就是:品红、黄、青。因为它们跟红、黄、蓝相近,所以有了这样的说法。
  • 为什么会比三原色多了一色呢?
    • 三种颜色调成黑色,
    • 不是纯粹的黑,三色等量相加之后只能形成一种深灰或深褐(我要五彩斑斓的黑

加色法混色模型 RGB

  • 我们在 CSS 样式中看到的形式如 #RRGGBB 的颜色代码,就是 RGB 颜色的十六进制表示法,其中 RR、GG、BB 分别是两位十六进制数字,表示红、绿、蓝三色通道的色阶。色阶可以表示某个通道的强弱。
  • 但 RGB 并不能表示人眼所见的所有颜色,它只能表示下面的这个区域

人眼看到的颜色vsRGB能表示的颜色

  • RGB 对色彩的描述,对计算机友好,但不够人性化
  • RGB 我们只能大致判断出它偏向于红色、绿色还是蓝色,或者在颜色立方体的大致位置。
  • 以及对比两个 RGB 颜色的时候,我们只能通过对比它们在 RGB 立方体中的相对距离,来判断它们的颜色差异。

RGB 立方体几何表示

  • 但我们对色彩的认识往往先是:颜色是什么,鲜艳不鲜艳,亮还是暗
  • and It’s not easy to to alter an RGB color to produce a lighter variant of the same hue.
    • 这在我们开发中也十分常见,有些时候设计师定下视觉基调和主色,我们需要根据数据情况由前端动态生成颜色值

HSL HSB&HSV

  • CSS 和 Canvas2D 都可以直接支持 HSL 颜色,只有 WebGL 需要做 RGB2HSV 转换。

HSL

H - Hue - 色相 - 0-360°的圆心角
  • H(hue)分量,代表的是人眼所能感知的颜色范围,这些颜色分布在一个平面的色相环上,取值范围是0°到360°的圆心角,每个角度可以代表一种颜色。
  • 色相值的意义在于,我们可以在不改变光感的情况下,通过旋转色相环来改变颜色。
  • 在实际应用中,我们需要记住色相环上的六大主色,用作基本参照:360°/0°红、60°黄、120°绿、180°青、240°蓝、300°洋红,它们在色相环上按照60°圆心角的间隔排列。

HSL 色相环

S - Saturation - 饱和度 - 0~1 或者 0%~100% 间的值
  • 和黑白没有关系,饱和度不控制颜色中混入黑白的多寡
  • 数值越大,颜色中的灰色越少,颜色越鲜艳,呈现一种从灰度到纯色的变化。

HSL S

L - Lightness - 亮度 - 0~1 或者 0%~100% 间的值
  • 控制纯色中的混入的黑白两种颜色
  • 数值越小,色彩越暗,越接近于黑色;数值越大,色彩越亮,越接近于白色。

HSL L

HSB & HSV

  • HSB 又称 HSV
  • HSV 色轮- WebGL 实现
    • 像素坐标转换为极坐标,再除以 2π,就能得到 HSV 的 H 值
    • 鼠标位置的 x、y 坐标来决定 S 和 V 的值
S - Saturation - 饱和度 - 0~1 或者 0%~100%间的值
  • 控制纯色中混入白色的量,值越大,白色越少,颜色越纯;
B - Brightness - 亮度 - 0~1 或者 0%~100%间的值
  • 控制纯色中混入黑色的量,值越大,黑色越少,明度越高

RGB 立方体转换成 HSL / HSV 过程

RGB 立方体转换成 HSL / HSV 过程

  • 我们可以把这个过程简单理解成,将 RGB 颜色的立方体从直角坐标系投影到极坐标系的圆柱上

  • HSV(色相、饱和度、明度)在概念上可以被认为是颜色的倒圆锥体(黑点在下顶点,白色在上底面圆心)

    • HSV倒圆锥
  • HSL 在概念上表示了一个双圆锥体和圆球体(白色在上顶点,黑色在下顶点,最大横切面的圆心是半程灰色)

    • HSL 概念图
  • 我们可以从下图来对比 HSL & HSV

    • HSL & HSV
  • 但即使我们可以均匀地修改每组的亮度和饱和度,由于人眼对不同频率的光的敏感度不同,我们仍然会感觉有的颜色看起来和其他的颜色差距明显,有的颜色还是没那么明显

  • 看下面的例子

    for(let i = 0; i < 20; i++) {
      ctx.fillStyle = `hsl(${Math.floor(i * 15)}, 50%, 50%)`;
      ctx.beginPath();
      ctx.arc((i - 10) * 20, 60, 10, 0, Math.PI * 2);
      ctx.fill();
    }
    
    for(let i = 0; i < 20; i++) {
      ctx.fillStyle = `hsl(${Math.floor((i % 2 ? 60 : 210) + 3 * i)}, 50%, 50%)`;
      ctx.beginPath();
      ctx.arc((i - 10) * 20, -60, 10, 0, Math.PI * 2);
      ctx.fill();
    }
    
    • 我们绘制两排不同的圆,让第一排每个圆的色相间隔都是 15,再让第二排圆的颜色在色相 60 和 210 附近两两交错。
    • 最终生成效果如下:
      • HSL 色相修改
    • 可以看出:
      • 第一排圆你会发现,虽然它们的色相相差都是 15,但是相互之间颜色变化并不是均匀的,尤其是中间几个绿色圆的颜色比较接近。
      • 第二排圆,虽然这些圆的亮度都是 50%,但是蓝色和紫色的圆看起来就是不如偏绿偏黄的圆亮。
  • 因此,HSL 依然不是最完美的色彩表示方法,我们还需要建立一套符合人类认知的标准。这个标准尽可能地满足一下 2 个原则

    • 人眼看到的色差 = 颜色向量间的欧氏距离
    • 相同的亮度,能让人感觉亮度相同

CIE Lab / CIE Lch

  • Lab色彩空间(英语:Lab color space)是颜色-对立空间,带有维度L表示亮度,a和b表示颜色对立维度,基于了非线性压缩的CIE XYZ色彩空间坐标。

  • CIE Lab 比较特殊的一点是,目前还没有能支持 CIE Lab 的图形系统,但规范中已经给出了 Lab 颜色值的定义

    lab() = lab( <percentage> <number> <number> [ / <alpha-value> ]? )
    lch() = lch( <percentage> <number> <hue> [ / <alpha-value> ]? )
    
  • 且一些 JavaScript 库也已经可以直接处理 Lab 颜色空间了,如 d3-color

    for(let i = 0; i < 20; i++) {
      const c = d3.lab(30, i * 15 - 150, i * 15 - 150).rgb();
      ctx.fillStyle = `rgb(${c.r}, ${c.g}, ${c.b})`;
      ctx.beginPath();
      ctx.arc((i - 10) * 20, 60, 10, 0, Math.PI * 2);
      ctx.fill();
    }
    
    for(let i = 0; i < 20; i++) {
      const c = d3.lab(i * 5, 80, 80).rgb();
      ctx.fillStyle = `rgb(${c.r}, ${c.g}, ${c.b})`;
      ctx.beginPath();
      ctx.arc((i - 10) * 20, -60, 10, 0, Math.PI * 2);
      ctx.fill();
    }
    
    • 这个例子与 HSL 的例子一样,也是显示两排圆形。
      • 第一排相邻圆形之间的 lab 色值的欧氏空间距离相同
      • 第二排相邻圆形之间的亮度按 5 阶的方式递增
    • d3 lab demo
  • 可以看出,在以 CIELab 方式呈现的色彩变化中,我们设置的数值和人眼感知的一致性比较强。

  • 至此,规范中出现的色彩空间表示方法已经介绍完了。

Cubehelix 色盘

  • 它的原理就是在 RGB 的立方中构建一段螺旋线,让色相随着亮度增加螺旋变换。
  • Cubehelix 螺旋线原理
  • 我们可以用 cubehelix 写一个颜色随着长度变化的长度
    • 首先,我们直接使用 cubehelix 函数创建一个 color 映射。
      • cubehelix 函数是一个高阶函数,它的返回值是一个色盘映射函数。这个返回函数的参数范围是 0 到 1,当它从小到大依次改变的时候,不仅颜色会依次改变,亮度也会依次增强。
    • 然后,我们用正弦函数来模拟数据的周期性变化,通过 color 获取当前的颜色值,再把颜色值赋给 ctx.fillStyle,颜色就能显示出来了。
    • 最后,我们用 rect 将柱状图画出来,用 requestAnimationFrame 实现动画就可以了 。
import {cubehelix} from 'cubehelix';
	
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
	
ctx.translate(0, 256);
ctx.scale(1, -1);
	
const color = cubehelix(); // 构造cubehelix色盘颜色映射函数
const T = 2000;
	
function update(t) {
  const p = 0.5 + 0.5 * Math.sin(t / T);
  ctx.clearRect(0, -256, 512, 512);
  const {r, g, b} = color(p);
  ctx.fillStyle = `rgb(${255 * r},${255 * g},${255 * b})`;
  ctx.beginPath();
  ctx.rect(20, -20, 480 * p, 40);
  ctx.fill();
  window.ctx = ctx;
  requestAnimationFrame(update);
}
	
update(0);
  • Cubehelix rect

Coverting

参考资料

写在后面

  • 祝大家多多发财
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值