RGB转十六进制

把 rgb()、rgba()、hsl()、hsla() 和纯数字三元组换算成 #RRGGBB 或 #RRGGBBAA,通道值先四舍五入到最近整数再截断到 0~255,并把取整前后的差异一并列出来。

提示:在输入框里直接按 Enter 即可换算;百分比通道、小数通道、hsl() 色相超过 360° 都会被规范化。

使用方法

  1. 在输入框里填一种写法,默认是 rgb(49, 95, 232);改完按 Enter 立即换算,不需要点按钮。
  2. 三种输入都接受:函数写法 rgb(49, 95, 232) / rgba(49, 95, 232, 0.5) / hsl(225, 80%, 55%),逗号或空格分隔都可以,也支持 CSS Color 4 的 / 斜杠语法;以及不带函数名的纯三元组 49, 95, 232。
  3. 通道值可以写整数、小数或百分比:rgb(49.5, 95.4, 231.5) 与 rgb(50%, 100%, 0%) 都会被正确解释成 0~255 的数值。
  4. 结果区给出 #RRGGBB(带透明度时给 #RRGGBBAA)、每个通道取整前后的值、以及 alpha 从 0~1 换算到 0~255 的中间量,便于核对。
  5. 点「复制十六进制」把色值带走;需要成批对照时看下面的「取整对照表」,默认显示 12 行,改行数或点「加载更多」可展开全部 24 行,也可以「导出 CSV」(带 BOM,Excel 不乱码)或「复制对照表」按 TSV 复制。
  6. 点「载入示例」还原 rgb(49, 95, 232),点「清空」清空输入并给出明确提示。

这个 RGB转十六进制工具能解决什么问题

一是把 rgb() 写法压缩成十六进制。设计标注和浏览器开发者工具给出的颜色经常是 rgb(49, 95, 232) 这种长写法,落到样式表里换成 #315FE8 能少 12 个字符;一个页面里几百处颜色,压缩下来对 CSS 体积是有意义的。

二是把 HSL 调色结果落成十六进制。HSL 便于按「色相微调 5 度、亮度降 3%」的思路改色,但很多老系统、图标库、配置文件只认十六进制。RGB转十六进制 会把 hsl() 先按标准公式换成 RGB,再量化成 #RRGGBB。

三是处理小数通道的取整问题。写着 rgb(49.5, 95.4, 231.5) 的色值在手工计算、取色插件和算法混色里很常见,到底是进位还是舍去并不是随便定的;本页用四舍五入到最近整数,并把取整前后的值并排列出,让你一眼看出差在哪一级。

四是生成带透明度的八位色值。rgba(49, 95, 232, 0.5) 这类写法在需要写进配置文件、设计 token 或小程序样式时,往往要转成 #315FE880 这种紧凑形式,本页会把 0.5 精确换算成 Math.round(0.5 × 255) = 128 = 0x80。

本页不做这些事:不解析十六进制(那是十六进制转RGB 那一页的职责,两页刻意不互相跳转)、不把颜色映射成 CSS 颜色名字、不做两种颜色的对比度判定、也不做图像取色与 CMYK 换算。

换算原理:取整、截断与 HSL 反算

第一步是解析输入。先看开头有没有函数名:rgb/rgba 走通道解析,hsl/hsla 先做 HSL→RGB,什么都没有则按纯三元组处理。括号内按逗号、空格或斜杠切分,所以 rgb(49 95 232 / 0.5) 这种 CSS Color 4 写法同样有效。带 % 的通道值按 百分比 ÷ 100 × 255 折算,例如 50% 等于 127.5;这是 CSS 规范里 <percentage> 到 0~255 的固定映射。

第二步是四舍五入。通道值用 Math.round 取最近整数,关键点在于:Math.round 采用的是「.5 一律向正无穷方向进位」,而不是 Python 那种 round() 的银行家舍入。Math.round(0.5) = 1、Math.round(1.5) = 2、Math.round(2.5) = 3、Math.round(127.5) = 128——2.5 在 Python 里会得到 2,在 JavaScript 里得到 3。本页统一按 JavaScript 的规则走,好处是同一段代码在浏览器、Node 与小程序里结果一致,不会出现「网页上算出来是 #808080、后端算出来是 #7F7F7F」这类对不上的问题。

