本文详细讲解如何在JavaScript中实现Web颜色值的相互转换。针对DOM样式获取的格式差异及半透明背景需求,提供了从原始代码到优化后的RGB转Hex算法,以及Hex转RGBA的完整实现方案。通过正则表达式匹配与字符串处理,解决颜色格式兼容性问题,并指出代码中关于非法参数处理的潜在优化空间。
引言与问题背景
近期忙于业务需求,许久未更新博客。今日稍有空闲,回顾项目前端代码时,注意到颜色转换功能。在进行颜色设置或编辑时,常需处理不同颜色格式间的互换。本文记录该功能的实现过程,旨在分享经验并促进交流。
先看看问题
在前端开发中,常通过 dom.style.backgroundColor = "#f00" 设置DOM元素背景色,或通过 var bgc = dom.style.backgroundColor 获取背景色。然而,获取与设置的格式可能存在差异,具体表现如下:

若上述对比不够直观,请继续观察后续示例。

显然,同一颜色值在逻辑上应相等,但实际结果却不一致。经测试,Chrome开发工具与Firefox控制台均呈现相同结果,此现象并非个例。
前端开发通常始于还原UI设计稿。设计中常见纯色背景(如 #f00)配合特定不透明度(如 75%)。此时,仅设置 dom.style.backgroundColor = "#f00" 无法实现半透明效果。CSS3引入了 rgba 格式,可通过 dom.style.backgroundColor = "rgba(255, 0, 0, 0.75)" 实现。问题在于,如何在JavaScript中将 ("#f00", 75) 转换为 rgba(255, 0, 0, 0.75)?
接下来,展示具体的实现方法。
RGB(A)转十六进制(HEX)
rgb(a)颜色值转成十六进制颜色(hex)
作为开发者,直接看代码更为高效。首先展示一段原始实现:
<!-- lang: js -->
代码如下:
var rgbToHex = function(rgb) {
var rRgb = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/,
rRgba = /rgba\((\d{1,3}),(\d{1,3}),(\d{1,3}),([.\d]+)\)/,
r, g, b, a, rs = rgb.replace(/\s+/g, "").match(rRgb),
rsa = rgb.replace(/\s+/g, "").match(rRgba);
if (rs) {
r = (+rs[1]).toString(16);
r = r.length == 1 ? "0" + r : r;
g = (+rs[2]).toString(16);
g = g.length == 1 ? "0" + g : g;
b = (+rs[3]).toString(16);
b = b.length == 1 ? "0" + b : b;
return {hex: "#" + r + g + b, alpha: 100};
} else if (rsa) {
r = (+rsa[1]).toString(16);
r = r.length == 1 ? "0" + r : r;
g = (+rsa[2]).toString(16);
g = g.length == 1 ? "0" + g : g;
b = (+rsa[3]).toString(16);
b = b.length == 1 ? "0" + b : b;
a = (+rsa[4]) * 100
return {hex: "#" + r + g + b, alpha: Math.ceil(a)};
} else {
return {hex: rgb, alpha: 100};
}
};
上述代码为何称为“最原始”?因为在代码审查中发现其仍有优化空间。对比优化后的代码:
<!-- lang: js -->
代码如下:
var rgbToHex = function(rgb) {
var rRgba = /rgba?\((\d{1,3}),(\d{1,3}),(\d{1,3})(,([.\d]+))?\)/,
r, g, b, a,
rsa = rgb.replace(/\s+/g, "").match(rRgba);
if (rsa) {
r = (+rsa[1]).toString(16);
r = r.length == 1 ? "0" + r : r;
g = (+rsa[2]).toString(16);
g = g.length == 1 ? "0" + g : g;
b = (+rsa[3]).toString(16);
b = b.length == 1 ? "0" + b : b;
a = (+(rsa[5] ? rsa[5] : 1)) * 100
return {hex: "#" + r + g + b, alpha: Math.ceil(a)};
} else {
return {hex: rgb, alpha: 100};
}
};
优化后不仅减少了一个if分支,代码量也显著降低。在控制台执行相关测试代码(见图示),结果显示方法基本达到预期。但图中红色箭头提示潜在问题:第一个箭头传入 rgb(255, 0, 0, 2),其中第四个参数非标准RGB格式;第二个箭头传入 rgba(255, 0, 0, 1.48),透明度超出合法范围。尽管方法仍能返回结果,但这表明代码在参数合法性校验方面仍有改进空间,供读者自行完善。

从执行结果来看,我们的方法似乎已经能够达到我们的目的了。但是,细心的朋友应该注意到了图中有两个红色箭头,这里是不是有什么坑?不错。我们仔细看看第一个箭头中传入的颜色参数 rgb(255, 0, 0, 2),其实这里并不是一个合法的颜色值,rgb格式的颜色值,是没有第四个(透明度)参数的;再看第二个箭头中 rgba(255, 0, 0, 1.48),这里格式是没问题了,但是透明度却为1.48,其实不是一个合法的透明度值。这两种情况,我们的方法都正常执行了,也正常返回了,说明,我们的方法还有进一步进化的空间,就交给大家自行发挥了!
十六进制(HEX)转RGB(A)
十六进制颜色(hex)转成rgba格式
日常开发中,十六进制颜色值(如 #ff0000、#f00)最为常用。若需将其转换为rgba格式,应如何处理?
<!-- lang: js -->
代码如下:
var hexToRgba = function(hex, al) {
var hexColor = /^#/.test(hex) ? hex.slice(1) : hex,
alp = hex === 'transparent' ? 0 : Math.ceil(al),
r, g, b;
hexColor = /^[0-9a-f]{3}|[0-9a-f]{6}$/i.test(hexColor) ? hexColor : 'fffff';
if (hexColor.length === 3) {
hexColor = hexColor.replace(/(\w)(\w)(\w)/gi, '$1$1$2$2$3$3');
}
r = hexColor.slice(0, 2);
g = hexColor.slice(2, 4);
b = hexColor.slice(4, 6);
r = parseInt(r, 16);
g = parseInt(g, 16);
b = parseInt(b, 16);
return {
hex: '#' + hexColor,
alpha: alp,
rgba: 'rgba(' + r + ', ' + g + ', ' + b + ', ' + (alp / 100).toFixed(2) + ')'
};
};
同样,编写验证代码以测试转换是否正常。执行结果显示方法能获取预期结果。但图中红色箭头再次提示非法透明度与非法颜色值的问题。这部分优化功能同样留给读者自行探索。

从执行结果来看,我们的方法,没有问题了,都能拿到我们想要的转换结果。但这里依然留给了大家两个红色箭头,非法的透明度和非法的颜色值。这部分进化功能也留给大家了,哈哈…
网页颜色值之间的相互转换是老生常谈的话题。本文仅列出一种简单方法,相信存在更多更优方案。欢迎提出建议,共同交流进步。