How to get hex color value rather than RGB value?

TLDR

Use this clean one-line function with both rgb and rgba support:

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 updated answer

Much time has passed since I originally answered this question. Then cool ECMAScript 5 and 2015+ features become largely available on browsers, like arrow functions, Array.map, String.padStart and template strings. So now it’s possible to write an one-liner 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)'))

Basically, we use a regular expression to get each digit inside the rgb string, slice(1) to get only the digits (the first result of match is the full string itself), map to iterate through each digit, each iteration converting to Number with parseInt, then back to an hexadecimal String (through a base-16 conversion), adding zero if needed via padStart. Finally, just join each converted/adjusted digit to a unique String starting with '#'.

Of course, we could extend it without much effort as an one-liner 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)'))

And that’s it. But if you want to dive deep in the old school JavaScript world, keep reading.


Original 2010 answer

Here is the cleaner solution I wrote based on @Matt suggestion:

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

Some browsers already returns colors as hexadecimal (as of Internet Explorer 8 and below). If you need to deal with those cases, just append a condition inside the function, like @gfrobenius suggested:

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

If you’re using jQuery and want a more complete approach, you can use CSS Hooks available since jQuery 1.4.3, as I showed when answering this question: Can I force jQuery.css(“backgroundColor”) returns on hexadecimal format?

Leave a Comment