-
-
Save haschek/1059983 to your computer and use it in GitHub Desktop.
| /* | |
| 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; | |
| } |
I don't advise using this code unless it's licensed MIT/Apache/BSD/ISC/etc. LGPL/GPL isn't clear about how it handles scripting languages and copy-pasting, so there are various hidden traps (albeit likely not intended by the author) that could create a derivative if you use the code.
I guess there is an issue with the function. I have passed both the colors white
$i: color_adjust_contrast_AERT(white,white);
.b{
color:$i;
}
and this returned the white color?
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.
Hi @haschek thanks for clarifying. I commented a bit hastily before appreciating the true nature of your mixin :)