jQuery Color Contrast: a 20-line solution

Contrasting the text with the background color is a extremely simple task. Downloading a full-blown plugin is overkill in most cases. A simple function can take care of it by chosing between black and white color based on the background. Of course it won't detect background image colors, but setting a similar fallback color along with the image should do it.

It all takes less than 20 lines of jQuery. The following contrasting function/plugin adds the light-color class to elements with dark backgrounds, indicating the text should be light, preferably white.

Here's the code:

$.fn.contrastColor = function() {
	return this.each(function() {
		var bg = $(this).css('background-color');
		//use first opaque parent bg if element is transparent
		if(bg == 'transparent' || bg == 'rgba(0, 0, 0, 0)') { 
			$(this).parents().each(function(){
				bg = $(this).css('background-color')
				if(bg != 'transparent' && bg != 'rgba(0, 0, 0, 0)') return false; 
			});
			//exit if all parents are transparent
			if(bg == 'transparent' || bg == 'rgba(0, 0, 0, 0)') return false;
		}
		//get r,g,b and decide
		var rgb = bg.replace(/^(rgb|rgba)\(/,'').replace(/\)$/,'').replace(/\s/g,'').split(',');
		var yiq = ((rgb[0]*299)+(rgb[1]*587)+(rgb[2]*114))/1000;
		if(yiq >= 128) $(this).removeClass('light-color');
		else $(this).addClass('light-color');
	});
};

Remember to add the light-color class. White color is recommended since the YIQ formula was meant to chose between black and white:

.light-color {
	color: white;
}

Finally, call the function on any jQuery object, for example:

$('.container > div').contrastColor();

The color contrast function uses a common formula based on the YIQ color space as explained in Calculating Color Contrast. If the element is transparent, the function checks the background of parent elements (starting with the immediate parent) until it finds one that is not transparent, and takes it as background for the calculation. If all parents are transparent, the function returns without changes. Semi-transparent backgrounds are treated the same as if they were opaque (the alpha values is ignored). The plugin might not work with background colors that are almost fully transparent (eg. rgba(0,0,0,0.1) will be treated as black).

Here are the results of the YIQ contrasting algorithm for several colors:

YIQ color contrast results

Please share any issues/improvements below. I'll be glad to update the post.

One comment

Leave a Reply

Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>