使用方法
- 在输入框里填一种写法,默认是
rgb(49, 95, 232);改完按 Enter 立即换算,不需要点按钮。 - 三种输入都接受:函数写法
rgb(49, 95, 232)/rgba(49, 95, 232, 0.5)/hsl(225, 80%, 55%),逗号或空格分隔都可以,也支持 CSS Color 4 的/斜杠语法;以及不带函数名的纯三元组49, 95, 232。 - 通道值可以写整数、小数或百分比:
rgb(49.5, 95.4, 231.5)与rgb(50%, 100%, 0%)都会被正确解释成 0~255 的数值。 - 结果区给出
#RRGGBB(带透明度时给#RRGGBBAA)、每个通道取整前后的值、以及 alpha 从 0~1 换算到 0~255 的中间量,便于核对。 - 点「复制十六进制」把色值带走;需要成批对照时看下面的「取整对照表」,默认显示 12 行,改行数或点「加载更多」可展开全部 24 行,也可以「导出 CSV」(带 BOM,Excel 不乱码)或「复制对照表」按 TSV 复制。
- 点「载入示例」还原
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转十六进制 的完整过程:
- 三个通道都已经是整数,
Math.round不改变数值; - 转十六进制:
49 → "31"、95 → "5F"、232 → "E8",拼起来是 #315FE8; - 没有 alpha,输出六位写法,不补
FF。
换一组带小数的通道: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, 232 | 49, 95, 232 | #315FE8 |
| rgb(49.5, 95.4, 231.5) | 49.5, 95.4, 231.5 | 50, 95, 232 | #325FE8 |
| rgb(49.4, 95.4, 231.6) | 49.4, 95.4, 231.6 | 49, 95, 232 | #315FE8 |
| rgb(127.5, 127.5, 127.5) | 127.5, 127.5, 127.5 | 128, 128, 128 | #808080 |
| rgb(0.5, 0.5, 0.5) | 0.5, 0.5, 0.5 | 1, 1, 1 | #010101 |
| rgb(0.4, 0.4, 0.4) | 0.4, 0.4, 0.4 | 0, 0, 0 | #000000 |
| rgb(50%, 100%, 0%) | 127.5, 255, 0 | 128, 255, 0 | #80FF00 |
| rgb(255.4, 0, 128) | 255.4, 0, 128 | 255, 0, 128 | #FF0080 |
| rgb(-10, 300, 128) | -10, 300, 128 | 0, 255, 128 | #00FF80 |
| rgb(1, 2, 3) | 1, 2, 3 | 1, 2, 3 | #010203 |
| rgba(49, 95, 232, 0.5) | 49, 95, 232 | 49, 95, 232 A=128 | #315FE880 |
| rgba(255, 255, 255, 0.75) | 255, 255, 255 | 255, 255, 255 A=191 | #FFFFFFBF |
下表补充说明几个边界写法分别会被解释成什么,规则全部来自 CSS Color Module Level 4:
| 输入 | 解释 | 取整结果 | 输出 |
|---|---|---|---|
| rgb(50%, 100%, 0%) | 百分比 ÷ 100 × 255 | 127.5 → 128, 255, 0 | #80FF00 |
| rgb(-10, 300, 128) | 越界后截断到 0~255 | 0, 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) = 255 | A=255,视为不透明 | #FFFFFF |
| rgba(255, 255, 255, 0.003) | round(0.003 × 255) = 1 | A=1,不是 0 | #FFFFFF01 |
结果边界与舍入说明
- 单通道最大取整误差是 0.5,相对满量程 255 是
0.5 ÷ 255 ≈ 0.196%;相邻两档之间的最小步长是1 ÷ 255 ≈ 0.392%,也就是说 8 位色深下 1 级通道差在视觉上就对应约 0.4% 的亮度变化。 .5一律进位。Math.round(0.5) = 1、Math.round(127.5) = 128、Math.round(255.5) = 256(随后被截断回 255)。这不同于 Python 的round()(银行家舍入,round(2.5) = 2)和 C 的trunc(直接舍去),跨语言对齐颜色时必须统一规则。- 截断发生在取整之后。先
Math.round再夹到 0~255,所以255.4 → 255、255.5 → 255、-0.4 → 0。如果先截断再取整,255.5会被算成 255 或 256,结果不稳定。 - alpha 的边界比 RGB 更敏感。0~1 只有 256 档,
α = 0.999会进位成 255 而被当成完全不透明、输出六位写法;α = 0.003会进位成 1 而不是 0,输出#FFFFFF01。想让颜色真正透明请写α = 0,不要写一个很小的小数。 - 色相取模、饱和度与亮度夹紧。
480°等价于120°、-120°等价于240°;S 与 L 小于 0 记为 0、大于 100% 记为 100%。这些都在换算之前完成,不会影响十六进制的位数。 - 输出只可能是六位或八位。六位是
#RRGGBB,八位是#RRGGBBAA;本页不输出三位或四位缩写。虽然#38f更短,但它要求三个通道的两位十六进制完全相同(11/22/33……FF),绝大多数颜色不满足,硬压缩会明显偏色。 - 八位写法的字节顺序是 CSS 的 #RRGGBBAA,alpha 在最后。Android 与 Java 的 ARGB 整数是
#AARRGGBB,把#315FE880直接塞进Color.parseColor,含义会从「半透明的蓝紫」变成完全不同的颜色。
常见问题
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() 写法。
相关工具
- 颜色选择器:从取色盘里挑一个颜色,直接读出十六进制、RGB 与 HSL 三种写法。
- 颜色对比度检测:按 WCAG 相对亮度公式算前景与背景的对比度,检查是否达到 4.5:1 与 7:1 的阈值。
- 互补色颜色查询:给定一个颜色求它在色环上的互补色,配色时用来拉开对比。
- Pastel颜色生成器:批量生成低饱和度的柔和色,输出可以直接使用的色值。
- CMYK转RGB转换器:把印刷用的 CMYK 油墨比例换算成屏幕用的 RGB,补齐本页不做的那一段。
- 随机颜色生成器:随机抽一个颜色并给出它的各种写法,用来填充占位图或测试数据。
- 调色工具:把基色按明度与饱和度微调成同色系的深浅变化,再回到本页量化成十六进制。
- 颜色工具:查看全部颜色工具。