How to Calculate Lighter or Darker Hex Colors in JavaScript

Using colors in HTML, CSS and JavaScript is easy. However, it’s often necessary to programmatically generate colors, i.e. you need a color which is 20% brighter than #123 or 10% darker than #abcdef.

CSS3 provides a great solution: HSL. Rather than using hex or RGB colors, you can set the Hue, Saturation, Luminosity (or Lightness) and, optionally, the opacity, e.g.


color: hsla(50, 80%, 20%, 0.5);
background-color: hsl(120, 100%, 50%);

HSL and HSLA are supported in most browsers except IE8 and below. You can set the third luminosity parameter to change how bright or dark your color should be.

Unfortunately, we don’t always have the luxury of working in HSL. While you may be able to set an individual HSL color, the browser ultimately converts it to RGB. In addition, RGB is generally easier to use and you probably have colors already defined in that format.

There are various algorithms to change color luminosity. Many convert RGB to HSL then back again which is a fairly convoluted calculation for client-side scripting. Therefore, I’ve written a quick and simple cross-browser solution in JavaScript. ColorLuminance accepts two parameters:

  • hex — a hex color value such as “#abc” or “#123456″ (the hash is optional)
  • lum — the luminosity factor, i.e. -0.1 is 10% darker, 0.2 is 20% lighter, etc.

The full code:


function ColorLuminance(hex, lum) {

	// validate hex string
	hex = String(hex).replace(/[^0-9a-f]/gi, '');
	if (hex.length < 6) {
		hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
	}
	lum = lum || 0;

	// convert to decimal and change luminosity
	var rgb = "#", c, i;
	for (i = 0; i < 3; i++) {
		c = parseInt(hex.substr(i*2,2), 16);
		c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
		rgb += ("00"+c).substr(c.length);
	}

	return rgb;
}

In essence, the first three lines clean the string and expand 3-digit hex codes to a full 6-digit representation.

The loop extracts the red, green and blue values in turn, converts them to decimal, applies the luminosity factor, and converts them back to hexadecimal. Examples:


ColorLuminance("#69c", 0);		// returns "#6699cc"
ColorLuminance("6699CC", 0.2);	// "#7ab8f5" - 20% lighter
ColorLuminance("69C", -0.5);	// "#334d66" - 50% darker
ColorLuminance("000", 1);		// "#000000" - true black cannot be made lighter!

Please view the demonstration page; the color gradient is generating using a series of 100 div elements with slightly lighter backgrounds.

I hope you find it useful. I’ll be using the function in another demonstration coming soon on SitePoint…

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Tim

    Nice work, I was looking for something like this a few months ago. Do you by any chance also have functions for calculating contrasting and complimentary colours for a given base colour? This is really useful when trying to come up with a colour scheme based on a company brand colour

  • jjclark

    Black is zero, so the numbers don’t work out when you try to manipulate it. If you add or remove 20% of zero, you still have zero!

  • jjclark

    Intuitively, 20% brighter than pure black makes some sense, because we think of it as full-black rather than zero colour. Ie, we’d think that 20% lighter than black is 80% black OR 20% white. But we can only use mathematics to communicate these rules to the computer, and in mathematical terms 20% of 0 will always be zero.
    Luckily, we can use false-blacks (as very dark grey but not quite pure black), which gives us something to play with.