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…

Craig is a freelance UK web consultant who built his first page for IE2.0 in 1995. Since that time he's been advocating standards, accessibility, and best-practice HTML5 techniques. He's written more than 1,000 articles for SitePoint and you can find him @craigbuckler

Free Guide:

How to Choose the Right Charting Library for Your Application

How do you make sure that the charting library you choose has everything you need? Sign up to receive this detailed guide from FusionCharts, which explores all the factors you need to consider before making the decision.


  • 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

  • http://indapublic.ru/ indapublic

    > true black cannot be made lighter!

    Why?

  • 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!

    • http://indapublic.ru/ indapublic

      Thank you for reply. Sorry for my English, but I try to explain my point view.
      It is correct through mathematics, but not by common sense.
      I want color 20% brighter than #000 – it is normal, isn’t it?

  • 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.

Learn JavaScript for free!
Free course: Introduction to JavaScript

Yours when you take up a free 14-day SitePoint Premium trial.