HEX、RGB、HSL 怎么换算?为什么调色时 HSL 更顺手
上周做个内部小工具的按钮,设计师给的蓝是 #5BB8FF。正常态用着挺好,hover 我想暗一点,active 再暗一点,再要一个禁用态的浅灰蓝。我盯着 R 91 G 184 B 255 看了半天,R 加几?G 减几?三个数一起改,改出来不是发紫就是发灰。后来我把这颜色换成 HSL:hsl(205, 100%, 68%),把 L 从 68 降到 48,hover 态立刻对了。同色系四个状态一共改了不到十秒。
后来我回想,RGB 改半天改不动,不是因为颜色难,是因为 RGB 这套表达方式不给人改色的把手。下面把三种格式各自是什么捋一遍,再说为什么 HSL 调色顺手。
屏幕颜色本来就是 RGB
屏幕发光靠红、绿、蓝三种子像素叠加,所以底层颜色模型就是 RGB:三个通道,每个 0 到 255,一共能拼出 256 × 256 × 256 = 16777216 种颜色。(0, 0, 0) 是全关等于黑,(255, 255, 255) 是全开等于白,(255, 0, 0) 是纯红。这是物理层面的事实,其他格式都是在这之上的不同写法。
HEX:把 RGB 写成十六进制
HEX 就是把三个通道的十进制数值各自写成两位十六进制,前面加 #,拼一起。比如:
#3498DB
拆开看:
34(十六进制)=3 × 16 + 4 = 52,所以 R = 5298(十六进制)=9 × 16 + 8 = 152,所以 G = 152DB(十六进制)=13 × 16 + 11 = 219,所以 B = 219
所以 #3498DB 等于 rgb(52, 152, 219),同一个颜色,两种写法。CSS 里两种都吃。
为什么前端更爱写 HEX?短。#3498DB 七个字符,rgb(52, 152, 219) 十几个字符,class 名一长串挤一起 HEX 显然更省眼。
RGB 和 RGBA:多一个 Alpha
加透明度就是 RGBA。前三位还是 RGB,第四位是 Alpha 通道。CSS 里 Alpha 是 0 到 1 的小数,0 全透明,1 不透明:
background: rgba(52, 152, 219, 0.5); /* 50% 不透明 */
rgb(52, 152, 219) 和 rgba(52, 152, 219, 1) 是一回事,现代 CSS 里 rgb() 也能写第四个参数,所以 RGB 和 RGBA 在语法上已经合并了。
HSL:按人眼的方式描述颜色
HSL 是另一套坐标系,三个分量是色相 H、饱和度 S、亮度 L:
- H(Hue,色相):0 到 360,单位是度,对应色环上的位置。0 是红,120 是绿,240 是蓝,转一圈 360 回到红。
- S(Saturation,饱和度):0% 到 100%,0% 是灰,100% 是最鲜艳。
- L(Lightness,亮度):0% 到 100%,0% 是纯黑,50% 是正常色,100% 是纯白。
同一个蓝 #3498DB,写成 HSL 是 hsl(204°, 70%, 53%)。
为什么调色时 HSL 比 RGB 直观
这才是关键。RGB 三个通道是给屏幕看的,不是给人调的。你想「再鲜艳一点」,脑子里没有「R 加 12、G 减 5、B 加 8」这种对应关系,只能瞎试。HSL 三个分量分别对应人脑里调色的三个直觉动作:
- 想更鲜艳,调 S。把 S 从 50% 拉到 80%,颜色立刻活起来。
- 想更亮或更暗,调 L。L 从 53% 降到 35%,立刻变深色态;拉到 75%,立刻变浅色态。
- 想换同色系另一个颜色,调 H。蓝色
204°减到180°就是青色,加到230°就是偏紫的蓝。
回头看开头那个 hover 态的例子。#5BB8FF 换算后是 hsl(205°, 100%, 68%),我要的只是「同色相、同饱和度、暗一点」,那就只动 L:68 → 48。派生出一组状态色:
正常 hsl(205°, 100%, 68%) /* #5BB8FF */
hover hsl(205°, 100%, 58%)
active hsl(205°, 100%, 48%)
disabled hsl(205°, 30%, 70%) /* 顺便把 S 降下来变灰 */
这组色在 RGB 里得算半天,在 HSL 里就是改两个数字。这是为什么几乎所有设计软件的调色板都默认给 HSL 滑块,为什么 CSS 也原生支持 hsl()、hsla() 写法。
顺带提两个坑
3 位 HEX 是 6 位的缩写。 CSS 里写 #abc 等于 #aabbcc,每个字符重复一次。所以 #abc 不是随便取的三个值,是 R=aa(170)、G=bb(187)、B=cc(204)。浏览器为了省字节允许这么缩,但只在每两位相同时合法。#3498DB 不能缩写成 #349,那样会变成 #334499,完全是另一种颜色。
Alpha 的写法两套别混。 CSS 函数式里 Alpha 是 0 到 1 的小数(rgba(..., 0.5))。但 8 位 HEX #RRGGBBAA 里最后两位 AA 是 0 到 255 的十六进制:#3498DB80 的 80(十六进制)= 128,128 / 255 ≈ 0.5,所以这俩写出来的不透明度大致相同。常见坑是想写 10% 不透明度,HEX 写了 #3498DB10,结果 10(十六进制)= 16,16 / 255 ≈ 6%,比预期淡了一截。要 10% 得算 0.1 × 255 ≈ 26,写成 1A。
实操:三种格式对着看
写 CSS 的时候与其手算十六进制,不如把颜色丢进 UPTools 颜色转换工具 里。输入任意一种格式(HEX、RGB、HSL 都行),它同时显示三种(带 Alpha 的四种)结果,还有颜色选择器和透明度滑块。所有运算在浏览器本地完成,颜色数据不上传。
三句话总结
屏幕颜色本质是 RGB 三通道叠加,每通道 0-255,HEX 是把它写成两位十六进制拼一起,RGBA 多一个 0-1 的 Alpha。HSL 把同一个颜色改用色相、饱和度、亮度描述,调色时想鲜艳调 S、想亮调 L、换同色系调 H,比直接改 RGB 三通道直观得多。3 位 HEX 是 6 位的缩写(每字符重复两次),而 8 位 HEX 的 Alpha 是 0-255 十六进制,跟 CSS 函数里的 0-1 小数别搞混。
相关文章