Summary

I was contacted by Andrew Waer about a JavaScript class he had written to help determine the colour contrast between two colours, based on the algorithm suggested in the 26th of April 2000 working draft for Accessibility Evaluation and Repair Tools. Andrew has kindly allowed me to publish the details of the class. The class can either be used to create your own colour contrast checker, or to select appropriately contrasting colours on the fly.

Author: Gez Lemon

Contents

The JavaScript Colour Contrast Class

/*
  Color Contrast | Andrew Waer
  Origins: http://juicystudio.com/services/colourcontrast.php

  Usage:
 
  // Contrast test for two colors
  // returns passing score OR false if test fails
  Contrast.test('#ffffff', '#000000');

  // find best match from one or two color sets
  // returns array containing two hex values OR false if no match
  Contrast.match('#ffffff', ['#000000', '#336699']);
  Contrast.match(['#ffffff', '#000000', '#336699']);
  Contrast.match(['#ffffff','#ffffcc'], ['#000000', '#336699']);
*/

var Contrast = function()
{
  // private functions and properties
  var _private =
  {
    min : { 
      'brightness': 125, 
      'difference': 500 
    },
    brightness : function(rgb1, rgb2){
      var b1 = ((rgb1.r * 299) + (rgb1.g * 587) + (rgb1.b * 114)) / 1000;
      var b2 = ((rgb2.r * 299) + (rgb2.g * 587) + (rgb2.b * 114)) / 1000;
      return Math.abs(Math.round(b1-b2));
    },
    difference : function(rgb1, rgb2){
      var diff = (Math.max(rgb1.r, rgb2.r) - Math.min(rgb1.r, rgb2.r)) + 
                 (Math.max(rgb1.g, rgb2.g) - Math.min(rgb1.g, rgb2.g)) + 
                 (Math.max(rgb1.b, rgb2.b) - Math.min(rgb1.b, rgb2.b));
      return Math.abs(Math.round(diff));
    },
    rgb : function(hex){
      hex = hex.replace('#','');
      var rgb = {
        r: parseInt(hex[0] + hex[1], 16),
        g: parseInt(hex[2] + hex[3], 16),
        b: parseInt(hex[4] + hex[5], 16)
      };
      return rgb;
    }
  };
  // public functions and properties
  var _public =
  {
    test : function(hex1, hex2){
      var rgb1 = _private.rgb(hex1);
      var rgb2 = _private.rgb(hex2);
      var brightness = _private.brightness(rgb1, rgb2);
      var difference = _private.difference(rgb1, rgb2);
      return (
        brightness >= _private.min.brightness && difference >= _private.min.difference
          ? ((brightness - _private.min.brightness) + (difference - _private. min.difference))
          : false
      );
    },
    match : function(hex1, hex2){
      var total_score, i, j;

      if (typeof hex1 == 'string') {hex1 = [hex1];}
      if (typeof hex2 == 'string') {hex2 = [hex2];}
      var best_match = { 
        score: 0,
        hex1:  null,
        hex2:  null
      };
      if (hex2 == null){
        for (i=0; i<hex1.length; i++){
          for (j=0; j<hex1.length; j++){
            total_score = _public.test(hex1[i], hex1[j]);
            if (total_score > best_match.score){
              best_match.score = total_score;
              best_match.hex1 = hex1[i];
              best_match.hex2 = hex1[j];
            }
          }
        }
      } 
      else {
        for (i=0; i<hex1.length; i++){
          for (j=0; j<hex2.length; j++){
            total_score = _public.test(hex1[i], hex2[j]);
            if (total_score > best_match.score){
              best_match.score = total_score;
              best_match.hex1 = hex1[i];
              best_match.hex2 = hex2[j];
            }
          }
        }
      }
      return (
        best_match.score > 0
        ? [ best_match.hex1, best_match.hex2 ]
        : false
      );
    }
  };
  return _public;
}();

The test method

The test method returns the total passing score (the amount above the minimum brightness + the amount above minimum difference), or false if the colour combinations fail.

var strResult = Contrast.test('#ffffcc', '#333300');

The match method

The match method accepts two arguments, both of which may be a string or an array, where the second argument is optional. The following are examples of calling the match method with variables and literals. The result of all of these calls is an array if a successful match is found, otherwise false.

Passing 2 String Variables

var arColour = Contrast.match(strColour, strAlternate);

Passing a String and an Array

var arColour = Contrast.match(strColour, arColours);

Passing an Array and a String

var arColour = Contrast.match(arColours, strColour);

Passing 2 Arrays

var arColour = Contrast.match(arColours, arAlternate);

Passing 2 String Literals

var arColour = Contrast.match('#ffffff', '#000000');

Passing a String Literal and an Array Literal

var arColour = Contrast.match('#ffffff', ['#000000', '#336699']);

Passing an Array Literal and a String Literal

var arColour = Contrast.match(['#000000', '#336699'], '#ffffff');

Passing 2 Array Literals

var arColour = Contrast.match(['#000000', '#336699'], ['#ffffff', 'ffffcc']);

Of course, the method can also be called with a mixture of variables and literals. Alternatively, the match method may be passed a single array, and will choose the best match from the colours in the array if a match is found, otherwise it will return false.

Passing a Single Array

var arColour = Contrast.match(arColours);

Passing a Single Array Literal

var arColour = Contrast.match(['#ffffff', '#000033', '#000000']);

Category: Scripting.

Comments

Comments are closed for this entry.