From 2c8125f8580f452921b0d69073da251f71ce8461 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Mon, 2 Apr 2018 12:49:25 -0700 Subject: [PATCH 1/5] warning coloring needs two colors, bleh --- src-docs/src/views/guidelines/colors.js | 1 + src/components/button/_button.scss | 2 +- src/components/call_out/_call_out.scss | 2 +- src/components/text/_text_color.scss | 2 +- src/global_styling/variables/_colors.scss | 5 ++++- src/themes/eui/eui_colors_dark.scss | 3 ++- 6 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src-docs/src/views/guidelines/colors.js b/src-docs/src/views/guidelines/colors.js index 639762da493..059050227e2 100644 --- a/src-docs/src/views/guidelines/colors.js +++ b/src-docs/src/views/guidelines/colors.js @@ -34,6 +34,7 @@ const allowedColors = [ 'euiColorPrimary', 'euiColorSecondary', 'euiColorWarning', + 'euiColorWarningDark', 'euiColorDanger', 'euiColorAccent', ]; diff --git a/src/components/button/_button.scss b/src/components/button/_button.scss index fbbafe0c014..daba9666f4b 100644 --- a/src/components/button/_button.scss +++ b/src/components/button/_button.scss @@ -70,7 +70,7 @@ $buttonTypes: ( primary: $euiColorPrimary, secondary: $euiColorSecondary, - warning: $euiColorWarning, + warning: $euiColorWarningDark, danger: $euiColorDanger, ghost: $euiColorGhost, // Ghost is special, and does not care about theming. ); diff --git a/src/components/call_out/_call_out.scss b/src/components/call_out/_call_out.scss index b0ed06447b6..54a8a0b2c75 100644 --- a/src/components/call_out/_call_out.scss +++ b/src/components/call_out/_call_out.scss @@ -11,7 +11,7 @@ $callOutTypes: ( primary: $euiColorPrimary, success: $euiColorSecondary, - warning: adjust-hue($euiColorWarning, 20%), + warning: $euiColorWarning, danger: $euiColorDanger, ); diff --git a/src/components/text/_text_color.scss b/src/components/text/_text_color.scss index 8d9eab0abb6..bd4699f9090 100644 --- a/src/components/text/_text_color.scss +++ b/src/components/text/_text_color.scss @@ -4,7 +4,7 @@ $textColors: ( subdued: $euiColorDarkShade, secondary: $euiColorSecondary, accent: $euiColorAccent, - warning: $euiColorWarning, + warning: $euiColorWarningDark, danger: $euiColorDanger, ghost: $euiColorGhost, ); diff --git a/src/global_styling/variables/_colors.scss b/src/global_styling/variables/_colors.scss index b774ddf31d0..0f453a40a3e 100644 --- a/src/global_styling/variables/_colors.scss +++ b/src/global_styling/variables/_colors.scss @@ -37,7 +37,10 @@ $euiColorGhost: #FFF !default; // Status $euiColorSuccess: $euiColorSecondary !default; $euiColorDanger: #A30000 !default; -$euiColorWarning: #CF3800 !default; +$euiColorWarning: #E5830E !default; +// Yellow doesn't work great for accessibility, so we have a darker orange +// for use when using whites. +$euiColorWarningDark: #CF3800 !default; // Grays $euiColorEmptyShade: #FFF !default; diff --git a/src/themes/eui/eui_colors_dark.scss b/src/themes/eui/eui_colors_dark.scss index 4c578239ad1..7429441adcf 100644 --- a/src/themes/eui/eui_colors_dark.scss +++ b/src/themes/eui/eui_colors_dark.scss @@ -9,7 +9,8 @@ $euiColorDarkestShade: #F5F5F5; $euiColorFullShade: #FFF; $euiColorSlightHue: #494E51; $euiColorPrimary: #4da1c0; -$euiColorWarning: #e45c29; +$euiColorWarning: #c06c4c; +$euiColorWarningDark: #c06c4c; $euiColorDanger: #bf4d4d; $euiTextColor: #DDD; From 1183ee81366579bb2e50ec6a739fa3397c8e3a67 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Tue, 3 Apr 2018 11:44:12 -0700 Subject: [PATCH 2/5] New color functions for accessibility --- src-docs/src/views/guidelines/colors.js | 1 - src/components/button/_button.scss | 15 ++-- src/components/call_out/_call_out.scss | 7 +- src/components/text/_text_color.scss | 6 +- src/global_styling/functions/_colors.scss | 83 +++++++++++++++++++++++ src/global_styling/functions/_index.scss | 2 + src/global_styling/functions/_math.scss | 44 ++++++++++++ src/global_styling/index.scss | 1 + src/global_styling/variables/_colors.scss | 31 --------- src/themes/eui/eui_colors_dark.scss | 1 - 10 files changed, 142 insertions(+), 49 deletions(-) create mode 100644 src/global_styling/functions/_colors.scss create mode 100644 src/global_styling/functions/_index.scss create mode 100644 src/global_styling/functions/_math.scss diff --git a/src-docs/src/views/guidelines/colors.js b/src-docs/src/views/guidelines/colors.js index 059050227e2..639762da493 100644 --- a/src-docs/src/views/guidelines/colors.js +++ b/src-docs/src/views/guidelines/colors.js @@ -34,7 +34,6 @@ const allowedColors = [ 'euiColorPrimary', 'euiColorSecondary', 'euiColorWarning', - 'euiColorWarningDark', 'euiColorDanger', 'euiColorAccent', ]; diff --git a/src/components/button/_button.scss b/src/components/button/_button.scss index daba9666f4b..c6fa2bb4638 100644 --- a/src/components/button/_button.scss +++ b/src/components/button/_button.scss @@ -70,7 +70,7 @@ $buttonTypes: ( primary: $euiColorPrimary, secondary: $euiColorSecondary, - warning: $euiColorWarningDark, + warning: $euiColorWarning, danger: $euiColorDanger, ghost: $euiColorGhost, // Ghost is special, and does not care about theming. ); @@ -78,21 +78,16 @@ $buttonTypes: ( // Create button modifiders based upon the map. @each $name, $color in $buttonTypes { .euiButton--#{$name} { - color: $color; + color: makeHighContrastColor($color, $euiColorEmptyShade); border-color: $color; &.euiButton--fill { background-color: $color; border-color: $color; - $textColor: #FFF; - @if ($name == 'ghost') { - $textColor: #000; - } @else if (lightness($euiTextColor) > 50) { - $textColor: $euiTextColor; - } + $fillTextColor: chooseLightOrDarkText($color, #FFF, #000); - color: $textColor; + color: $fillTextColor; &:enabled { &:hover, &:focus { @@ -102,7 +97,7 @@ $buttonTypes: ( } &:disabled .euiButton__spinner { - border-color: euiLoadingSpinnerBorderColors(transparentize($textColor, .3)); + border-color: euiLoadingSpinnerBorderColors(transparentize($fillTextColor, .3)); } } diff --git a/src/components/call_out/_call_out.scss b/src/components/call_out/_call_out.scss index 54a8a0b2c75..0bb0d2cbf11 100644 --- a/src/components/call_out/_call_out.scss +++ b/src/components/call_out/_call_out.scss @@ -18,10 +18,11 @@ $callOutTypes: ( // Create button modifiders based upon the map. @each $name, $color in $callOutTypes { .euiCallOut--#{$name} { - border-color: $color; - background-color: tintOrShade($color, 90%, 70%); + $backgroundColor: tintOrShade($color, 90%, 70%); + $textColor: makeHighContrastColor($color, $backgroundColor); - $textColor: shadeOrTint($color, 30%, 70%); + border-color: $color; + background-color: $backgroundColor; .euiCallOutHeader__icon { fill: $textColor; diff --git a/src/components/text/_text_color.scss b/src/components/text/_text_color.scss index bd4699f9090..daa7ff62f5a 100644 --- a/src/components/text/_text_color.scss +++ b/src/components/text/_text_color.scss @@ -4,7 +4,7 @@ $textColors: ( subdued: $euiColorDarkShade, secondary: $euiColorSecondary, accent: $euiColorAccent, - warning: $euiColorWarningDark, + warning: $euiColorWarning, danger: $euiColorDanger, ghost: $euiColorGhost, ); @@ -12,11 +12,11 @@ $textColors: ( // Create color modifiers based on the map @each $name, $color in $textColors { .euiTextColor.euiTextColor--#{$name} { - color: $color !important; + color: makeHighContrastColor($color, $euiColorEmptyShade) !important; // We need a blanket approach for coloring. It should overule everything. * { - color: $color !important; + color: makeHighContrastColor($color, $euiColorEmptyShade) !important; } } } diff --git a/src/global_styling/functions/_colors.scss b/src/global_styling/functions/_colors.scss new file mode 100644 index 00000000000..555e6b59dda --- /dev/null +++ b/src/global_styling/functions/_colors.scss @@ -0,0 +1,83 @@ +// Mixes a provided color with white. +@function tint($color, $percent) { + @return mix(#fff, $color, $percent); +} + +// Mixes a provided color with black. +@function shade($color, $percent) { + @return mix(#000, $color, $percent); +} + +// For theming. Checks the text color and tells us whether it's light or dark. +// Based on that we either tint (add white) or shade (add black). +@function tintOrShade($color, $tint, $shade) { + @if (lightness($euiTextColor) > 50) { + @return shade($color, $shade); + } @else { + @return tint($color, $tint); + } +} + +// The reverse of the above +@function shadeOrTint($color, $shade, $tint) { + @if (lightness($euiTextColor) < 50) { + @return shade($color, $shade); + } @else { + @return tint($color, $tint); + } +} + +// Calculates luminance, which is better than brightness for checking colors +// pow, nth functions come from the _math.scss functions +@function 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); +} + +// Calculate contrast +@function checkContrast($background, $foreground) { + $backgroundLum: luminance($background) + .05; + $foregroundLum: luminance($foreground) + .05; + + @return max($backgroundLum, $foregroundLum) / min($backgroundLum, $foregroundLum); +} + +// Compare the contrast against both light and white text, then pick the highest. +@function chooseLightOrDarkText($color, $light, $dark) { + $lightContrast: checkContrast($color, white); + $darkContrast: checkContrast($color, black); + + @if ($lightContrast > $darkContrast) { + @return $light; + } + @else { + @return $dark; + } +} + +// Given a color and a background, make that color AA accessibility by slightly +// adjusting it till it works +@function makeHighContrastColor($forground, $background) { + $contrast: checkContrast($forground, $background); + + $highContrastTextColor: $forground; + + @while ($contrast < 4.5) { + $highContrastTextColor: shadeOrTint($highContrastTextColor, 5%, 5%); + $contrast: checkContrast($highContrastTextColor, $euiColorEmptyShade); + } + + @return $highContrastTextColor; +} diff --git a/src/global_styling/functions/_index.scss b/src/global_styling/functions/_index.scss new file mode 100644 index 00000000000..81fba6b95a2 --- /dev/null +++ b/src/global_styling/functions/_index.scss @@ -0,0 +1,2 @@ +@import 'math'; +@import 'colors'; diff --git a/src/global_styling/functions/_math.scss b/src/global_styling/functions/_math.scss new file mode 100644 index 00000000000..0040dc3fb18 --- /dev/null +++ b/src/global_styling/functions/_math.scss @@ -0,0 +1,44 @@ +// Greatest common devisor +// From: http://rosettacode.org/wiki/Greatest_common_divisor#JavaScript +@function gcd($a, $b) { + @if ($b != 0) { + @return gcd($b, $a % $b); + } @else { + @return abs($a); + } +} + +// Handles decimal exponents by trying to convert them into a fraction and then +// use a nthRoot-algorithm for parts of the calculation +@function pow($base, $exponent, $prec: 12) { + @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; +} + +// From: http://rosettacode.org/wiki/Nth_root#JavaScript +@function nthRoot($num, $n: 2, $prec: 12) { + $x: 1; + + @for $i from 0 through $prec { + $x: 1 / $n * (($n - 1) * $x + ($num / pow($x, $n - 1))); + } + + @return $x; +} diff --git a/src/global_styling/index.scss b/src/global_styling/index.scss index dbaf1a9869d..0e340dbbe98 100644 --- a/src/global_styling/index.scss +++ b/src/global_styling/index.scss @@ -1,4 +1,5 @@ // Core +@import 'functions/index'; @import 'variables/index'; @import 'mixins/index'; @import 'reset/index'; diff --git a/src/global_styling/variables/_colors.scss b/src/global_styling/variables/_colors.scss index 0f453a40a3e..3400db5d572 100644 --- a/src/global_styling/variables/_colors.scss +++ b/src/global_styling/variables/_colors.scss @@ -1,31 +1,3 @@ -// Mixes a provided color with white. -@function tint($color, $percent) { - @return mix(#fff, $color, $percent); -} - -// Mixes a provided color with black. -@function shade($color, $percent) { - @return mix(#000, $color, $percent); -} - -// For theming. Checks the text color and tells us whether it's light or dark. -// Based on that we either tint or shade. -@function tintOrShade($color, $tint, $shade) { - @if (lightness($euiTextColor) > 50) { - @return shade($color, $shade); - } @else { - @return tint($color, $tint); - } -} - -@function shadeOrTint($color, $shade, $tint) { - @if (lightness($euiTextColor) < 50) { - @return shade($color, $shade); - } @else { - @return tint($color, $tint); - } -} - // Core $euiColorPrimary: #0079a5 !default; @@ -38,9 +10,6 @@ $euiColorGhost: #FFF !default; $euiColorSuccess: $euiColorSecondary !default; $euiColorDanger: #A30000 !default; $euiColorWarning: #E5830E !default; -// Yellow doesn't work great for accessibility, so we have a darker orange -// for use when using whites. -$euiColorWarningDark: #CF3800 !default; // Grays $euiColorEmptyShade: #FFF !default; diff --git a/src/themes/eui/eui_colors_dark.scss b/src/themes/eui/eui_colors_dark.scss index 7429441adcf..58302f0b16e 100644 --- a/src/themes/eui/eui_colors_dark.scss +++ b/src/themes/eui/eui_colors_dark.scss @@ -10,7 +10,6 @@ $euiColorFullShade: #FFF; $euiColorSlightHue: #494E51; $euiColorPrimary: #4da1c0; $euiColorWarning: #c06c4c; -$euiColorWarningDark: #c06c4c; $euiColorDanger: #bf4d4d; $euiTextColor: #DDD; From 0e91f7d4f148a89ab2ae72ffac0def8e5d673e3c Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Tue, 3 Apr 2018 12:13:45 -0700 Subject: [PATCH 3/5] rename contrast ratio --- src/global_styling/functions/_colors.scss | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/global_styling/functions/_colors.scss b/src/global_styling/functions/_colors.scss index 555e6b59dda..f7777cb73b9 100644 --- a/src/global_styling/functions/_colors.scss +++ b/src/global_styling/functions/_colors.scss @@ -47,7 +47,7 @@ } // Calculate contrast -@function checkContrast($background, $foreground) { +@function contrastRatio($background, $foreground) { $backgroundLum: luminance($background) + .05; $foregroundLum: luminance($foreground) + .05; @@ -56,8 +56,8 @@ // Compare the contrast against both light and white text, then pick the highest. @function chooseLightOrDarkText($color, $light, $dark) { - $lightContrast: checkContrast($color, white); - $darkContrast: checkContrast($color, black); + $lightContrast: contrastRatio($color, white); + $darkContrast: contrastRatio($color, black); @if ($lightContrast > $darkContrast) { @return $light; @@ -70,13 +70,13 @@ // Given a color and a background, make that color AA accessibility by slightly // adjusting it till it works @function makeHighContrastColor($forground, $background) { - $contrast: checkContrast($forground, $background); + $contrast: contrastRatio($forground, $background); $highContrastTextColor: $forground; @while ($contrast < 4.5) { $highContrastTextColor: shadeOrTint($highContrastTextColor, 5%, 5%); - $contrast: checkContrast($highContrastTextColor, $euiColorEmptyShade); + $contrast: contrastRatio($highContrastTextColor, $euiColorEmptyShade); } @return $highContrastTextColor; From a94f4f112365dd9b4e41bd6d317f726c7d42e1c0 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Tue, 3 Apr 2018 14:10:48 -0700 Subject: [PATCH 4/5] address feedback --- src/components/button/_button.scss | 10 ++++++++- src/global_styling/functions/_colors.scss | 27 ++++++++++++++--------- src/global_styling/functions/_index.scss | 3 +++ src/global_styling/index.scss | 8 +++++++ 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/components/button/_button.scss b/src/components/button/_button.scss index c6fa2bb4638..b3cdb4f7e0e 100644 --- a/src/components/button/_button.scss +++ b/src/components/button/_button.scss @@ -78,7 +78,15 @@ $buttonTypes: ( // Create button modifiders based upon the map. @each $name, $color in $buttonTypes { .euiButton--#{$name} { - color: makeHighContrastColor($color, $euiColorEmptyShade); + + @if ($name == 'ghost') { + // Ghost is unique and ALWAYS sits against a dark background. + color: $color; + } @else { + // Other colors need to check their contrast against the page background color. + color: makeHighContrastColor($color, $euiColorEmptyShade); + } + border-color: $color; &.euiButton--fill { diff --git a/src/global_styling/functions/_colors.scss b/src/global_styling/functions/_colors.scss index f7777cb73b9..a5e43ba1c47 100644 --- a/src/global_styling/functions/_colors.scss +++ b/src/global_styling/functions/_colors.scss @@ -54,25 +54,30 @@ @return max($backgroundLum, $foregroundLum) / min($backgroundLum, $foregroundLum); } -// Compare the contrast against both light and white text, then pick the highest. -@function chooseLightOrDarkText($color, $light, $dark) { - $lightContrast: contrastRatio($color, white); - $darkContrast: contrastRatio($color, black); +// Given $color, decided whether $lightText or $darkText should be used as the text color +// ex: chooseLightOrDarkText(#EEE, #FFF, #000) would return #000 because it has +// a higher contrast than #FFF against a #EEE background. +@function chooseLightOrDarkText($background, $lightText, $darkText) { + $lightContrast: contrastRatio($background, $lightText); + $darkContrast: contrastRatio($background, $darkText); @if ($lightContrast > $darkContrast) { - @return $light; + @return $lightText; } @else { - @return $dark; + @return $darkText; } } -// Given a color and a background, make that color AA accessibility by slightly -// adjusting it till it works -@function makeHighContrastColor($forground, $background) { - $contrast: contrastRatio($forground, $background); +// Given a $foreground and a $background, make the $foreground AA accessibility by slightly +// adjusting it till the contrast is high enough - $highContrastTextColor: $forground; +// ex: makeContrastColor($lightPink, #FFF) would continually shade the pink until +// it had higher than 4.5 contrast on a white background. +@function makeHighContrastColor($foreground, $background) { + $contrast: contrastRatio($foreground, $background); + + $highContrastTextColor: $foreground; @while ($contrast < 4.5) { $highContrastTextColor: shadeOrTint($highContrastTextColor, 5%, 5%); diff --git a/src/global_styling/functions/_index.scss b/src/global_styling/functions/_index.scss index 81fba6b95a2..de8260b2bba 100644 --- a/src/global_styling/functions/_index.scss +++ b/src/global_styling/functions/_index.scss @@ -1,2 +1,5 @@ +// Math needs to be first in the load order @import 'math'; + +// Using math, we have functions to manipulate contrast / luminosity for accessibility @import 'colors'; diff --git a/src/global_styling/index.scss b/src/global_styling/index.scss index 0e340dbbe98..29729d85f7b 100644 --- a/src/global_styling/index.scss +++ b/src/global_styling/index.scss @@ -1,5 +1,13 @@ // Core + +// Functions need to be first, since we use them in our variables and mixin definitions @import 'functions/index'; + +// Variables come next, and are used in some mixins @import 'variables/index'; + +// Mixins provide generic code expansion through helpers @import 'mixins/index'; + +// The reset file makes use of variables and mixins @import 'reset/index'; From c61d43ecc5494651aaa4c119e693048369ddbe2e Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Tue, 3 Apr 2018 14:25:27 -0700 Subject: [PATCH 5/5] more comments, changelog --- CHANGELOG.md | 1 + src/components/text/_text_color.scss | 2 ++ src/global_styling/functions/_colors.scss | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 745ed965593..ffedfb0792a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # [`master`](https://github.com/elastic/eui/tree/master) - Modifying drop shadow intensities and color. ([607](https://github.com/elastic/eui/pull/607)) +- Add Sass color functions. Make `$euiColorWarning` color usage more accessible while still being "yellow". ([628](https://github.com/elastic/eui/pull/628)) **Bug fixes** diff --git a/src/components/text/_text_color.scss b/src/components/text/_text_color.scss index daa7ff62f5a..3bffe2ffff0 100644 --- a/src/components/text/_text_color.scss +++ b/src/components/text/_text_color.scss @@ -12,6 +12,8 @@ $textColors: ( // Create color modifiers based on the map @each $name, $color in $textColors { .euiTextColor.euiTextColor--#{$name} { + + // The below function makes sure the color is accessible on our default background. color: makeHighContrastColor($color, $euiColorEmptyShade) !important; // We need a blanket approach for coloring. It should overule everything. diff --git a/src/global_styling/functions/_colors.scss b/src/global_styling/functions/_colors.scss index a5e43ba1c47..d87a17e5955 100644 --- a/src/global_styling/functions/_colors.scss +++ b/src/global_styling/functions/_colors.scss @@ -54,7 +54,7 @@ @return max($backgroundLum, $foregroundLum) / min($backgroundLum, $foregroundLum); } -// Given $color, decided whether $lightText or $darkText should be used as the text color +// Given $color, decide whether $lightText or $darkText should be used as the text color // ex: chooseLightOrDarkText(#EEE, #FFF, #000) would return #000 because it has // a higher contrast than #FFF against a #EEE background. @function chooseLightOrDarkText($background, $lightText, $darkText) {