理解了 HSL 颜色表示法,就能实现 ColorPicker 组件

选择颜色是常见需求,想必大家都用过 ColorPicker 组件。

比如 Chrome DevTools 的这个:

antd 也有 ColorPicker 组件:

其实浏览器原生也支持 color 类型的 input:

功能更强大,还支持网页颜色吸取。

兼容性也很不错:

那为什么 antd 还在 5.5 版本实现一个 ColorPicker 呢?

应该主要是为了统一 UI 吧,浏览器原生组件各个浏览器都不一样。

比如 safari 的 <input type="color"/> 是这样的:

safari 的这个做的还挺复杂的,还有一个原生的窗口来做选择,支持的功能挺多:

但这样会导致产品在各个浏览器的体验是不一致的。

出于这个原因,我们会用 antd 的 ColorPicker 组件,而不是原生的 color 类型的 input。

那这个颜色选择组件是怎么实现的呢?

这就要学习一些颜色的知识了。

颜色有很多种表示法,RGB 是最常用的,分别是 red、green、blue,还可以用十六进制标识法 #FFFFFF

R、G、B 的取值范围是 0 到 255。

颜色用空格或者逗号分隔都行,最后的 / 后面是透明度,可以用百分比或者小数:

此外,HSL 标识法也很常用,分别是色相、饱和度、亮度,/ 后面是透明度。

色相的取值范围是 0 到 360

饱和度和亮度都是 0% 到 100%

那为什么还会有 0.3turn、150deg 这种单位呢?

因为色相是色相环上的颜色:

美术生应该很熟悉这种色相环,什么相差 60 度是邻近色、相差 180 度是互补色等等。

所以取值范围是 0 到 360 也就是共 360 度。

0.3 turn 就是一圈的 0.3 的地方的颜色,而 150 deg 就是 150 度的地方的颜色。

有 RGB 不就好了么?为啥还要搞个 HSL?

红绿蓝是计算机存储颜色的方式,它喜欢这种表示法,可以直接用来显示颜色。

但是对人来说,是不是还是明暗关系、色彩饱和度更容易理解一点?

所以选色的时候都是基于色相、饱和度、亮度这些东西,但存储的时候使用 RGB,最后屏幕显示颜色也是基于 RGB的。

此外,还有 HSV/HSB,这俩用明度而不是亮度,都是差不多的东西:

所以说,HSL 对人很友好,调解下明暗度、色彩饱和度等很直观。在网页里支持 RGB 和 HSL 这俩表示法。

颜色选择器一般都是基于 HSL 来做的:

你拖动下面的色彩条的时候,调节的就是色相环的位置,色相环为 0 的时候是红色、色相环 360 的时候也是红色,正好转一圈。

你拖动上面的滑块的时候,调节的就是饱和度和亮度。

图中可以看到色相没变,往下滑亮度减少、往左滑饱和度减少。

是不是很直观?调节颜色的体验很好?

那如果用 RBG 来做这种颜色调节呢?

safari 的颜色选择器里就有这个,是这样的:

是不是用起来一脸懵逼?

怎么就变成粉色了,怎么又变紫色了?

不止你懵逼,设计师用起来也懵逼。

所以颜色选择器一般都是 HSL 的,调节色相、饱和度、亮度这三者,而不是直接调节 RGB。

最后显示的时候才转成 RGB。

rgb 和 hsl 的互转算法都是固定的,可以安装用 @swiftcarrot/color-fns 这个包来做:

然后我们具体来看下 ColorPicker 的每一部分怎么实现:

下面这个透明度滑块很容易理解,拖动改变的是透明度,从 0% 到 100%,

滑块设置一个渐变背景就行。

上面色相的滑块也差不多,取值范围是 0 到 360

但它的渐变设置比较麻烦,不是两个颜色的渐变。不然从红色渐变到红色么?

而是根据取色相环不同角度的颜色来设置渐变:

比如取 0、60、120、180、240、360 这些角度共 7 个颜色来渐变:

取出的值是 0 到 360 的色相值。

最后,上面的调整饱和度亮度的部分又是怎么实现的呢?

其实也很简单,也是加了渐变,把渐变去掉就是纯色了。

一共两个渐变:

从下到上是黑色到透明的渐变。

我一般都是写 linear-gradient(to top, xxx,xxx),用 0deg 也可以。看 devtools 标出的小圆圈也很直观。

然后从左到右是从拜到透明的渐变。

这样,就可以根据 left、top 的值,计算出饱和度和亮度的值,从上到下饱和度从 100% 到 0%,从由向左饱和度从 100% 到 0%。

这样通过 3 个滑块,就实现了任意透明度、任意色相、亮度、饱和度的颜色的选取。

之后再转成计算机喜欢的 RGB 就好了。

这就是 ColorPicker 的实现原理。

有同学可能会问,那这个吸色器呢?

这个东西可不是网页里实现的,这个是原生组件,可以很方便的拿到网页渲染的结果,然后取色。

不过浏览器现在也有这个 api 了,叫做 EyeDropper

用起来很简单:

效果也很好:

但是你看看这个惨不忍睹的兼容性:

如果你要吸取颜色,还是用原生组件 <input type="color"/>好了。

总结

选择颜色是常见需求,可以用浏览器的 <input type="color"/> 的原生标签,也可以用 antd 的 ColorPicker 组件。

原生标签虽然支持的功能多,但是各个浏览器实现不一致。

实现这样的颜色选择组件,需要了解颜色表示法:

网页支持的颜色表示法有 RGB、HSL 两种:

RGB 是计算机喜欢的颜色表示法,可以直接用红绿蓝来显示颜色。

HSL 是人更喜欢的颜色表示法,用色相、饱和度、亮度来表示颜色,最后转成 RGB。

(HSV/HSB 和 HSL 是一样的东西,只不过叫明度而不是亮度)

ColorPicker 一般都是用 HSL 来实现的,通过滑块调节色相、饱和度、亮度,显示的时候加上几个渐变,就能实现这种组件:

理解了 HSL 颜色表示法,就能实现 ColorPicker 组件。

相关推荐
魔法少女樱几秒前
如何在idea中写spark程序
前端·javascript·ajax
三思而后行,慎承诺2 分钟前
npm、pnpm 和 yarn 包管理工具
前端·npm·node.js
wuhen_n23 分钟前
CSS元素动画篇:基于当前位置的变换动画(三)
前端·css·html·css3·html5
brzhang25 分钟前
告别面条代码!用可视化编程 Flyde 给你的 Node.js/Web 应用逻辑解解耦
前端·后端·架构
brzhang44 分钟前
还在手撸线程?搞懂这 6 大多线程设计模式,并发编程不再难!
前端·后端·架构
拖孩1 小时前
【Nova UI】十四、打造组件库之按钮组件(下):按钮组组件的构建之旅
前端·javascript·vue.js
pixle01 小时前
Vue3 Echarts 3D圆形柱状图实现教程以及封装一个可复用的组件
前端·3d·vue·echarts
Rudon滨海渔村1 小时前
[随笔] 升级uniapp旧项目的vue、pinia、vite、dcloudio依赖包等
前端·vue.js·uni-app
机构师1 小时前
<uniapp><插件><UTS>在uniapp中,创建自己的插件并发布到uni插件市场
javascript·uni-app·vue·插件·hbuilderx·uni
Watermelo6172 小时前
Vue3调度器错误解析,完美解决Unhandled error during execution of scheduler flush.
前端·javascript·vue.js·elementui·html·es6·bug