参考资料过多,内容大同小异,便不举出。只给出MDN的颜色选择器示例,可参考其代码。
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Colors/Color_picker_tool
基础概念
颜色空间
颜色空间有很多,网页颜色拾取器涉及到的基本只有3种:RGB,HSV,HSL。
HEX为RGB的16进制表示法,不是单独的颜色空间。
以下内容主要针对透明度,对于颜色空间的理解并无帮助。
CSS颜色混合
由于透明度是模拟光线穿过透明玻璃的情形,故含alpha的颜色混合满足结合律,但不满足分配率,所以颜色混合的先后顺序有要求。
css中,后写入的颜色先渲染,亦即后写入的颜色在后。第一个写入的颜色最后渲染,在最前。
实现
颜色拾取
通常使用HSV表示法。由条状hue
,条状alpha
和,x轴表示saturation
y轴表示value
的平面组成。
alpha
比较容易解决,以下内容不提及。
拾取区域背景
hue
是由六原色组成的渐变背景。(原因未知)
background: linear-gradient(90deg, #f00 0, #ff0 16.7%, #0f0 33.3%, #0ff 50%, #00f 66.7%, #f0f 83.3%, #f00)
平面是三色混合(黑,白,hue
)组成的渐变背景。(原因未知,但此颜色空间为HSV空间)
background: linear-gradient(0deg, #000, transparent),linear-gradient(90deg, #fff, transparent),${hue}
鼠标事件获取坐标
相对页面左上角:event.pageX - element.getBoundingClientRect().left + window.scrollX
相对窗口左上角:event.clientX - element.getBoundingClientRect().left
两种皆可(y轴同理)
注意:
getBoundingClientRect()
获取到的为静态值,每次都应重新获取以防止元素位置变动
从坐标计算出颜色
坐标到HSV
由于使用的HSV坐标,坐标值转换为百分比值就能轻松得到结果。
坐标与值对应关系如下:
hue
坐标:左 -> 右 | 0 ->xRange
;值: 左 -> 右 | 0 -> 360(同向)saturation
坐标:左 -> 右 | 0 ->xRange
;值: 左 -> 右 | 0 -> 100(同向)value
坐标:上 -> 下 | 0 ->yRange
;值: 上 -> 下 | 100 -> 0(逆向)
xRange
为width
-1。yRange
同理。
坐标到HSL
从RGB转到HSL。(没有找到别的思路,也没有找到HSV转HSL)
坐标到RGB
有两种方法:
- 从HSV转到RGB
- 用RGB颜色混合算法计算
HSV转RGB资料很多。以下介绍RGB颜色混合算法。
首先需要获取hue
的RGB值,可通过坐标和变化规律,直接计算得到。直接上代码。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27// 单位长度
const hueUnit = 255 * 6 / xRange
// 分隔长度
const hueRange = xRange / 6
// 从坐标计算rgb单通道值
function getAddedColorFromCoordinate(deltaX) {
return deltaX > hueRange ? 255 : Math.round(deltaX * hueUnit)
}
function getCutColorFromCoordinate(deltaX) {
return deltaX > hueRange ? 0 : Math.round(255 - deltaX * hueUnit)
}
// hue变化格式
const hueFormat = [c => `rgb(255, ${c}, 0)`, c => `rgb(${c}, 255, 0)`, c => `rgb(0, 255, ${c})`, c => `rgb(0, ${c}, 255)`, c => `rgb(${c}, 0, 255)`, c => `rgb(255, 0, ${c})`,]
function getHueFromCoordinate(x) {
let hue
for (let i = 1; i <= 6; i++) {
if (x <= hueRange * i) {
if (i % 2 === 1) {
hue = getAddedColorFromCoordinate(x - hueRange * (i - 1))
} else {
hue = getCutColorFromCoordinate(x - hueRange * (i - 1))
}
return hueFormat[i - 1](hue)
}
}
}
然后是计算坐标处颜色混合的结果。
两颜色混合算法详细可见:带Alpha通道的色彩叠加问题或两个半透明颜色的叠加计算方法
RGBA
两颜色混合是分别计算R、G、B的通道值获得的。给出R通道值的计算方法,G、B通道值同理。(α值混合后颜色的透明度。Cr指混合后颜色的R通道值。C1在前,C2在后。)
α = α1 + α2 - α1 * α2
Cr = (C1r * α1r + C2r * α2r - C2r * α1r * α2r) / α
rgba(0, 0, 0, y), rgba(255, 255, 255, x), rgba(Cr, Cg, Cb, 1)
(css混合顺序)混合的R、G、B通道值计算方法为:
C = (255 * (xRange - x) * (yRange - y) + C3 * x * (yRange - y)) / (xRange * yRange)
从颜色计算出坐标
响应用户输入颜色需要。
HSV到坐标
由于颜色拾取区域为HSV坐标,由坐标到HSV反推即可。
HSL到坐标
HSL转RGB后转坐标。
RGB到坐标
有两种方法:
- 从RGB转到HSV
- 从RGB颜色混合算法解方程(不建议)
RGB转HSV的资料很多,不进行研究。
从RGB颜色混合算法计算解方程,可以实现。
前提为得知
hue
的R、G、B通道值。所知方法为RGB转HSV获得hue
,再将hue
转为RGB。略麻烦,不推荐,只顺手研究下。
以下式子中:C为混合后R、G、B通道值,C’为hue
的R、G、B通道值
deltaC = max(C1, C2, C3) - min(C1, C2, C3)
- 当
deltaC
不为0时:
deltaC' = max(C1', C2', C3') - min(C1', C2', C3')
y = yRange * (255 - C - (255 - C') * deltaC / deltaC') / 255
x = xRange * yRange * deltaC / ((yRange - y) * deltaC)
- 当
deltaC
为0时:
得到各C相等。从三色混合计算中可知,若要C全相等,则C’也要全相等或,x为0。但易从hue变化格式中发现,C’不可能全相等。故此时x = 0
,y = yRange * (255 - C)
颜色转换代码
RGB转HSV
1 | function RGBArrayToHSVArray([red, green, blue]) { // r, g, b值范围为0-1 |
RGB转HSL
1 | function RGBToHSL([red, green, blue]) { // r, g, b值范围为0-1 |
HSL转RGB
1 | function HSLToRGB([hue, saturation, lightness]) { // 0-360, 0-100, 0-100 |
HSV转RGB
1 | function HSVToRGB([hue, saturation, value]) { // 0-360, 0-100, 0-100 |
颜色格式正则判断
1 | const colorFormat = Object.freeze({ |