第三步是截断到合法区间。取整之后再把结果夹到 0~255:超过 255 记 255,小于 0 记 0。rgb(-10, 300, 128) 因此变成 rgb(0, 255, 128) 即 #00FF80。CSS 规范对越界的 rgb() 通道就是这种「先按数值处理、再截断」的行为,而不是报错或者取模。

第四步是量化成两位十六进制。每个通道用 toString(16) 转成小写十六进制串,再用 padStart(2, '0') 补齐两位——0 会变成 "0",必须补成 "00",否则 rgb(0, 0, 255) 会被拼成 #000FF 这种五位错误值。最后统一转成大写并与 # 拼接,因为设计标注与 Figma 导出习惯用大写。

第五步是 HSL 反算。先取色相 H、饱和度 S、亮度 L:色相按 360 取模(480° → 120°、-120° → 240°),S 与 L 除以 100 归一到 0~1。然后算 C = (1 − |2L − 1|) × S、X = C × (1 − |H/60 取模 2 − 1|)、m = L − C/2,按色相落在哪个 60° 扇区把 C、X、0 分配给 R、G、B,最后每个通道 × 255 并加上 m。这一段的输出是小数,正好交给上面的四舍五入步骤收口。

alpha 的处理单独成一条。透明度是 0~1 的小数,换算到八位十六进制时同样用四舍五入:A = round(α × 255)。只有当这个结果小于 255 时才输出八位写法;round(α × 255) = 255 时按完全不透明处理,输出六位,和 CSS 的序列化行为保持一致。整套解析、截断与序列化规则依据 W3C 的 CSS Color Module Level 4。

完整示例(数值仅作演示)

下面用页面打开时的默认值 rgb(49, 95, 232) 走一遍 RGB转十六进制 的完整过程:

换一组带小数的通道:rgb(49.5, 95.4, 231.5) 里 49.5 与 231.5 都落在 .5 这个进位边界上,四舍五入后是 (50, 95, 232),对应 #325FE8——和默认的 #315FE8 只差红色通道的 1 级。如果把 49.5 改成 49.4、231.5 改成 231.6,取整结果是 (49, 95, 232),又回到了 #315FE8。

再看百分比写法:rgb(50%, 100%, 0%)。50% 折算成 0.5 × 255 = 127.5,四舍五入进位到 128,即 0x80;100% 是 255;0% 是 0。结果是 #80FF00。如果某个工具在这 里用了截断而不是四舍五入,会得到 #7FFF00,两者相差 1 级红色。

再试HSL 输入:hsl(225, 80%, 55%) 反算出的原始通道是 (48.45, 94.35, 232.05),四舍五入后是 (48, 94, 232),输出 #305EE8。它和 #315FE8 并不是同一个值,红、绿各低 1 级——原因是这个 HSL 是 #315FE8 取整之后的结果,小数信息已经丢了。这也说明 HSL 与十六进制之间来回换算是有损的,需要精确还原时请保留原始的十六进制值。

最后是带透明度的例子:rgba(49, 95, 232, 0.5),颜色部分得到 #315FE8,alpha 部分 Math.round(0.5 × 255) = 128 = 0x80,合并输出 #315FE880。注意这里是 128 而不是 127,用 127 会得到 #315FE87F,透明度差了 1/255。

输入范围与取整对照表

下表把常见的输入写法与它们的取整结果并排列出,默认显示 12 行,点「加载更多」可展开全部 24 行。表里的数字都由本页算法当场算出:第 1 行就是默认示例,第 14 行起是 hsl() 输入的对照。

输入写法原始通道值四舍五入并截断后输出十六进制
rgb(49, 95, 232)49, 95, 23249, 95, 232 #315FE8
rgb(49.5, 95.4, 231.5)49.5, 95.4, 231.550, 95, 232 #325FE8
rgb(49.4, 95.4, 231.6)49.4, 95.4, 231.649, 95, 232 #315FE8
rgb(127.5, 127.5, 127.5)127.5, 127.5, 127.5128, 128, 128 #808080
rgb(0.5, 0.5, 0.5)0.5, 0.5, 0.51, 1, 1 #010101
rgb(0.4, 0.4, 0.4)0.4, 0.4, 0.40, 0, 0 #000000
rgb(50%, 100%, 0%)127.5, 255, 0128, 255, 0 #80FF00
rgb(255.4, 0, 128)255.4, 0, 128255, 0, 128 #FF0080
rgb(-10, 300, 128)-10, 300, 1280, 255, 128 #00FF80
rgb(1, 2, 3)1, 2, 31, 2, 3 #010203
rgba(49, 95, 232, 0.5)49, 95, 23249, 95, 232 A=128 #315FE880
rgba(255, 255, 255, 0.75)255, 255, 255255, 255, 255 A=191 #FFFFFFBF

