 petermac-
8/22/2013 - 9:03 AM

## Pure SASS script for calculating contrast ratios of colors. MOVED TO: https://github.com/voxpelli/sass-color-helpers

Pure SASS script for calculating contrast ratios of colors. MOVED TO: https://github.com/voxpelli/sass-color-helpers

``````@function gcd(\$a, \$b) {
// From: http://rosettacode.org/wiki/Greatest_common_divisor#JavaScript
@if (\$b != 0) {
@return gcd(\$b, \$a % \$b);
} @else {
@return abs(\$a);
}
}

@function pow(\$base, \$exponent, \$prec: 12) {
// Handles decimal exponents by trying to convert them into a fraction and then use a nthRoot-algorithm for parts of the calculation
@if (floor(\$exponent) != \$exponent) {
\$prec2 : pow(10, \$prec);
\$exponent: round(\$exponent * \$prec2);
\$denominator: gcd(\$exponent, \$prec2);
@return nthRoot(pow(\$base, \$exponent / \$denominator), \$prec2 / \$denominator, \$prec);
}

\$value: \$base;
@if \$exponent > 1 {
@for \$i from 2 through \$exponent {
\$value: \$value * \$base;
}
} @else if \$exponent < 1 {
@for \$i from 0 through -\$exponent {
\$value: \$value / \$base;
}
}

@return \$value;
}

@function nthRoot(\$num, \$n: 2, \$prec: 12) {
// From: http://rosettacode.org/wiki/Nth_root#JavaScript
\$x: 1;

@for \$i from 0 through \$prec {
\$x: 1 / \$n * ((\$n - 1) * \$x + (\$num / pow(\$x, \$n - 1)));
}

@return \$x;
}
``````
``````@function color_luminance(\$color) {
// Formula: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
\$rgba: red(\$color), green(\$color), blue(\$color);
\$rgba2: ();

@for \$i from 1 through 3 {
\$rgb: nth(\$rgba, \$i);
\$rgb: \$rgb / 255;

\$rgb: if(\$rgb < .03928, \$rgb / 12.92, pow((\$rgb + .055) / 1.055, 2.4));

\$rgba2: append(\$rgba2, \$rgb);
}

@return .2126 * nth(\$rgba2, 1) + .7152 * nth(\$rgba2, 2) + 0.0722 * nth(\$rgba2, 3);
}

@function color_contrast(\$color1, \$color2) {
// Formula: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
\$luminance1: color_luminance(\$color1) + .05;
\$luminance2: color_luminance(\$color2) + .05;
\$ratio: \$luminance1 / \$luminance2;

@if \$luminance2 > \$luminance1 {
\$ratio: 1 / \$ratio;
}

\$ratio: round(\$ratio * 10) / 10;

@return \$ratio;
}

@function pick_best_color(\$base, \$colors, \$tolerance: 0) {
\$contrast: color_contrast(\$base, nth(\$colors, 1));
\$best: nth(\$colors, 1);

@for \$i from 2 through length(\$colors) {
\$current_contrast: color_contrast(\$base, nth(\$colors, \$i));
@if (\$current_contrast - \$contrast > \$tolerance) {
\$contrast: color_contrast(\$base, nth(\$colors, \$i));
\$best: nth(\$colors, \$i);
}
}

@if (\$contrast < 3) {
@warn "Contrast ratio of #{\$best} on #{\$base} is pretty bad, just #{\$contrast}";
}

@return \$best;
}
``````

Pure SASS-adaption of Lea Verou's contrast-ratio javascript. Can be useful when eg. generating colored buttons from a single supplied color as you can then check which out of a couple of text colors would give the best contrast.

This script currently lacks the support for alpha-transparency that Lea supports in her script though.

In addition to the color-contrast adaption there's also some math methods that were needed to be able to calculate the exponent of a number and especially so when the exponent is a decimal number. A 2.4 exponent is used to calculate the luminance of a color and calculating such a thing is not something that SASS supports out of the box and not something I found a good pure-SASS script for calculating and I much prefer pure-SASS over ruby extensions. The math methods might perhaps be unecessary though if you're running Compass or similar as they may provide compatible math methods themselves.

Normal usage: `color: pick_best_color(#f00, (#fff, #ccc, #666));`

Bonus feature: Just want to get warned when the contrast becomes unacceptably low? Supply just that one color in the color-pick function: `color: pick_best_color(#f00, #fff);`

Math methods: `pow(10, 3.14)` and `nthRoot(32, 5)`