~/static/img/default-avatar-0.jpeg

vitoliu

前端开发工程师

博客

前端人需要了解的色彩表示方法

vitoliu 2022-12-30

在前端开发中,色彩信息非常重要,它可以影响用户视觉,来表达数据的大小、操作的优先级等等。按照惯例,我们先来看几个需求:

  • 任意图片上的文案清晰(亮度高的颜色,显示深色文字,亮度低的颜色上,显示浅色文字)
  • 生成设计规范或组件库的主题颜色梯度
  • 大数据可视化场景下的颜色渐变

三原色

色彩当然要从三原色开始说起 R红 G绿 B蓝 (A透明),将三原色各种组合也就有了各种颜色。对于屏幕这种发光的场景通常是“加色模式”,对于颜料这种是“减色模式”。

image.png

image.png

我们接触的各种彩色屏幕,其实就是由更小的三原色发光材料来控制每个像素的颜色的。

image.png

所以通常用红、绿、蓝来表示颜色,也就是 RGB。虽然RGB不能表示肉眼所见的全部颜色,但也足够丰富了,一般的显示器、彩色打印机、扫描仪等都支持它。web开发也离不开他,如:#0064ff 、rgb(0, 100, 255)、rgba(0, 100, 255, 1),都是我们常用的表示颜色的方式。 但是 RGB 是理想化的色彩表示方式,我们只能大致的判断出它偏向红色、绿色还是蓝色,或者颜色立方体的大致位置,除此之外就没有其它信息了,也就很难有办法动态生成一组对比鲜明的颜色。因此,在需要动态构建视觉颜色效果的时候,我们很少直接选用 RGB 色值,而是使用其他色彩表示形式。这其中比较常用的就是HSL、HSV色彩表示方式。

HSL、HSV

类似的还有HSB、HSI,HSV = HSB,HSL ≈ HSI,是一种将RGB色彩模型中的点在圆柱坐标系中的表示法。 转换方法:

image.png

目前,浏览器 css 早已支持HSL的色彩表达。

image.png

表示方式为:

/*  hsl( 色相hue<0~360>, 饱和度saturation<0%~100%>, 亮度lightness<0%~100%> ) */
background: hsl(10,30%,30%);
color: hsla(360,100%,100%,1);

image.png

借助 HSL,就可以很容易生成颜色梯度:

  • 相邻的颜色的颜色梯度,只需要将色相递增或递减即可

    image.png 色相间隔15,饱和度和梯度都是50%:hsl(n*15, 50%, 50%)

  • 亮度颜色梯度,只需要将亮度递增或递减即可

    image.png

    hsl(120/240, 50%, 25+n*5%)

但细心的你一定发现了,在色相梯度中,绿色附近的颜色比较接近,而其他颜色则跨度较大。而且相同亮度情况下,绿色要比蓝紫色看起来要亮上一些,这是因为人眼对不同频率的光的敏感度不同造成的。 因此,HSL依然不完美,于是一套针对人类知觉标准的色彩模型就诞生了:CIELAB

  • 人眼看到的颜色梯度均匀
  • 相同的亮度,让人眼也感觉亮度相同。

CIELAB

CIELCHuv、 CIELCHab是同一个以人类感知为主的色彩模型,只是表示方式不同。

image.png 不规则的色彩空间

目前,仅 Safari 在 15 及以上版本的 css(css-level 4) 才支持 lch()lab()

image.png

lab为例:

/*lab( 亮度<0%~100%> a<-125~125> b<-125~125> ), a/b表示:Lab颜色空间中沿“a”和“b”轴的距离 */
background: lab(45.90% 25.22 -84.96); /* 中间没有逗号 */

image.png lab(59% ${-125+i*10} ${-125+j*10})

可以看到在亮度一致的情况下,各个颜色的感观亮度也一致,且颜色过渡均匀,更适合需要动态生成颜色的场景。

更多色彩空间

色彩空间的发展远远不止上述提到的这些,以知名的 Color.js 颜色转换库支持的色彩空间为例,就支持了数十种,这个库提供了非常直观的 API 设计,可以很方便进行颜色转换,有兴趣的自行了解。

image.png

Color.js Supported Color Spaces

应用案例

antd 颜色算法使用的库:TinyColor

image.png

image.png

https://tinycolor.vercel.app/

zrender (Echarts 依赖的 2D图形库)

https://github1s.com/ecomfe/zrender/blob/HEAD/src/tool/color.ts

image.png

回答开篇需求

有了上述这些色彩空间,和颜色的表示方法,处理颜色渐变肯定不成问题了。至于显示清晰的文字,只需要根据在 CIELAB 模型(HSL 也行)下的亮度,取个相反的即可。各种色彩空间实际都是,在各种场景、需求背景下诞生下的工具,只要工具选对了,问题就能迎刃而解啦。

参考

作者相关知识精选
  • 一图看懂 Typescript 4.9bate 新操作符 satisfies

    image.png

    查看更多
  • TS 类型体操:根据类型获取引用类型的 key

    type TypeKeys<T extends Record<string, any>, Type> = keyof { [Key in keyof T as T[Key] extends Type ? Key : never]: any }
    

    使用案例:点我在线看

    type MyPlugin = {
      name: string
      onFetch: (res: any, payload: Record<string, any>) => void
      onSelect: (selected: any[]) => void
    }
    // 批量触发 plugin 中的函数 hook
    const runNotify = (key: keyof MyPlugin) => {
      //...
    }
    
    runNotify('name') // 开发时没有错误提示
    
    // 改进版
    const runNotifyPlus = (key: TypeKeys<MyPlugin, Function>) => {
      //...
    }
    
    runNotifyPlus('name') // 报错:Argument of type '"name"' is not assignable to parameter of type '"onFetch" | "onSelect"'.(2345)
    
    查看更多
  • Volar 强大、全面的 Vue 开发神器

    随着 Vue3 一大堆新特性的发布,并且源头上支持了 TS,而 Vetur 备受诟病的 性能、TS 支持已经跟不上 Vue 了,于是基于 @vue/reactivity ,实现一切按需计算,提供原生 TypeScript 语言服务级别的性能对 Volar 这一高性能的 Vue 语言插件孕育而生。

    使用方式也很简单,正常通过 vite 创建 Vue 项目即可。

    除了支持 Vue3 基本的语法高亮、和代码提示, Volar 还具备:

    1. 超级快的 .vue 文件解析
    2. 完备的 TypeScript 提示,哪怕是在 <template> 上。
    3. 右上角的代码分割
    4. <style> 里面的 class 引用
    5. CSS Module 类型提示
    6. lang 语法提示
    7. <template> 语法转换

    让人意外的是,Volar 还支持了 vue2,只需要在 ts.config.json 加上个配置即可。

    (文档上说还需安装 @vue/runtime-dom 和删除 .d.ts,但是效果并不好)

    {
      //...
      "vueCompilerOptions": {
        "target": 2,
      },
    }
    

    此外, Volar 还提供了一些开箱即用的插件,有兴趣的可以了解一下

    查看更多