下表补充说明几个边界写法分别会被解释成什么,规则全部来自 CSS Color Module Level 4:

输入解释取整结果输出
rgb(50%, 100%, 0%)百分比 ÷ 100 × 255127.5 → 128, 255, 0#80FF00
rgb(-10, 300, 128)越界后截断到 0~2550, 255, 128#00FF80
rgb(49 95 232 / 0.5)CSS Color 4 空格 + 斜杠语法49, 95, 232 · A=128#315FE880
hsl(480, 100%, 50%)色相按 360 取模 → 120°0, 255, 0#00FF00
hsl(-120, 100%, 50%)负色相加 360 → 240°0, 0, 255#0000FF
hsl(0, 0%, 0%)亮度 0,与色相无关0, 0, 0#000000
rgba(255, 255, 255, 0.999)round(0.999 × 255) = 255A=255,视为不透明#FFFFFF
rgba(255, 255, 255, 0.003)round(0.003 × 255) = 1A=1,不是 0#FFFFFF01

结果边界与舍入说明

常见问题

rgb(127.5, 127.5, 127.5) 为什么变成 #808080 而不是 #7F7F7F?

因为 127.5 正好落在进位边界上,Math.round(127.5) = 128,128 的十六进制是 0x80。如果换成 127.4,四舍五入到 127(0x7F),得到 #7F7F7F。两者只差 1 级通道,肉眼几乎看不出,但在做像素级比对时会算作不同的颜色。

为什么 50% 的红会是 0x80 而不是 0x7F?

因为百分比到 0~255 的映射是线性的:50% → 0.5 × 255 = 127.5,四舍五入进位到 128,即 0x80。用截断的算法会得到 127,也就是 0x7F。CSS 规范里 <percentage> 到通道值的换算就是这个 0~255 的线性映射,之后再按取整规则量化。

通道值写成 300 或者 −10 会怎样?

会被截断到合法区间:大于 255 记 255,小于 0 记 0。rgb(-10, 300, 128) 的结果是 #00FF80。本页不会因为越界就报错,因为 CSS 对 rgb() 通道越界本身就是这种「截断」行为;只有输入完全没法解析(比如写了 rgb(红, 绿, 蓝))时才会给出报错。

输出的十六进制是大写还是小写?

统一大写,例如 #315FE8。toString(16) 在 JavaScript 里返回的是小写串,本页显式做了转大写,目的是和设计标注、Figma 导出、VS Code 的颜色预览保持一致,方便直接肉眼比对两个色值是否相同。大小写在 CSS 里不影响渲染。

hsl() 的色相写 370、480 或者 −30 会怎样?

按 360 取模后参与计算:370° → 10°、480° → 120°、-30° → 330°。hsl(480, 100%, 50%) 因此与 hsl(120, 100%, 50%) 得到同样的 #00FF00。这和 CSS 规范里色相是「角度」、超出 360 度要环绕的处理方式一致。

透明度 0.5 输出的末两位为什么是 80?

因为八位写法的 alpha 是 0~255 的整数,0.5 × 255 = 127.5,四舍五入进位到 128,128 就是 0x80。如果按截断算成 127,末两位会是 7F,两者相差 1/255 的透明度。顺带一提,alpha 为 1 时本页直接输出六位写法,不再补 FF。

为什么不能直接 Math.floor 或者 parseInt 取整?

因为那样会导致系统性偏暗:所有小数部分都被舍去,平均让每个通道低 0.5 级。同一组颜色在不同工具里换算会出现「有的偏亮有的偏暗」,对不上。四舍五入是无偏的,平均误差为 0,这也是 CSS 序列化和主流图形库的做法。

换算出来的 #RRGGBB 可以直接粘进 CSS 吗?

可以,六位与八位十六进制都是合法的 CSS 颜色值,例如 color:#315FE8 或 background:#315FE880。要留意的是八位写法在老版本浏览器(IE 全系、Android 4.4 自带浏览器)里不被识别,需要兼容时请改用 rgba() 写法。

相关工具