How to get hex color value rather than RGB value?

187,370

Solution 1

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

(Source)

Solution 2

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?

Solution 3

Most browsers seem to return the RGB value when using:

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

Only I.E (only 6 tested so far) returns the Hex value.

To avoid error messages in I.E, you could wrap the function in an if statement:

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

Solution 4

Updated @ErickPetru for rgba compatibility:

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

I updated the regex to match the alpha value if defined, but not use it.

Solution 5

Here's an ES6 one liner that doesn't use 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('');
Share:
187,370

Related videos on Youtube

bfavaretto
Author by

bfavaretto

I know that I know nothing.

Updated on April 06, 2022

Comments

  • bfavaretto
    bfavaretto about 2 years

    Using the following jQuery will get the RGB value of an element's background color:

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

    Is there a way to get the hex value rather than the RGB?

    • Michael Scheper
      Michael Scheper over 9 years
      On a related topic, more (and arguably better) ways to convert between hex and RGB colours are here: stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rg‌​b This wheel has been reinvented enough times to build a road train. I was hoping one of the popular JS libraries, simpler than less, would have a utility function.
    • Twelve24
      Twelve24 almost 9 years
      Remember that some browsers return rgba(#,#,#,#), such as rgba(0,0,0,0) which is transparent, not black. The 4th value is the opacity, with 1.0 being full color 100% and 0.5 being 50%.
  • orip
    orip over 14 years
    +1, You could use Number.toString(16) - at least for each hex digit (or pad with 0 if under 16)
  • Matt
    Matt over 14 years
    -1. As mentioned by orip, you could use toString(16). Downvoted for other inefficiencies. If you're going to declare hexDigits on every function call, at least do it in rgb2hex's function body (not hex's body), so the array is not redefined 3 times per 1 call to rgb2hex. Also learn to use 'var', so you don't pollute the global scope.
  • Pascal Lindelauf
    Pascal Lindelauf almost 13 years
    This one works better than most others, since Jim takes rgba into account, which is what Safari (at least on Mac OS X) uses. Thanks, Jim!
  • Erick Petrucelli
    Erick Petrucelli about 12 years
    I suggest to everyone: take a look at my response here to see a improved version using jQuery CSS Hooks.
  • Paul T
    Paul T over 11 years
    In older versions of IE, fetching a color value of an object using jquery can sometimes return hex instead of rgb, while most modern browsers return RGB. The linked to function handles both use cases
  • Erick Petrucelli
    Erick Petrucelli about 11 years
    @Ghigo, sorry but you are wrong. IE8 already returns colors as hexadecimal when getting the current style, this way: document.getElementById("your_id").currentStyle["backgroundC‌​olor"]. The function rgb2hex() isn't needed. Here's the jQuery plugin using CSS Hooks that I suggested above, which already does all the validations to recover colors in different browsers: stackoverflow.com/questions/6177454/…
  • Ghigo
    Ghigo about 11 years
    I'm not wrong. I don't want to put browser detection here and there to handle different implementations. The solution just below from Jim F handle correctly IE8. Your code do not handle IE8 and its hexadecimal color format, Jim color does. That's all.
  • Erick Petrucelli
    Erick Petrucelli about 11 years
    @Ghigo, I think you misunderstand: you SHOULD NOT use this function if you are in a browser that returns in HEX. This function convert RGB to HEX and just it. Do not use it when it's not in RGB. The fact that you need a more complete solution (which detects if the value is already as RGB, as made by @Jim-F) don't change the fact that this solution offers exactly what was requested by the OP. Your downvote makes no sense, sorry.
  • Ghigo
    Ghigo about 11 years
    I'm sorry but I do not agree. A cross browser function is always better than one that need execution based on browser detection. Op asked to convert $('#selector').css('backgroundColor') to hex, not a rgb value to hex. And on IE8, $('#selector').css('backgroundColor') is already hex so it must be handled. That's it. Don't get mad at me :)
  • Xotic750
    Xotic750 about 11 years
    This method does not seem very tolerant of differing white-space or capitalisation. jsfiddle.net/Xotic750/pSQ7d
  • Peter
    Peter over 10 years
    Great solution. Note that function returns lower case letters i.e. #ff5544 not #FF5544.
  • binderbound
    binderbound about 10 years
    If you realy want to be pedantic, you can make the regex more permissive: rgb.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i‌​) However, the regex given is designed to cope with the format given by a browser when using jQuery, and this doesn't have the different white-space or captilisation consistencies you are talking about. You could also use the same regex and just remove all whitespaces and convert to lowercase before matching on rgb. P.S. Your fiddle example: 'rgb(10, 128,)' I don't think that is reasonable to test on
  • gfrobenius
    gfrobenius almost 10 years
    Do this guys, a simple one liner I added to the rgb2hex() function, thanks @ErickPetru! I have to code back to IE7 believe it or not. With .css('backgroundColor') and native obj.style.backgroundColor IE7 & 8 will return hex, not RGB, so I added this as the first line in the rgb2hex() function in the supplied answer so it works all the way back to 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); //I'm doing a subtring here because I do not want the leading # symbol Hope that helps.
  • Miguel
    Miguel over 9 years
    and for me the return of jquery css background-colors comes in format with rgba , so this does not works.
  • Twelve24
    Twelve24 almost 9 years
    Does not work on rgba(0,0,0,0). First: the order needs to change .replace("rgba", "") .replace("rgb", "") .replace("(", "") .replace(")", ""); Otherwise, you get left with a0,0,0,0. And, it returns #000000, which is Black, instead of transparent.
  • Twelve24
    Twelve24 almost 9 years
    If the 4th value in an rgba is 0 (zero), then for css for that 'element' would be: element{ color: #000000, opacity: 0.0;} which is transparent or just conditionally return the 'rgba(0,0,0,0)' back to the caller.
  • jave.web
    jave.web almost 9 years
    @Twelve24 Parsing fixed - I actually noticed that before reading your comment, but definitely thanks for that :) , As for transparency - function is supposed to return HEXA color, or the "base color" - so that one is on purpose :)
  • Gaurav
    Gaurav almost 9 years
    This is the best answer i think because it accepts the jquery css output directly and returns the hex.
  • Erick Petrucelli
    Erick Petrucelli almost 9 years
    @Gaurav, for jQuery users I strongly suggest the approach with CSS Hooks.
  • Slim Fadi
    Slim Fadi over 8 years
    if you want to support rgba use this expression: rgb = rgb.match(/^rgba?((\d+),\s*(\d+),\s*(\d+)(,\s*\d+)?)‌​$/);
  • Jason
    Jason over 8 years
    Thanks, that helped me incorporate it into a Wordpress page which strips out the regex backslashes in the previous answers.
  • xr280xr
    xr280xr about 8 years
    @SlimFadi your regex doesn't work because you un-escaped the parenthesis. Once that's fixed, it would match invalid values such as rgb(0, 0, 0, 0) and rgba(0, 0 ,0) too, but that shouldn't be a problem for this purpose.
  • Óscar Gómez Alcañiz
    Óscar Gómez Alcañiz over 7 years
    Just for completeness: I am working on a thing that will export to PowerPoint (don't ask...), and it accepts a fourth byte on the hex string for the alpha channel, so one can make use of it like this: return hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]) /* Add the alpha channel if it exists */ + (rgb[5] !== undefined ? hex(Math.round(rgb[5] * 255)) : ''); Also I am removing the # symbol to make it agnostic of the final use (one could get the output and prepend it with 0x for example, or leave it without prefix). Hope it helps someone!
  • Eddie
    Eddie almost 6 years
    It returns everything in the style. :c
  • Henning Winter
    Henning Winter over 4 years
    This regex will support aplha channels as well in the above solution rgb = rgb.match(/^rgba?((\d+),\s*(\d+),\s*(\d+)(?:,\s*(0\.\d+)‌​)?)$/);
  • Fabrice T
    Fabrice T over 3 years
    You can replace if (r.length == 1) ... r = "0" + r; by *.padStart(2, "0")
  • yankee
    yankee about 3 years
    Slightly shorter: rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/).slice(1).map(i => parseInt(i).toString(16).padStart(2, '0')).join('');
  • SidOfc
    SidOfc over 2 years
    This answer does not work for small numbers, e.g. parseInt('0').toString(16) # => '0', the string must be padded if it's a single digit parseInt('0').toString(16).padStart(2, '0') => '00'.