You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I also did some tests and was not sure if the function light-or-dark is intended to be used on its own because the following output does not seem right:
Here is the file I used to test using sass 1.58 with auto-migrated slash division, defined white and black variables and debug statements at the end:
@use "sass:math";
$white: #fff;
$black: #000;
// @function strip-unit($value)
// @param {number with unit} $value
@function strip-unit($value) {
@return math.div($value, $value * 0 + 1);
}
// @function pow($base, $exponents)
// Helper: Raise a number the power of another number
// Adapted from: https://gist.github.com/hail2u/1964056
//
// @param {number} $base — The base number
// @param {number} $exponents — The exponent to which to raise $base
@function pow($base, $exponents) {
$raised: 1;
@for $i from 1 through $exponents {
$raised: $raised * $base;
}
@return $raised;
}
// @function luminance($color)
// Helper: Calculate Luminance of a single color
// Adapted from: https://medium.com/dev-channel/using-sass-to-automatically-pick-text-colors-4ba7645d2796
// White luminance is 1, Black luminance is 0
// To be used in other functions or mixins — creates non-standard CSS output:
// Usage:
// .sample { luminance: luminance(#c00); }
// Output:
// .sample { luminance: 0.1283736922; }
//
@function luminance($color) {
// Thanks voxpelli for a very concise implementation of luminance measure in sass
// Adapted from: https://gist.github.com/voxpelli/6304812
$rgba: red($color), green($color), blue($color);
$rgba2: ();
@for $i from 1 through 3 {
$rgb: nth($rgba, $i);
$rgb: math.div($rgb, 255);
$rgb: if($rgb < .03928, math.div($rgb, 12.92), pow(math.div($rgb + .055, 1.055), 2));
$rgba2: append($rgba2, $rgb);
}
@return (.2126 * nth($rgba2, 1) + .7152 * nth($rgba2, 2) + 0.0722 * nth($rgba2, 3))*100;
}
// @function contrast-ratio($fg, $bg)
// Helper: Calculate "readability" as defined by WCAG 2.1
// Adapted from: https://github.com/LeaVerou/contrast-ratio/blob/gh-pages/color.js
// Formula: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
// To be used in other functions or mixins — creates non-standard CSS output:
// Usage:
// .sample { color-contrast: contrast-ratio(#c00, #fff); }
// Output:
// .sample { color-contrast: 5.89; }
//
@function contrast-ratio($fg, $bg) {
$luminance1: luminance($fg) + 0.05;
$luminance2: luminance($bg) + 0.05;
$ratio: math.div($luminance1, $luminance2);
@if $luminance2 > $luminance1 {
$ratio: math.div(1, $ratio);
}
// Round to a hundreth because 6.96 should not pass a ratio of 7.0
$ratio: round($ratio * 100) * 0.01;
@return $ratio;
}
// @function validate-font-size($size)
// Helper: Depending on the unit recalculate a font size value into pixels if possible
// To be used in other functions or mixins — creates non-standard CSS output:
// Usage:
// .sample { validate-font-size: validate-font-size(1em); }
// Output:
// .sample { validate-font-size: 16; }
//
@function validate-font-size($size) {
@if unit($size) == 'em' or unit($size) == 'rem' or unit($size) == 'px' or unit($size) == '' {
// Check if a flexible unit
@if unit($size) == 'em' or unit($size) == 'rem' {
// Need to convert to a pixel value. Let's not overcomplicate it with possible EM inheritence scale factors
@return strip-unit($size * 16)
}
@if unit($size) == 'px' {
// We expect PX, so strip the value and return it
@return strip-unit($size);
}
@if unit($size) == '' {
@return $size;
}
} @else {
@error 'validate-font-size(): An unexpected font size unit was supplied.';
}
}
// @function get-ratio($level: 'AA', $size: 16, $bold: false)
// Helper: Determine the correct ratio value to use based on font-size and WCAG Level
// To be used in other functions or mixins — creates non-standard CSS output:
// Usage:
// .sample { get-ratio: get-ratio('AAA', 19, true); }
// Output:
// .sample { get-ratio: 4.5; }
//
@function get-ratio($level: 'AA', $size: 16, $bold: false) {
// Default ratio
$ratio: 4.5;
@if $level == 'AAA' {
$ratio: 7;
}
// Make sure the size is valid. If the value is not EM, REM, or PX (preferred), we can't help
$size: validate-font-size($size);
// Check font size
@if $size < 24 {
// Small text, use defaults
// But:
@if $size >= 19 and $bold == true {
// Special case: Small text but also bold
@if $level == 'AAA' {
$ratio: 4.5;
} @else {
$ratio: 3;
}
}
} @else {
// Larger than 24
$ratio: 3;
@if $level == 'AAA' {
$ratio: 4.5;
}
}
@return $ratio;
}
// @function light-or-dark($color)
// Helper: Use contrast against white or black to determine if a color is "light" or "dark"
// Adapted from: https://medium.com/dev-channel/using-sass-to-automatically-pick-text-colors-4ba7645d2796
// To be used in other functions or mixins — creates non-standard CSS output:
// Usage:
// .sample { light-or-dark: light-or-dark(#c00); }
// Output:
// .sample { light-or-dark: "light"; }
//
@function light-or-dark($color) {
$light-contrast: contrast-ratio($color, $white);
$dark-contrast: contrast-ratio($color, $black);
@if $light-contrast > $dark-contrast {
// Contrast against white is higher than against black, so, this is a dark color
@return "dark";
} @else {
@return "light";
}
}
// @function color-contrast($color)
// Helper: Returns black or white compared to a color, whichever produces the highest contrast
// Usage:
// .sample {
// background-color: #c00;
// color: color-contrast(#c00);
// }
// Output:
// .sample {
// background-color: #c00;
// color: #fff;
// }
//
// Named for the forthcoming CSS Module 5 spec function color-contrast();
// See https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-contrast()
//
@function color-contrast($color) {
$color-lod: light-or-dark($color);
@if ($color-lod == "dark") {
@return $white;
} @else {
@return $black;
}
}
// @function a11y-color($fg, $bg, $level: 'AA', $size: 16, $bold: false)
// Goal: Return a color that passes for the chosen WCAG level without changing the Hue of the color
// Usage:
// .sample {
// background-color: #000;
// color: a11y-color(#c0c, #000);
// }
// Output:
// .sample {
// background-color: #000;
// color: #d200d2;
// }
//
@function a11y-color($fg, $bg, $level: 'AA', $size: 16, $bold: false) {
// Helper: make sure the font size value is acceptable
$font-size: validate-font-size($size);
// Helper: With the level, font size, and bold boolean, return the proper target ratio. 3.0, 4.5, or 7.0 expected
$ratio: get-ratio($level, $font-size, $bold);
// Calculate the first contrast ratio of the given pair
$original-contrast: contrast-ratio($fg, $bg);
@if $original-contrast >= $ratio {
// If we pass the ratio already, return the original color
@return $fg;
} @else {
// Doesn't pass. Time to get to work
// Should the color be lightened or darkened?
$fg-lod: light-or-dark($fg);
$bg-lod: light-or-dark($bg);
// Set a "step" value to lighten or darken a color
// Note: Higher percentage steps means faster compile time, but we might overstep the required threshold too far with something higher than 4%
$step: 1%;
// Run through some cases where we want to darken, or use a negative step value
@if $fg-lod == 'light' and $bg-lod == 'light' {
// Both are light colors, darken the fg
$step: - $step;
} @else if $fg-lod == 'dark' and $bg-lod == 'light' {
// bg is light, fg is dark but does not pass, darken more
$step: - $step;
}
// Keeping the rest of the logic here, but our default values do not change, so this logic is not needed
//@else if $fg-lod == 'light' and $bg-lod == 'dark' {
// // bg is dark, fg is light but does not pass, lighten further
// $step: $step;
//} @else if $fg-lod == 'dark' and $bg-lod == 'dark' {
// // Both are dark, so lighten the fg
// $step: $step;
//}
// The magic happens here
// Loop through with a @while statement until the color combination passes our required ratio. Scale the color by our step value until the expression is false
// This might loop 100 times or more depending on the colors
@while contrast-ratio($fg, $bg) < $ratio {
$sat-step: 0%;
@if saturation($fg) > 10 {
$sat-step: $step;
}
$fg: scale-color($fg, $lightness: $step, $saturation:$sat-step);
}
@return $fg;
}
}
@debug (light-or-dark(rgb(30,30,30)));
@debug (light-or-dark(rgb(25, 25, 25)));
@debug (light-or-dark(#1E1E1E));
The text was updated successfully, but these errors were encountered:
Hello, really appreciating the effort and very much looking forward to https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-contrast.
I noticed two things with the functions:
$white
and$black
) https://github.com/jhogue/automated-a11y-sass/blob/master/a11y-color.scss#L144-L145I also did some tests and was not sure if the function
light-or-dark
is intended to be used on its own because the following output does not seem right:rgb(30, 30, 30)
should not be considered light, as writing with black color on this background is almost invisible (https://webaim.org/resources/contrastchecker/?fcolor=000000&bcolor=1E1E1E).Here is the file I used to test using sass 1.58 with auto-migrated slash division, defined white and black variables and debug statements at the end:
The text was updated successfully, but these errors were encountered: