这篇文章发布于 2010年03月12日,星期五,16:15,归类于 JS实例。 阅读 261699 次, 今日 35 次 22 条评论
by zhangxinxu from https://www.zhangxinxu.com
本文地址:https://www.zhangxinxu.com/wordpress/?p=646
一、关于颜色的表示
颜色的表示方式不知一种,从photoshop的取色面板就可以看出,如下:

上图共显示了5种颜色的表示方法:HSB,lab,RGB,CMYK与十六进制表示法
在CSS中,我们也经常与颜色打交道,其中有color(文字颜色),还有一个就是background-color背景颜色,还有就是border-color。一般,我们习惯用十六进制表示颜色,//zxx:AS中也是如此,不过是以”0x”打头,而不是”#”,例如黑色表示为:#000000;在CSS 2.1中,还支持RGB的颜色表示法,IE,Firefox等浏览器均支持,例如黑色可以表示为RGB(0, 0, 0);
在CSS3中,增加了 HSL colors HSLA colors RGBA colors表示方法,不过这些这里不讨论。
更多颜色的知识可以点击这里:维基百科-颜色
二、颜色表示方式转换的必要性
这确实是个疑问,虽说在CSS中有两种颜色表示方法,那么为什么还有进行颜色表示方式的转换呢,不都是一样的表示颜色吗?
确实,大多数情况下,转换时没有必要的,但是web页面千变万化,遇到的情况千奇百怪,是有需要转换的情况。
举个我遇到的例子吧,我去年9月份,学习Ajax的时候,做过一个Ajax+PHP多人在线聊天室聊天室(访问该页面点击这里),其中里面有个很重要的工具就是取色面板,用以改变显示的文字颜色的。见下图:

