前端开发里,颜色格式换来换去是家常便饭:CSS 里手写 HEX,JavaScript 操作 Canvas 用 RGB,做主题色变体、写交互动画又要靠 HSL。三种格式本质描述的是同一个颜色,只是"坐标系"不同。很多人拿到一个 #FF8040 想改成 HSL,或者拿到 rgb(255,128,64) 想塞回 CSS,只能临时打开搜索引擎现查。
这篇文章把三种格式、它们之间的转换公式,以及什么时候该用哪种格式一次讲透,最后给一个能直接用的在线转换工具。
一、先认清三种颜色格式
HEX(十六进制)
写法是 #RRGGBB,一共 6 位十六进制,每两位一组,分别对应红(R)、绿(G)、蓝(B)三个通道。每一位的取值范围是 0~F(即 0~15),所以每两位的范围是 00~FF,对应十进制的 0~255。
例如 #FF8040:
FF= 红通道,等于十进制 255;80= 绿通道,等于十进制 128;40= 蓝通道,等于十进制 64。
HEX 的优点是紧凑、一眼能读,是 CSS 里最常见的手写格式。它还有几种变体:三位缩写 #RGB(#FA0 等价于 #FFAA00),以及带透明度的八位写法 #RRGGBBAA。
RGB(十进制)
写法是 rgb(r, g, b),三个通道都用十进制 0~255 表示,和 HEX 一一对应。比如 rgb(255, 128, 64) 就是上面那个 #FF8040。带透明度时用 rgba(r, g, b, a) 或现代语法 rgb(r g b / a)。
RGB 的优点是直接、和机器底层一致------JS 的 Canvas、CSS 的 rgb() 函数、各种图形库内部都用 RGB,所以代码里操作颜色通常用 RGB。
HSL(色相 - 饱和度 - 明度)
写法是 hsl(h, s%, l%),用三个完全不同的维度描述颜色:
- 色相 H(Hue) :
0~360度,表示在色轮上的位置。0/360是红,120是绿,240是蓝; - 饱和度 S(Saturation) :
0%~100%,0%是灰色,100%是纯色; - 明度 L(Lightness) :
0%~100%,0%是黑,100%是白,50%是正常亮度。
HSL 不是另一种"物理表示",而是把颜色重新组织成"人怎么调色"的维度------想变亮就调 L,想变灰就调 S,想换颜色就转 H。
三种格式对比
| 维度 | HEX | RGB | HSL |
|---|---|---|---|
| 通道 | R、G、B 各 2 位十六进制 | R、G、B 各 0~255 | H(0360)、S、L(0100%) |
| 可读性 | 紧凑,但看不出颜色倾向 | 直观,但不方便调色 | 最符合"调色直觉" |
| 常见用途 | CSS 手写、设计稿标色 | JS/Canvas/图形库操作 | 调色、色阶、主题变体 |
| 调色难度 | 高(改一个通道靠猜) | 中 | 低(明暗、鲜艳度直接调) |
| 本质 | RGB 的十六进制写法 | 三原色叠加 | 色彩三要素重新组织 |
二、HEX ↔ RGB 互转
这两个格式其实是一回事,只是"进制"不同:HEX 是十六进制,RGB 是十进制。
HEX → RGB
把 #RRGGBB 拆成三段,每段十六进制转十进制即可。
十六进制转十进制的规则:两位十六进制 XY,其十进制值 = X × 16 + Y,其中 A~F 分别代表 10~15。
拿 #FF8040 举例:
FF=15 × 16 + 15=25580=8 × 16 + 0=12840=4 × 16 + 0=64
所以 #FF8040 = rgb(255, 128, 64)。
RGB → HEX
反过来,把每个十进制转成两位十六进制,不足两位前面补 0,再按 R、G、B 顺序拼接。
十进制转十六进制用"除 16 取余":
255 ÷ 16 = 15 余 15,15就是F,所以是FF;128 ÷ 16 = 8 余 0,所以是80;64 ÷ 16 = 4 余 0,所以是40。
拼起来就是 #FF8040。小于 16 的记得补前导 0:比如十进制 10 要写成 0A,否则 #A 会被当成三位缩写。
三、RGB ↔ HSL 互转(重点公式)
HEX 和 RGB 是进制换算,简单。但 RGB 和 HSL 之间是真正的"坐标变换",手算起来容易错,值得把公式写清楚。
RGB → HSL
设 r' = r/255、g' = g/255、b' = b/255(先把 0~255 归一化到 0~1)。
- 找最大值、最小值与差:
max = max(r', g', b')min = min(r', g', b')delta = max - min
- 明度 L :
L = (max + min) / 2
- 饱和度 S :
- 若
delta = 0(三通道相等,是灰色),则S = 0; - 否则
S = delta / (1 - |2L - 1|)
- 若
- 色相 H :
- 若
delta = 0,则H = 0; - 若
max = r',则H = 60 × (((g' - b') / delta) mod 6); - 若
max = g',则H = 60 × ((b' - r') / delta + 2); - 若
max = b',则H = 60 × ((r' - g') / delta + 4); - 若算出
H < 0,加 360 转正。
拿#FF8040走一遍完整流程:
- 若
r' = 1,g' = 128/255 ≈ 0.502,b' = 64/255 ≈ 0.251max = 1,min ≈ 0.251,delta ≈ 0.749L = (1 + 0.251) / 2 ≈ 0.625→62.5%S = 0.749 / (1 - |2×0.625 - 1|) = 0.749 / (1 - 0.25) = 0.749 / 0.75 ≈ 1→100%- 因为
max = r',H = 60 × ((0.502 - 0.251) / 0.749) = 60 × 0.335 ≈ 20.1°
结果是 hsl(20°, 100%, 62.5%),约等于 hsl(20, 100%, 63%)------一个色相 20 度的橙色,饱和拉满。和 #FF8040 肉眼看到的橙红色完全对得上。
HSL → RGB
反向转换常用"chroma(彩度)"法,思路更清晰:
C = (1 - |2L - 1|) × SX = C × (1 - |(H / 60) mod 2 - 1|)m = L - C / 2- 按 H 所在区间确定中间值
(R', G', B'):0° ≤ H < 60°:(C, X, 0)60° ≤ H < 120°:(X, C, 0)120° ≤ H < 180°:(0, C, X)180° ≤ H < 240°:(0, X, C)240° ≤ H < 300°:(X, 0, C)300° ≤ H < 360°:(C, 0, X)
- 最终
R = (R' + m) × 255,G、B同理。
把 hsl(20°, 100%, 62.5%) 代回去,会得到约 rgb(255, 128, 64),往返一致,验证公式正确。
这套公式看起来绕,但它是标准算法,所有图形库、浏览器内核内部都这么算。记不住没关系,理解"为什么要归一化、为什么要分区间"就够了,实际换算交给工具。
四、HSL 到底好在哪
很多人会问:有 HEX 和 RGB 了,为什么还要记 HSL?答案是------HSL 把"调色"这件事从数学问题变成了直觉问题 。
1. 想调亮调暗,只改 L
把 hsl(20, 100%, 63%) 调亮,直接把明度从 63% 提到 75%,颜色变浅但色相不变。同样的操作在 HEX 里,你得同时推高 R、G、B 三个值并保证比例不变,#FF8040 调亮该改成 #FF9A66 还是 #FFB08C?肉眼很难直接给出答案,HSL 里却是一句话。
2. 生成同色系的色阶
做一个按钮的 hover、active 状态,或者一组渐变色,只需要锁定 H 和 S,把 L 从浅到深排开,就得到一套和谐的同色色阶。这也是 Tailwind 这类设计系统里颜色令牌(如 orange-100 到 orange-900)背后的生成逻辑。
3. 找互补色、邻近色
互补色直接 H + 180;邻近色 H ± 30;三等分配色 H + 120、H + 240。这些色彩关系在 HSL 里就是简单的加减法,在 HEX 里几乎无法心算。
4. 做饱和度、灰阶调整
想让一个颜色"变灰"(去饱和),把 S 从 100% 降到 30% 即可。这在设计"置灰按钮""禁用状态"时极其常用。
五、手算容易错,什么时候该用工具
手工换算有两个高频坑:
- 补 0 遗漏 :RGB 里
10转 HEX 是0A,漏了前导 0 就变成#A,解析成三位缩写后颜色完全跑偏; - RGB↔HSL 的分区间公式 :
H的六段区间、delta=0的灰色特判,稍不注意就得到错误的色相或负值。
所以实际的正确姿势是:公式用来理解原理,转换交给工具。输入任意一种格式,其它格式实时输出,既快又不会错。
星点颜色格式转换就做这件事:HEX、RGB、HSL 三种格式互转,输入一个,另外两个实时同步输出,不用下载、不用注册,写 CSS、做主题色、核对设计稿色值时随手一用。
六、小结
- HEX 和 RGB 本质是同一套 RGB 坐标的"十六进制 / 十进制"两种写法,互转就是进制换算;
- HSL 是色彩三要素(色相、饱和度、明度)的重新组织,调色更符合直觉;
- RGB↔HSL 有标准公式,理解即可,不必死记,转换交给在线工具;
- 做主题变体、色阶、互补色这类"调色"场景,优先用 HSL 思考,再转成项目需要的 HEX/RGB。
下次再遇到 #FF8040 这种色值,别再对着十六进制心算了,直接丢进星点颜色格式转换,一秒拿到 rgb(255,128,64) 和 hsl(20,100%,63%)。
星点颜色格式转换(xingdian.net/app/color/convert/)。