How to Calculate Lighter or Darker Hex Colors in JavaScript

    Craig Buckler

    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…