里面对颜色字符做了些处理,就是以十六进制的形式显示。做处理归根结底的原因就是浏览器的差异,差异如下:
在Firefox浏览器下(chrome同样),即使你使用了十六进制形式表示了颜色值,但是在HTML页面中,其却是以RGB形式表示的,这与IE浏览器是不一致的。也就是说,如果不做字符显示的处理的话,那么Firefox浏览器下,上面的聊天颜色面板获得的值就是类似于RGB(255,0,0)这种形式的,而不是”#FF0000″,我们可以做个简单的测试,看如下的代码。
<button style="color:#ff3300;" onclick="javascript:alert(this.style.color);">点击我</button>
您可以自己点击下面的按钮测试一下:
可见,这种颜色表示的差异性,使得有时候,颜色转换成为的必须。
三、JavaScript颜色转换的核心
JavaScript颜色转换的核心就是进制间的转换。RGB格式其实就是十进制表示法,所以,十六进制颜色与RGB颜色的转换就是十六进制与十进制之间的转换。
十六进制转换为十进制相对容易些,核心代码如下示例:parseInt("0xFF"),其结果就是255,”0x”就表明当前是16进制,由于parseInt后面无参数,默认就是转换为10进制了。
十进制转换为16进制,核心代码如下:var num=255; num.toString(16);,其结果是FF。”16″表示数值转换为16进制字符串。
四、JavaScript颜色表示方式的转换的实现
转换代码如下,首先是RGB颜色转换为十六进制表示:
String.prototype.colorHex = function(){
var that = this;
//十六进制颜色值的正则表达式
var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
// 如果是rgb颜色表示
if (/^(rgb|RGB)/.test(that)) {
var aColor = that.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
var strHex = "#";
for (var i=0; i<aColor.length; i++) {
var hex = Number(aColor[i]).toString(16);
if (hex.length < 2) {
hex = '0' + hex;
}
strHex += hex;
}
if (strHex.length !== 7) {
strHex = that;
}
return strHex;
} else if (reg.test(that)) {
var aNum = that.replace(/#/,"").split("");
if (aNum.length === 6) {
return that;
} else if(aNum.length === 3) {
var numHex = "#";
for (var i=0; i<aNum.length; i+=1) {
numHex += (aNum[i] + aNum[i]);
}
return numHex;
}
}
return that;
};
然后是十六进制颜色转为RGB格式:
String.prototype.colorRgb = function(){
var sColor = this.toLowerCase();
//十六进制颜色值的正则表达式
var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
// 如果是16进制颜色
if (sColor && reg.test(sColor)) {
if (sColor.length === 4) {
var sColorNew = "#";
for (var i=1; i<4; i+=1) {
sColorNew += sColor.slice(i, i+1).concat(sColor.slice(i, i+1));
}
sColor = sColorNew;
}
//处理六位的颜色值
var sColorChange = [];
for (var i=1; i<7; i+=2) {
sColorChange.push(parseInt("0x"+sColor.slice(i, i+2)));
}
return "RGB(" + sColorChange.join(",") + ")";
}
return sColor;
};
上面颜色转换方法使用示意:
var sRgb = "RGB(23, 245, 56)" , sHex = "#34538b"; var sHexColor = sRgb.colorHex(); var sRgbColor = sHex.colorRgb();
其中colorHex()表示转换为十六进制方法,colorRgb()表示转为RGB颜色值的方法。
您可以狠狠地点击这里:测试demo页面
您也可以直接在下面进行测试:
十六进制颜色值:
GRB颜色值:
说明:此JavaScript实现的一个小小原则是“以统一的形式显示”,所以十六进制缩写的颜色值(如:#333)会以#333333显示。如果转为的字符格式不匹配或是值溢出返回,则会原值返回。例如:RGB(0,0,256)会返回RGB(0,0,256),#3456会返回#3456,#egd会返回#egd。
新增于2015-05-20
这里再附上HSL转RGB以及RGB转HSL的代码,出处见这里。
HSL转RGB
/**
* HSL颜色值转换为RGB.
* 换算公式改编自 http://en.wikipedia.org/wiki/HSL_color_space.
* h, s, 和 l 设定在 [0, 1] 之间
* 返回的 r, g, 和 b 在 [0, 255]之间
*
* @param Number h 色相
* @param Number s 饱和度
* @param Number l 亮度
* @return Array RGB色值数值
*/
function hslToRgb(h, s, l) {
var r, g, b;
if(s == 0) {
r = g = b = l; // achromatic
} else {
var hue2rgb = function hue2rgb(p, q, t) {
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
RGB转HSL
/**
* RGB 颜色值转换为 HSL.
* 转换公式参考自 http://en.wikipedia.org/wiki/HSL_color_space.
* r, g, 和 b 需要在 [0, 255] 范围内
* 返回的 h, s, 和 l 在 [0, 1] 之间
*
* @param Number r 红色色值
* @param Number g 绿色色值
* @param Number b 蓝色色值
* @return Array HSL各值数组
*/
function rgbToHsl(r, g, b) {
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if (max == min){
h = s = 0; // achromatic
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, l];
}
这里转换的HSL并不能直接当作CSS颜色值处理,因为范围不一样。
H指Hue(色调)。 0(或360)表示红色,120表示绿色,240表示蓝色,当然可取其他数值来确定其它颜色;
S指Saturation(饱和度)。 取值为0%到100%之间的值;
L指Lightness(亮度)。 取值为0%到100%之间的值;
自己需要再转换下。
关于HSL,可以参见这里:css3-hsl-colors
补充于2018-11-23
增加个RGB转HSB/HSV的方法:
function rgbToHsv(r, g, b) {
r = r / 255;
g = g / 255;
b = b / 255;
var h, s, v;
var min = Math.min(r, g, b);
var max = v = Math.max(r, g, b);
var l = (min + max) / 2;
var difference = max - min;
if (max == min) {
h = 0;
} else {
switch (max) {
case r:
h = (g - b) / difference + (g < b ? 6 : 0);
break;
case g:
h = 2.0 + (b - r) / difference;
break;
case b:
h = 4.0 + (r - g) / difference;
break;
}
h = Math.round(h * 60);
}
if (max == 0) {
s = 0;
} else {
s = 1 - min / max;
}
s = Math.round(s * 100);
v = Math.round(v * 100);
return [h, s, v];
}
补充于2020-06-29
今天发现需要用到HSV/HSB转RGB色值的场景,补上一段代码:
// 参数arr的3个值分别对应[h, s, v]
function hsvToRgb(arr) {
var h = arr[0], s = arr[1], v = arr[2];
s = s / 100;
v = v / 100;
var r = 0, g = 0, b = 0;
var i = parseInt((h / 60) % 6);
var f = h / 60 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
switch (i) {
case 0:
r = v; g = t; b = p;
break;
case 1:
r = q; g = v; b = p;
break;
case 2:
r = p; g = v; b = t;
break;
case 3:
r = p; g = q; b = v;
break;
case 4:
r = t; g = p; b = v;
break;
case 5:
r = v; g = p; b = q;
break;
default:
break;
}
r = parseInt(r * 255.0)
g = parseInt(g * 255.0)
b = parseInt(b * 255.0)
return [r, g, b];
}
补充于2017年9月19日
再补充个任意色值(甚至是CSS颜色关键字)转换为RGB颜色的方法,此方法IE9+浏览器支持,基于DOM特性实现。
var colorToRgb = function (color) {
var div = document.createElement('div');
div.style.backgroundColor = color;
document.body.appendChild(div);
var c = window.getComputedStyle(div).backgroundColor;
document.body.removeChild(div);
return c;
};
需要保证color是不带透明度的,否则最后得到的回事RGBA颜色,而不是RGB颜色。
五、结语
我js资历尚浅,所以代码可能会遇到以下些不足:
1、可能漏了些特殊情况;
2、在效率方面还可以进一步改进;
3、在算法上可以进一步优化;
欢迎指出这些不足。

本文为原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[https://www.zhangxinxu.com]
本文地址:https://www.zhangxinxu.com/wordpress/?p=646
(本篇完)
- JS判断图像背景颜色单一还是丰富 (0.387)
- 是时候介绍这几个全新的CSS颜色函数了 (0.326)
- ES6 Math方法和Number新特性简介 (0.323)
- 全新的CSS相对颜色语法-使用from和calc() (0.290)
- CSS全部147个颜色关键字及对应颜色值 (0.094)
- 小tip: 了解LinearRGB和sRGB以及使用JS相互转换 (0.094)
- Canvas中颜色过渡动画效果的实现 (0.094)
- CSS文字和背景color自动配色技术简介 (0.094)
- 3D LUT 滤镜颜色映射原理剖析与JS实现 (0.094)
- CSS1-CSS3 <color>颜色知识知多少? (0.075)
- SVG图标颜色文字般继承与填充 (RANDOM - 0.029)


楼主太强了,多少年了,后来者的小年轻看了你的东西,都能收获很多,能够帮助
如果16进制的颜色种夹杂着一些单词颜色 ,想统一转成rba,有什么方案
最后有介绍吧,getComputedStyle加DOM特性可以获取。
感谢 大佬分享!学习下
HSL转RGB代码中:
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h – 1/3);
这三行中的h应该先除以360,否则转换出来是错误的。
h = h/360;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h – 1/3);
这位老铁是对的
很赞的文章,收走了,留个脚印,谢谢。
* 换算公式改编自 http://en.wikipedia.org/wiki/HSL_color_space.
已经更新
应该是
https://en.wikipedia.org/wiki/HSL_and_HSV
rgb转hex有点问题
rbg小于16时,转16进制只有一位数,导致输出有误
源码:
if (hex === ‘0’) { hex += hex }
我的改进:
hex = hex < 16 ? '0' + hex : hex
hex = Number(aColor[i]) < 16 ? '0' + hex : hex;
您的源码里的校验hex颜色的正则是这么写的:var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
其中“A-f”这里应该是“A-F”,否则无法匹配大写的F。
哈哈哈,我知道了,之所以你这里没有出错,是因为你函数正文里全都转换为小写了。
好的,感谢反馈,已修正。
RGB转HSL那个函数,h/=6是不应该修改为h*=60?
H是一个角度值(0-360)
这个有个BUG 在CHROME下面 有些颜色转换不了
不好意思没事了,由于字符集编码问题,下载后的源码注释包括第一行代码是乱码导致的。现在可以了。感谢博主的倾情付出!
谢谢!
抱歉,昨天发的代码还应该改进一下,保证了一位数前面补0的情况:
var colorHex = function(value) {
var color = value.replace(/[^\d,]/g, ”).replace(/(\d+)/g, function(s, s1) {
var v = parseInt(s1).toString(16);
return v.length == 1 ? ‘0’+v : v;
});
return ‘#’+color.replace(/,/g, ”).toUpperCase();
};
rgb转16进制也可以这样,代码更少:
var colorHex = function(value) {
var color = value.replace(/[^\d,]/g, ”).replace(/(\d+)/g, function(s, s1) {
return parseInt(s1).toString(16);
});
return ‘#’+color.replace(/,/g, ”).toUpperCase();
};
不错 谢了
谢谢!not bad!
不错~~~