如何获取十六进制颜色值而不是RGB值?

208

使用以下jQuery代码可以获取元素背景色的RGB值:

$('#selector').css('backgroundColor');

有没有办法获取十六进制值而非RGB值?


2
在相关主题上,更多(且可以说更好)的将十六进制和RGB颜色之间进行转换的方法在这里:https://dev59.com/7G035IYBdhLWcg3wGMDa。这个轮子已经被重复发明了足够多次来建造一列火车了。我希望其中一个流行的JS库能够提供一个比less更简单的实用函数。 - Michael Scheper
请记住,某些浏览器返回rgba(#,#,#,#)格式,例如rgba(0,0,0,0)表示透明而不是黑色。第四个值是不透明度,1.0表示完全颜色100%,0.5表示50%。 - Twelve24
理想情况下,我们应该能够告诉浏览器使用哪种格式。我有这样的印象,与浏览器相关的人们更倾向于使用RGBA而不是备受喜爱的十六进制代码。 - run_the_race
25个回答

208

简而言之

使用这个干净的一行函数,支持 rgbrgba

const rgba2hex = (rgba) => `#${rgba.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+\.{0,1}\d*))?\)$/).slice(1).map((n, i) => (i === 3 ? Math.round(parseFloat(n) * 255) : parseFloat(n)).toString(16).padStart(2, '0').replace('NaN', '')).join('')}`

2021年更新的答案

自我最初回答此问题以来,已经过去了很长时间。现在,像箭头函数Array.mapString.padStart模板字符串等酷炫的ECMAScript 5和2015+功能已经在浏览器上广泛使用。几年来,可以编写跨浏览器的一行代码rgb2hex

const rgb2hex = (rgb) => `#${rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/).slice(1).map(n => parseInt(n, 10).toString(16).padStart(2, '0')).join('')}`

// Use as you wish...
console.log(rgb2hex('rgb(0,0,0)'))
console.log(rgb2hex('rgb(255, 255, 255)'))
console.log(rgb2hex('rgb(255,0,0)'))
console.log(rgb2hex('rgb(38, 170, 90)'))

它通过使用正则表达式获取rgb字符串中的每个数字,使用slice(1)获取数字(match的第一个结果是完整的字符串本身),使用map迭代每个数字,每次迭代将其转换为parseInt中的Number,然后再转换为十六进制String(通过基数16转换),如果需要则使用padStart添加零。最后,使用join将每个转换/调整后的数字连接成以'#'开头的唯一String
当然,我们可以轻松地将它扩展为一行代码的rgba2hex函数:

const rgba2hex = (rgba) => `#${rgba.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+\.{0,1}\d*))?\)$/).slice(1).map((n, i) => (i === 3 ? Math.round(parseFloat(n) * 255) : parseFloat(n)).toString(16).padStart(2, '0').replace('NaN', '')).join('')}`

// Now it doesn't matter if 'rgb' or 'rgba'...
console.log(rgba2hex('rgb(0,0,0)'))
console.log(rgba2hex('rgb(255, 255, 255)'))
console.log(rgba2hex('rgb(255,0,0)'))
console.log(rgba2hex('rgb(38, 170, 90)'))
console.log(rgba2hex('rgba(255, 0, 0, 0.5)'))
console.log(rgba2hex('rgba(0,255,0,1)'))
console.log(rgba2hex('rgba(127,127,127,0.25)'))

就是这样。但如果你想深入了解老式JavaScript的世界,请继续阅读。


2010年原始答案

这是我根据@Matt建议编写的更清晰的解决方案:

function rgb2hex(rgb) {
    rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
    function hex(x) {
        return ("0" + parseInt(x).toString(16)).slice(-2);
    }
    return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
}

一些浏览器已经以十六进制返回颜色(如Internet Explorer 8及以下版本)。如果您需要处理这些情况,可以在函数内部添加一个条件,像@gfrobenius建议的那样:

function rgb2hex(rgb) {
    if (/^#[0-9A-F]{6}$/i.test(rgb)) return rgb;

    rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
    function hex(x) {
        return ("0" + parseInt(x).toString(16)).slice(-2);
    }
    return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
}

如果您正在使用jQuery并且想要更全面的方法,可以使用自jQuery 1.4.3起提供的CSS Hooks。在回答这个问题时,我展示了如何使用CSS Hooks:CSS HooksCan I force jQuery.css("backgroundColor") returns on hexadecimal format?。请注意,HTML标签将被保留,但无解释。

3
我建议大家查看我的回复(在此处)以查看使用jQuery CSS Hooks改进的版本。请注意,不要更改原意,并使内容易于理解。 - Erick Petrucelli
2
@Ghigo,我认为你误解了:如果你在一个返回十六进制的浏览器中,就不应该使用这个函数。这个函数只是将RGB转换为HEX。当它不在RGB时不要使用它。你需要一个更完整的解决方案(可以检测值是否已经像@Jim-F所做的那样作为RGB),但这并不改变这个解决方案正好提供了OP所请求的内容。你的反对票毫无意义,抱歉。 - Erick Petrucelli
4
抱歉,但我不同意。跨浏览器的功能总是比需要基于浏览器检测执行的功能更好。Op要求将$('#selector').css('backgroundColor')转换为十六进制,而不是将RGB值转换为十六进制。在IE8上,$('#selector').css('backgroundColor')已经是十六进制,因此必须进行处理。就这样,不要对我发脾气 :) - Ghigo
1
这是一个简单的一句话代码,我将其添加到 rgb2hex() 函数中,感谢 @ErickPetru!你们可能不信,我必须要编写兼容 IE7 的代码。使用 .css('backgroundColor') 和本地的 obj.style.backgroundColor,IE7 和 IE8 将返回十六进制值而不是 RGB 值,所以我在提供的答案的 rgb2hex()函数中添加了第一行代码,以便它能够向后兼容 IE7:/* IE7&8 will return hex, so no need to run this function if it is already hex. */ `if (/^#[0-9A-F]{6}$/i.test(rgb)) return rgb.substring(1, 7); //我进行了子字符串操作,因为我不想要前导的 # 符号。希望这有所帮助。 - gfrobenius
1
我认为这是最好的答案,因为它可以直接接受 jQuery CSS 输出并返回十六进制。 - Gaurav
显示剩余4条评论

145
var hexDigits = new Array
        ("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"); 

//Function to convert rgb color to hex format
function rgb2hex(rgb) {
 rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
 return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
}

function hex(x) {
  return isNaN(x) ? "00" : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16];
 }

(来源)


8
+1,你可以使用Number.toString(16)来表示每个十六进制数字(如果小于16则在前面补0)。 - orip
22
如orip所提到的,你可以使用toString(16)。由于其他效率问题而被downvote了。如果你想在每次函数调用时声明hexDigits,请至少在rgb2hex函数体中进行(而不是hex函数体),这样数组就不会在每次调用rgb2hex时重新定义3次。此外,学会使用“var”,这样就不会污染全局范围了。 - Matt
3
这种方法似乎不太容忍不同的空格或大小写。http://jsfiddle.net/Xotic750/pSQ7d/ - Xotic750
1
如果你真的想要严谨一些,你可以使正则表达式更加宽容: rgb.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i) 然而,给定的正则表达式是为了处理使用jQuery时浏览器提供的格式而设计的,这并没有你所说的不同的空格或大小写一致性。你也可以使用相同的正则表达式,在匹配rgb之前删除所有空格并转换为小写。另外,关于你的fiddle示例:'rgb(10, 128,)',我认为这不是一个合理的测试。 - binderbound
1
@SlimFadi,你的正则表达式不起作用是因为你没有转义括号。一旦修复了这个问题,它将匹配无效的值,例如rgb(0, 0, 0, 0)和rgba(0, 0 ,0),但对于此目的来说,这不应该是一个问题。 - xr280xr
显示剩余2条评论

66

大多数浏览器在使用以下代码时似乎返回RGB值:

$('#selector').css('backgroundColor');

目前只有IE浏览器(测试过6个版本)会返回十六进制值。

为了避免在IE浏览器中出现错误消息,您可以将函数包装在if语句中:

function rgb2hex(rgb) {
     if (  rgb.search("rgb") == -1 ) {
          return rgb;
     } else {
          rgb = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))?\)$/);
          function hex(x) {
               return ("0" + parseInt(x).toString(16)).slice(-2);
          }
          return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]); 
     }
}

1
这个比其他大多数更好,因为Jim考虑了rgba,而Safari(至少在Mac OS X上)使用它。感谢Jim! - Pascal Lindelauf
1
很棒的解决方案。请注意,该函数返回小写字母,即#ff5544而不是#FF5544。 - Peter
1
这个正则表达式也将在上述解决方案中支持 alpha 通道。 rgb = rgb.match(/^rgba?((\d+),\s*(\d+),\s*(\d+)(?:,\s*(0.\d+))?)$/); - Henning Winter

24

为了兼容rgba,更新了@ErickPetru的代码:

function rgb2hex(rgb) {
    rgb = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))?\)$/);
    function hex(x) {
        return ("0" + parseInt(x).toString(16)).slice(-2);
    }
    return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
}

我更新了正则表达式以匹配 alpha 值(如果被定义),但不使用它。


仅为完整起见:我正在开发一个可以导出到PowerPoint的东西(别问为什么……),它在十六进制字符串上接受第四个字节作为透明度通道,因此可以像这样使用它:return hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]) /* 如果存在,则添加alpha通道 */ + (rgb[5] !== undefined ? hex(Math.round(rgb[5] * 255)) : '');同时我删除了“#”符号,以使其不依赖于最终使用(例如,可以获取输出并在前面添加“0x”,或者保留没有前缀)。希望它能对某个人有所帮助! - Óscar Gómez Alcañiz

13

这里有一个ES6只需一行代码就能完成而不需要使用jQuery的方法:

var rgb = document.querySelector('#selector').style['background-color'];
return '#' + rgb.substr(4, rgb.indexOf(')') - 4).split(',').map((color) => parseInt(color).toString(16).padStart(2, '0')).join('');

1
谢谢,这帮助我将其整合到一个WordPress页面中,该页面会剥离先前答案中的正则表达式反斜杠。 - Jason
1
这个答案不适用于小数字,例如parseInt('0').toString(16)#=> '0',如果是单个数字,则必须填充字符串parseInt('0').toString(16).padStart(2,'0')=> '00' - SidOfc

7
这是一个也检查透明度的版本,因为我的目标是将其插入到样式属性中,其中十六进制颜色的透明版本实际上是单词“transparent”。
function rgb2hex(rgb) {
     if (  rgb.search("rgb") == -1 ) {
          return rgb;
     }
     else if ( rgb == 'rgba(0, 0, 0, 0)' ) {
         return 'transparent';
     }
     else {
          rgb = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))?\)$/);
          function hex(x) {
               return ("0" + parseInt(x).toString(16)).slice(-2);
          }
          return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]); 
     }
}

7

简短

// c - color str e.g."rgb(12,233,43)", result color hex e.g. "#0ce92b"
let rgb2hex=c=>'#'+c.match(/\d+/g).map(x=>(+x).toString(16).padStart(2,0)).join``

// rgb - color str e.g."rgb(12,233,43)", result color hex e.g. "#0ce92b"
let rgb2hex= c=> '#'+c.match(/\d+/g).map(x=>(+x).toString(16).padStart(2,0)).join``

console.log(rgb2hex("rgb(12,233,43"));


6

返回元素背景颜色的十六进制函数。

function getBgColorHex(elem){
    var color = elem.css('background-color')
    var hex;
    if(color.indexOf('#')>-1){
        //for IE
        hex = color;
    } else {
        var rgb = color.match(/\d+/g);
        hex = '#'+ ('0' + parseInt(rgb[0], 10).toString(16)).slice(-2) + ('0' + parseInt(rgb[1], 10).toString(16)).slice(-2) + ('0' + parseInt(rgb[2], 10).toString(16)).slice(-2);
    }
    return hex;
}

使用示例:

$('#div1').click(function(){
   alert(getBgColorHex($(this));
}

jsfiddle


5

易读且无正则表达式(无正则表达式)

我创建了一个使用易于理解的基本函数且不使用正则表达式的函数。
该函数接受以十六进制、RGB或RGBA CSS格式表示的颜色,并返回十六进制表示。
编辑:修复了解析RGBA()格式的错误...

function getHexColor( color ){
    //if color is already in hex, just return it...
    if( color.indexOf('#') != -1 ) return color;
    
    //leave only "R,G,B" :
    color = color
                .replace("rgba", "") //must go BEFORE rgb replace
                .replace("rgb", "")
                .replace("(", "")
                .replace(")", "");
    color = color.split(","); // get Array["R","G","B"]
    
    // 0) add leading #
    // 1) add leading zero, so we get 0XY or 0X
    // 2) append leading zero with parsed out int value of R/G/B
    //    converted to HEX string representation
    // 3) slice out 2 last chars (get last 2 chars) => 
    //    => we get XY from 0XY and 0X stays the same
    return  "#"
            + ( '0' + parseInt(color[0], 10).toString(16) ).slice(-2)
            + ( '0' + parseInt(color[1], 10).toString(16) ).slice(-2)
            + ( '0' + parseInt(color[2], 10).toString(16) ).slice(-2);
}

2
不适用于rgba(0,0,0,0)。首先,需要更改顺序.replace("rgba", "") .replace("rgb", "") .replace("(", "") .replace(")", "");否则,你会得到a0,0,0,0。并且,它返回#000000,这是黑色,而不是透明的。 - Twelve24
如果rgba中的第四个值为0(零),则该“元素”的css将为:element{ color: #000000, opacity: 0.0;},即透明,或者有条件地将'rgba(0,0,0,0)'返回给调用者。 - Twelve24
@Twelve24 解析已修复 - 在阅读您的评论之前,我实际上已经注意到了,但是非常感谢您:) 至于透明度 - 函数应该返回HEXA颜色或“基本颜色”,所以这是故意的 :) - jave.web

5

相同的答案喜欢@Jim F的答案,但使用ES6语法,因此指令较少:

const rgb2hex = (rgb) => {
  if (rgb.search("rgb") === -1) return rgb;
  rgb = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))?\)$/);
  const hex = (x) => ("0" + parseInt(x).toString(16)).slice(-2);
  return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接