JS HEX十六进制与RGB, HSL颜色的相互转换

这篇文章发布于 2010年03月12日,星期五,16:15,归类于 JS实例。 阅读 159651 次, 今日 51 次 17 条评论

 

一、关于颜色的表示

颜色的表示方式不知一种,从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>

结果Firefox下的显示是,如下图:
Firefox浏览器下的颜色显示 张鑫旭-鑫空间-鑫生活

而IE浏览器下则是:
IE浏览器下颜色的表示 张鑫旭-鑫空间-鑫生活

您可以自己点击下面的按钮测试一下:

可见,这种颜色表示的差异性,使得有时候,颜色转换成为的必须。

三、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

补充于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、在算法上可以进一步优化;

欢迎指出这些不足。

(本篇完)

分享到:1

赞助商推荐:

×
×


发表评论(目前17 条评论)

  1. fxss说道:

    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);

  2. 阳光岛主说道:

    很赞的文章,收走了,留个脚印,谢谢。

  3. TPORL说道:

    rgb转hex有点问题
    rbg小于16时,转16进制只有一位数,导致输出有误

    源码:
    if (hex === ‘0’) { hex += hex }

    我的改进:
    hex = hex < 16 ? '0' + hex : hex

  4. Zz说道:

    您的源码里的校验hex颜色的正则是这么写的:var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;

    其中“A-f”这里应该是“A-F”,否则无法匹配大写的F。

  5. codelegant说道:

    RGB转HSL那个函数,h/=6是不应该修改为h*=60?
    H是一个角度值(0-360)

  6. 范生说道:

    这个有个BUG 在CHROME下面 有些颜色转换不了

  7. jsper说道:

    不好意思没事了,由于字符集编码问题,下载后的源码注释包括第一行代码是乱码导致的。现在可以了。感谢博主的倾情付出!

  8. JuN说道:

    谢谢!

  9. RedOrange说道:

    抱歉,昨天发的代码还应该改进一下,保证了一位数前面补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();
    };

  10. RedOrange说道:

    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();
    };

  11. 熊熊说道:

    不错 谢了

  12. thank you!说道:

    谢谢!not bad!