Sam Starling
29 May 2012

Desaturating Colours using Javascript

An interesting question popped up on Stack Overflow this evening, asking about how to desaturate colours using Javascript. My initial thought is that it would be a bit tricky — you’d have to convert the RGB colour to HSV, get rid of the saturation, and convert it back to RGB again.

However, a bit of digging around on Google, and I found a much simpler answer. You could take the three RGB values, average them, and set each of the values to that average. But that’s not particularly accurate.

Why not? Our eyes have differing levels of sensitivity when it comes to red, green and blue. If you calculate a weighted average based on this differing sensitivity, then you get a better greyscale representation of that colour.

Code time. Let’s see what that looks like in Javascript:

function desaturate(r, g, b) {
  var intensity = 0.3 * r + 0.59 * g + 0.11 * b;
  var k = 1;
  r = Math.floor(intensity * k + r * (1 - k));
  g = Math.floor(intensity * k + g * (1 - k));
  b = Math.floor(intensity * k + b * (1 - k));
  return [r, g, b];
}

The co-efficients of red, green and blue on the second line represent the sensitivity of our eyes to those colours. The value of k represents how much the colour should be desaturated, where 1 means fully desaturated.

Further Implementation

There are a few more bits we need to cover so that we can make use of this function easily. Namely, fetching the RGB values for an element, and setting them again.

Getting it is easy, as jQuery returns us a string of the RGB values which we can parse using regular expressions. Setting it is easy too - we just need to turn the array returned by desaturate into a valid CSS string.

Here are the functions that do just that, assuming you’ve got jQuery loaded:

function rgb_to_string(r, g, b) {
  return 'rgb(' + r + ', ' + g + ', ' + b + ')';
}

function desaturate_element(el) {
  var rgb = $(el).css('color').match(/\d+/g);
  $(el).css('color', desaturate(rgb[0], rgb[1], rgb[2]));
}

Then you can just call desaturate_element with the element name. You can see this code in action on JSFiddle, or have a look at the original question on StackOverflow.