Skip to content

Instantly share code, notes, and snippets.

@haschek
Last active August 14, 2019 14:20
Show Gist options
  • Save haschek/1059983 to your computer and use it in GitHub Desktop.
Save haschek/1059983 to your computer and use it in GitHub Desktop.
SCSS/SASS Accessibility Color Methods
/*
SCSS Color Methods for Accessibility
================================================================================
Adjust given colors to ensure that those color combination provide sufficient
contrast.
@version 0.1
@link http://eye48.com/go/scsscontrast
@license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License (LGPL)
@author Michael Haschke, http://michael.haschke.biz/
Usage
--------------------------------------------------------------------------------
Import contrast.scss first, then use method ``color_adjust_contrast_AERT``.
```(scss)
@import 'libs/contrast';
.my-element {
background-color: #eee;
color: color_adjust_contrast_AERT(#ccc, #eee); // get grey with good contrast on #eee
}
```
How it works
--------------------------------------------------------------------------------
It tests for sufficent difference on brightness and color of two values. If it
is not enough contrats regarding test formulas of accessible guidelines then one
color is adjusted on lightness and saturation.
Methods using calculations from:
* "Techniques For Accessibility Evaluation And Repair Tools (AERT)" working draft,
@see http://www.w3.org/TR/AERT#color-contrast
* TODO: add methods to test with WCAG2 formulas
*/
// -- AERT ----------------------------------------------------------------
@function color_adjust_contrast_AERT(
$color_adjust,
$color_keep,
$lightness_change_value:1,
$saturation_change_value:1,
$brightness_min: 75,
$difference_min: 500)
{
@if (color_test_contrast_AERT($color_adjust, $color_keep, $brightness_min, $difference_min) == true)
{
@return $color_adjust;
}
$color_save: $color_adjust;
$S: saturation($color_adjust);
$L: lightness($color_adjust);
$foundresult: false;
@while(($foundresult == false) and ($S > 0 or ($L > 0 and $L < 100)))
{
$color_adjust: desaturate($color_adjust, $saturation_change_value);
$S: $S - $saturation_change_value;
@if (lightness($color_keep) > lightness($color_adjust))
{
$color_adjust: darken($color_adjust, $lightness_change_value);
$L: $L - $lightness_change_value;
}
@else
{
$color_adjust: lighten($color_adjust, $lightness_change_value);
$L: $L + $lightness_change_value;
}
$foundresult: color_test_contrast_AERT($color_adjust, $color_keep, $brightness_min, $difference_min);
}
@if ($foundresult == false)
{
@debug $color_save + " was adjusted to " + $color_adjust + " but this is not enough contrast to " + $color_keep + " (AERT).";
}
@return $color_adjust;
}
@function color_test_contrast_AERT($color_1, $color_2, $brightness_min: 75, $difference_min: 500)
{
$difference_brightness: math_absolute(color_brightness_AERT($color_1) - color_brightness_AERT($color_2));
$difference_color: color_difference_AERT($color_1, $color_2);
@if (($difference_brightness < $brightness_min) or ($difference_color < $difference_min))
{
@return false;
}
@else
{
@return true;
}
}
@function color_brightness_AERT($color)
{
$r: red($color);
$g: green($color);
$b: blue($color);
@return (($r * 299) + ($g * 587) + ($b * 114)) / 1000;
}
@function color_difference_AERT($color1, $color2)
{
$r1: red($color1);
$g1: green($color1);
$b1: blue($color1);
$r2: red($color2);
$g2: green($color2);
$b2: blue($color2);
@return (math_max($r1, $r2) - math_min($r1, $r2)) + (math_max($g1, $g2) - math_min($g1, $g2)) + (math_max($b1, $b2) - math_min($b1, $b2));
}
// -- math stuff ----------------------------------------------------------
@function math_max($value1, $value2)
{
@if ($value1 > $value2) { @return $value1; }
@return $value2;
}
@function math_min($value1, $value2)
{
@if ($value1 < $value2) { @return $value1; }
@return $value2;
}
@function math_absolute($value)
{
@if ($value > 0) { @return $value; }
@return $value * -1;
}
@Merovex
Copy link

Merovex commented Apr 25, 2018

I found that I was able to establish a 4.5:1 contrast ratio (WCAG 2.0-AA Normal Text, WCAG 2.0-AAA Large Text) by setting the $difference_min value to 320. I was able to establish almost 7:1 (WCAG 2.0-AAA Normal Text) by setting $difference_min value around 355. The actual value in the second case would hover between 6.7:1 and 7:1 depending on the background color. As you approach 400, the color washes out. Since my site's base-font is in the Large Text range, I settled on a score of 340.

I left the $brightness_min value stock.

To test this, I used WebAIM's color contrast tool. For background colors, I used the Bootstrap 4.1 alert SCSS, using a bootswap gunmetal swatch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment