这篇文章发布于 2010年03月12日,星期五,16:15,归类于 JS实例。 阅读 253794 次, 今日 13 次 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
(本篇完)
- 是时候介绍这几个全新的CSS颜色函数了 (0.393)
- JS判断图像背景颜色单一还是丰富 (0.348)
- ES6 Math方法和Number新特性简介 (0.290)
- CSS全部147个颜色关键字及对应颜色值 (0.086)
- 小tip: 了解LinearRGB和sRGB以及使用JS相互转换 (0.086)
- Canvas中颜色过渡动画效果的实现 (0.086)
- CSS前景背景自动配色技术简介 (0.086)
- 3D LUT 滤镜颜色映射原理剖析与JS实现 (0.086)
- CSS1-CSS3 <color>颜色知识知多少? (0.072)
- PNG格式小图标的CSS任意颜色赋色技术 (0.072)
- SVG图标颜色文字般继承与填充 (RANDOM - 0.028)
楼主太强了,多少年了,后来者的小年轻看了你的东西,都能收获很多,能够帮助
如果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!
不错~~~