]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Use WCAG contrast algo (#30168)
authorGaël Poupard <ffoodd@users.noreply.github.com>
Mon, 23 Mar 2020 17:03:56 +0000 (18:03 +0100)
committerGitHub <noreply@github.com>
Mon, 23 Mar 2020 17:03:56 +0000 (18:03 +0100)
scss/_functions.scss
scss/_variables.scss
scss/mixins/_buttons.scss
scss/mixins/_forms.scss
site/assets/scss/_colors.scss
site/content/docs/4.3/getting-started/theming.md
site/content/docs/4.3/migration.md

index ad0e7a6679edc44e8caf14c79676327dc158d1cd..00179049c1a61260f4ce139108167bc37f1224b3 100644 (file)
 }
 
 // Color contrast
-@function color-yiq($color, $dark: $yiq-text-dark, $light: $yiq-text-light) {
-  $r: red($color);
-  $g: green($color);
-  $b: blue($color);
+// See https://github.com/twbs/bootstrap/pull/30168
 
-  $yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000;
+// A list of pre-calculated numbers of pow(($value / 255 + .055) / 1.055, 2.4). (from 0 to 255)
+// stylelint-disable-next-line scss/dollar-variable-default, scss/dollar-variable-pattern
+$_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 .0033 .0037 .004 .0044 .0048 .0052 .0056 .006 .0065 .007 .0075 .008 .0086 .0091 .0097 .0103 .011 .0116 .0123 .013 .0137 .0144 .0152 .016 .0168 .0176 .0185 .0194 .0203 .0212 .0222 .0232 .0242 .0252 .0262 .0273 .0284 .0296 .0307 .0319 .0331 .0343 .0356 .0369 .0382 .0395 .0409 .0423 .0437 .0452 .0467 .0482 .0497 .0513 .0529 .0545 .0561 .0578 .0595 .0612 .063 .0648 .0666 .0685 .0704 .0723 .0742 .0762 .0782 .0802 .0823 .0844 .0865 .0887 .0908 .0931 .0953 .0976 .0999 .1022 .1046 .107 .1095 .1119 .1144 .117 .1195 .1221 .1248 .1274 .1301 .1329 .1356 .1384 .1413 .1441 .147 .15 .1529 .1559 .159 .162 .1651 .1683 .1714 .1746 .1779 .1812 .1845 .1878 .1912 .1946 .1981 .2016 .2051 .2086 .2122 .2159 .2195 .2232 .227 .2307 .2346 .2384 .2423 .2462 .2502 .2542 .2582 .2623 .2664 .2705 .2747 .2789 .2831 .2874 .2918 .2961 .3005 .305 .3095 .314 .3185 .3231 .3278 .3325 .3372 .3419 .3467 .3515 .3564 .3613 .3663 .3712 .3763 .3813 .3864 .3916 .3968 .402 .4072 .4125 .4179 .4233 .4287 .4342 .4397 .4452 .4508 .4564 .4621 .4678 .4735 .4793 .4851 .491 .4969 .5029 .5089 .5149 .521 .5271 .5333 .5395 .5457 .552 .5583 .5647 .5711 .5776 .5841 .5906 .5972 .6038 .6105 .6172 .624 .6308 .6376 .6445 .6514 .6584 .6654 .6724 .6795 .6867 .6939 .7011 .7084 .7157 .7231 .7305 .7379 .7454 .7529 .7605 .7682 .7758 .7835 .7913 .7991 .807 .8148 .8228 .8308 .8388 .8469 .855 .8632 .8714 .8796 .8879 .8963 .9047 .9131 .9216 .9301 .9387 .9473 .956 .9647 .9734 .9823 .9911 1;
 
-  @return if($yiq >= $yiq-contrasted-threshold, $dark, $light);
+@function color-contrast($background, $color-contrast-dark: $color-contrast-dark, $color-contrast-light: $color-contrast-light) {
+  $l1: luminance($background);
+  $l2: luminance(opaque($background, $color-contrast-light));
+
+  $contrast: if($l1 > $l2, ($l1 + .05) / ($l2 + .05), ($l2 + .05) / ($l1 + .05));
+
+  @return if($contrast < $min-contrast-ratio, $color-contrast-dark, $color-contrast-light);
+}
+
+// Return WCAG2.0 relative luminance
+// See https://www.w3.org/WAI/GL/wiki/Relative_luminance
+// See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
+@function luminance($color) {
+  $rgb: (
+    "r": red($color),
+    "g": green($color),
+    "b": blue($color)
+  );
+
+  @each $name, $value in $rgb {
+    $value: if($value / 255 < .03928, $value / 255 / 12.92, nth($_luminance-list, $value + 1));
+    $rgb: map-merge($rgb, ($name: $value));
+  }
+
+  @return (map-get($rgb, "r") * .2126) + (map-get($rgb, "g") * .7152) + (map-get($rgb, "b") * .0722);
+}
+
+// Return opaque color
+// opaque(#fff, rgba(0, 0, 0, .5)) => #808080
+@function opaque($background, $foreground) {
+  @return mix(rgba($foreground, 1), $background, opacity($foreground) * 100);
 }
 
 // Request a color level
index 7818a09d8acbee53b872ecad69bfa2772587624d..5060a206614448480fd6878334afd77b80807b4e 100644 (file)
@@ -79,14 +79,15 @@ $theme-colors: (
 ) !default;
 
 // Set a specific jump point for requesting color jumps
-$theme-color-interval:      8% !default;
+$theme-color-interval: 8% !default;
 
-// The yiq lightness value that determines when the lightness of color changes from "dark" to "light". Acceptable values are between 0 and 255.
-$yiq-contrasted-threshold:  150 !default;
+// The contrast ratio to reach against white, to determine if color changes from "light" to "dark". Acceptable values for WCAG 2.0 are 3, 4.5 and 7.
+// See https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast
+$min-contrast-ratio:   3 !default;
 
-// Customize the light and dark text colors for use in our YIQ color contrast function.
-$yiq-text-dark:             $gray-900 !default;
-$yiq-text-light:            $white !default;
+// Customize the light and dark text colors for use in our color contrast function.
+$color-contrast-dark:      $gray-900 !default;
+$color-contrast-light:     $white !default;
 
 // fusv-disable
 $blue-100: tint-color($blue, 8) !default;
index acf6b450c5000e80ae84697c33e3c072b0ed6af2..53a337ba03275e714c653942b89a5f952e6cf074 100644 (file)
@@ -6,13 +6,13 @@
 @mixin button-variant(
   $background,
   $border,
-  $color: color-yiq($background),
+  $color: color-contrast($background),
   $hover-background: darken($background, 7.5%),
   $hover-border: darken($border, 10%),
-  $hover-color: color-yiq($hover-background),
+  $hover-color: color-contrast($hover-background),
   $active-background: darken($background, 10%),
   $active-border: darken($border, 12.5%),
-  $active-color: color-yiq($active-background)
+  $active-color: color-contrast($active-background)
 ) {
   color: $color;
   @include gradient-bg($background);
 
 @mixin button-outline-variant(
   $color,
-  $color-hover: color-yiq($color),
+  $color-hover: color-contrast($color),
   $active-background: $color,
   $active-border: $color,
-  $active-color: color-yiq($active-background)
+  $active-color: color-contrast($active-background)
 ) {
   color: $color;
   border-color: $color;
index 18735599421e95d18a95c430d0646edfa8ed94c5..7abfd23bfb25ac81d6c4b6d4af951c2b1bee7008 100644 (file)
@@ -32,7 +32,7 @@
     margin-top: .1rem;
     @include font-size($form-feedback-tooltip-font-size);
     line-height: $form-feedback-tooltip-line-height;
-    color: color-yiq($color);
+    color: color-contrast($color);
     background-color: rgba($color, $form-feedback-tooltip-opacity);
     @include border-radius($form-feedback-tooltip-border-radius);
   }
index b698b807b5723d8ce2003db01d4e8a97e51c70bf..fe0bf6c5b63c9c103377f9bb30b20af5f4a382f3 100644 (file)
 
 @each $color, $value in $colors {
   .swatch-#{$color} {
-    color: color-yiq($value);
+    color: color-contrast($value);
     background-color: #{$value};
   }
 }
 
 @each $color, $value in $grays {
   .swatch-#{$color} {
-    color: color-yiq($value);
+    color: color-contrast($value);
     background-color: #{$value};
   }
 }
 
 // stylelint-disable declaration-block-single-line-max-declarations
 
-.bd-blue-100 { color: color-yiq($blue-100); background-color: $blue-100; }
-.bd-blue-200 { color: color-yiq($blue-200); background-color: $blue-200; }
-.bd-blue-300 { color: color-yiq($blue-300); background-color: $blue-300; }
-.bd-blue-400 { color: color-yiq($blue-400); background-color: $blue-400; }
-.bd-blue-500 { color: color-yiq($blue-500); background-color: $blue-500; }
-.bd-blue-600 { color: color-yiq($blue-600); background-color: $blue-600; }
-.bd-blue-700 { color: color-yiq($blue-700); background-color: $blue-700; }
-.bd-blue-800 { color: color-yiq($blue-800); background-color: $blue-800; }
-.bd-blue-900 { color: color-yiq($blue-900); background-color: $blue-900; }
+.bd-blue-100 { color: color-contrast($blue-100); background-color: $blue-100; }
+.bd-blue-200 { color: color-contrast($blue-200); background-color: $blue-200; }
+.bd-blue-300 { color: color-contrast($blue-300); background-color: $blue-300; }
+.bd-blue-400 { color: color-contrast($blue-400); background-color: $blue-400; }
+.bd-blue-500 { color: color-contrast($blue-500); background-color: $blue-500; }
+.bd-blue-600 { color: color-contrast($blue-600); background-color: $blue-600; }
+.bd-blue-700 { color: color-contrast($blue-700); background-color: $blue-700; }
+.bd-blue-800 { color: color-contrast($blue-800); background-color: $blue-800; }
+.bd-blue-900 { color: color-contrast($blue-900); background-color: $blue-900; }
 
-.bd-indigo-100 { color: color-yiq($indigo-100); background-color: $indigo-100; }
-.bd-indigo-200 { color: color-yiq($indigo-200); background-color: $indigo-200; }
-.bd-indigo-300 { color: color-yiq($indigo-300); background-color: $indigo-300; }
-.bd-indigo-400 { color: color-yiq($indigo-400); background-color: $indigo-400; }
-.bd-indigo-500 { color: color-yiq($indigo-500); background-color: $indigo-500; }
-.bd-indigo-600 { color: color-yiq($indigo-600); background-color: $indigo-600; }
-.bd-indigo-700 { color: color-yiq($indigo-700); background-color: $indigo-700; }
-.bd-indigo-800 { color: color-yiq($indigo-800); background-color: $indigo-800; }
-.bd-indigo-900 { color: color-yiq($indigo-900); background-color: $indigo-900; }
+.bd-indigo-100 { color: color-contrast($indigo-100); background-color: $indigo-100; }
+.bd-indigo-200 { color: color-contrast($indigo-200); background-color: $indigo-200; }
+.bd-indigo-300 { color: color-contrast($indigo-300); background-color: $indigo-300; }
+.bd-indigo-400 { color: color-contrast($indigo-400); background-color: $indigo-400; }
+.bd-indigo-500 { color: color-contrast($indigo-500); background-color: $indigo-500; }
+.bd-indigo-600 { color: color-contrast($indigo-600); background-color: $indigo-600; }
+.bd-indigo-700 { color: color-contrast($indigo-700); background-color: $indigo-700; }
+.bd-indigo-800 { color: color-contrast($indigo-800); background-color: $indigo-800; }
+.bd-indigo-900 { color: color-contrast($indigo-900); background-color: $indigo-900; }
 
-.bd-purple-100 { color: color-yiq($purple-100); background-color: $purple-100; }
-.bd-purple-200 { color: color-yiq($purple-200); background-color: $purple-200; }
-.bd-purple-300 { color: color-yiq($purple-300); background-color: $purple-300; }
-.bd-purple-400 { color: color-yiq($purple-400); background-color: $purple-400; }
-.bd-purple-500 { color: color-yiq($purple-500); background-color: $purple-500; }
-.bd-purple-600 { color: color-yiq($purple-600); background-color: $purple-600; }
-.bd-purple-700 { color: color-yiq($purple-700); background-color: $purple-700; }
-.bd-purple-800 { color: color-yiq($purple-800); background-color: $purple-800; }
-.bd-purple-900 { color: color-yiq($purple-900); background-color: $purple-900; }
+.bd-purple-100 { color: color-contrast($purple-100); background-color: $purple-100; }
+.bd-purple-200 { color: color-contrast($purple-200); background-color: $purple-200; }
+.bd-purple-300 { color: color-contrast($purple-300); background-color: $purple-300; }
+.bd-purple-400 { color: color-contrast($purple-400); background-color: $purple-400; }
+.bd-purple-500 { color: color-contrast($purple-500); background-color: $purple-500; }
+.bd-purple-600 { color: color-contrast($purple-600); background-color: $purple-600; }
+.bd-purple-700 { color: color-contrast($purple-700); background-color: $purple-700; }
+.bd-purple-800 { color: color-contrast($purple-800); background-color: $purple-800; }
+.bd-purple-900 { color: color-contrast($purple-900); background-color: $purple-900; }
 
-.bd-pink-100 { color: color-yiq($pink-100); background-color: $pink-100; }
-.bd-pink-200 { color: color-yiq($pink-200); background-color: $pink-200; }
-.bd-pink-300 { color: color-yiq($pink-300); background-color: $pink-300; }
-.bd-pink-400 { color: color-yiq($pink-400); background-color: $pink-400; }
-.bd-pink-500 { color: color-yiq($pink-500); background-color: $pink-500; }
-.bd-pink-600 { color: color-yiq($pink-600); background-color: $pink-600; }
-.bd-pink-700 { color: color-yiq($pink-700); background-color: $pink-700; }
-.bd-pink-800 { color: color-yiq($pink-800); background-color: $pink-800; }
-.bd-pink-900 { color: color-yiq($pink-900); background-color: $pink-900; }
+.bd-pink-100 { color: color-contrast($pink-100); background-color: $pink-100; }
+.bd-pink-200 { color: color-contrast($pink-200); background-color: $pink-200; }
+.bd-pink-300 { color: color-contrast($pink-300); background-color: $pink-300; }
+.bd-pink-400 { color: color-contrast($pink-400); background-color: $pink-400; }
+.bd-pink-500 { color: color-contrast($pink-500); background-color: $pink-500; }
+.bd-pink-600 { color: color-contrast($pink-600); background-color: $pink-600; }
+.bd-pink-700 { color: color-contrast($pink-700); background-color: $pink-700; }
+.bd-pink-800 { color: color-contrast($pink-800); background-color: $pink-800; }
+.bd-pink-900 { color: color-contrast($pink-900); background-color: $pink-900; }
 
-.bd-red-100 { color: color-yiq($red-100); background-color: $red-100; }
-.bd-red-200 { color: color-yiq($red-200); background-color: $red-200; }
-.bd-red-300 { color: color-yiq($red-300); background-color: $red-300; }
-.bd-red-400 { color: color-yiq($red-400); background-color: $red-400; }
-.bd-red-500 { color: color-yiq($red-500); background-color: $red-500; }
-.bd-red-600 { color: color-yiq($red-600); background-color: $red-600; }
-.bd-red-700 { color: color-yiq($red-700); background-color: $red-700; }
-.bd-red-800 { color: color-yiq($red-800); background-color: $red-800; }
-.bd-red-900 { color: color-yiq($red-900); background-color: $red-900; }
+.bd-red-100 { color: color-contrast($red-100); background-color: $red-100; }
+.bd-red-200 { color: color-contrast($red-200); background-color: $red-200; }
+.bd-red-300 { color: color-contrast($red-300); background-color: $red-300; }
+.bd-red-400 { color: color-contrast($red-400); background-color: $red-400; }
+.bd-red-500 { color: color-contrast($red-500); background-color: $red-500; }
+.bd-red-600 { color: color-contrast($red-600); background-color: $red-600; }
+.bd-red-700 { color: color-contrast($red-700); background-color: $red-700; }
+.bd-red-800 { color: color-contrast($red-800); background-color: $red-800; }
+.bd-red-900 { color: color-contrast($red-900); background-color: $red-900; }
 
-.bd-orange-100 { color: color-yiq($orange-100); background-color: $orange-100; }
-.bd-orange-200 { color: color-yiq($orange-200); background-color: $orange-200; }
-.bd-orange-300 { color: color-yiq($orange-300); background-color: $orange-300; }
-.bd-orange-400 { color: color-yiq($orange-400); background-color: $orange-400; }
-.bd-orange-500 { color: color-yiq($orange-500); background-color: $orange-500; }
-.bd-orange-600 { color: color-yiq($orange-600); background-color: $orange-600; }
-.bd-orange-700 { color: color-yiq($orange-700); background-color: $orange-700; }
-.bd-orange-800 { color: color-yiq($orange-800); background-color: $orange-800; }
-.bd-orange-900 { color: color-yiq($orange-900); background-color: $orange-900; }
+.bd-orange-100 { color: color-contrast($orange-100); background-color: $orange-100; }
+.bd-orange-200 { color: color-contrast($orange-200); background-color: $orange-200; }
+.bd-orange-300 { color: color-contrast($orange-300); background-color: $orange-300; }
+.bd-orange-400 { color: color-contrast($orange-400); background-color: $orange-400; }
+.bd-orange-500 { color: color-contrast($orange-500); background-color: $orange-500; }
+.bd-orange-600 { color: color-contrast($orange-600); background-color: $orange-600; }
+.bd-orange-700 { color: color-contrast($orange-700); background-color: $orange-700; }
+.bd-orange-800 { color: color-contrast($orange-800); background-color: $orange-800; }
+.bd-orange-900 { color: color-contrast($orange-900); background-color: $orange-900; }
 
-.bd-yellow-100 { color: color-yiq($yellow-100); background-color: $yellow-100; }
-.bd-yellow-200 { color: color-yiq($yellow-200); background-color: $yellow-200; }
-.bd-yellow-300 { color: color-yiq($yellow-300); background-color: $yellow-300; }
-.bd-yellow-400 { color: color-yiq($yellow-400); background-color: $yellow-400; }
-.bd-yellow-500 { color: color-yiq($yellow-500); background-color: $yellow-500; }
-.bd-yellow-600 { color: color-yiq($yellow-600); background-color: $yellow-600; }
-.bd-yellow-700 { color: color-yiq($yellow-700); background-color: $yellow-700; }
-.bd-yellow-800 { color: color-yiq($yellow-800); background-color: $yellow-800; }
-.bd-yellow-900 { color: color-yiq($yellow-900); background-color: $yellow-900; }
+.bd-yellow-100 { color: color-contrast($yellow-100); background-color: $yellow-100; }
+.bd-yellow-200 { color: color-contrast($yellow-200); background-color: $yellow-200; }
+.bd-yellow-300 { color: color-contrast($yellow-300); background-color: $yellow-300; }
+.bd-yellow-400 { color: color-contrast($yellow-400); background-color: $yellow-400; }
+.bd-yellow-500 { color: color-contrast($yellow-500); background-color: $yellow-500; }
+.bd-yellow-600 { color: color-contrast($yellow-600); background-color: $yellow-600; }
+.bd-yellow-700 { color: color-contrast($yellow-700); background-color: $yellow-700; }
+.bd-yellow-800 { color: color-contrast($yellow-800); background-color: $yellow-800; }
+.bd-yellow-900 { color: color-contrast($yellow-900); background-color: $yellow-900; }
 
-.bd-green-100 { color: color-yiq($green-100); background-color: $green-100; }
-.bd-green-200 { color: color-yiq($green-200); background-color: $green-200; }
-.bd-green-300 { color: color-yiq($green-300); background-color: $green-300; }
-.bd-green-400 { color: color-yiq($green-400); background-color: $green-400; }
-.bd-green-500 { color: color-yiq($green-500); background-color: $green-500; }
-.bd-green-600 { color: color-yiq($green-600); background-color: $green-600; }
-.bd-green-700 { color: color-yiq($green-700); background-color: $green-700; }
-.bd-green-800 { color: color-yiq($green-800); background-color: $green-800; }
-.bd-green-900 { color: color-yiq($green-900); background-color: $green-900; }
+.bd-green-100 { color: color-contrast($green-100); background-color: $green-100; }
+.bd-green-200 { color: color-contrast($green-200); background-color: $green-200; }
+.bd-green-300 { color: color-contrast($green-300); background-color: $green-300; }
+.bd-green-400 { color: color-contrast($green-400); background-color: $green-400; }
+.bd-green-500 { color: color-contrast($green-500); background-color: $green-500; }
+.bd-green-600 { color: color-contrast($green-600); background-color: $green-600; }
+.bd-green-700 { color: color-contrast($green-700); background-color: $green-700; }
+.bd-green-800 { color: color-contrast($green-800); background-color: $green-800; }
+.bd-green-900 { color: color-contrast($green-900); background-color: $green-900; }
 
-.bd-teal-100 { color: color-yiq($teal-100); background-color: $teal-100; }
-.bd-teal-200 { color: color-yiq($teal-200); background-color: $teal-200; }
-.bd-teal-300 { color: color-yiq($teal-300); background-color: $teal-300; }
-.bd-teal-400 { color: color-yiq($teal-400); background-color: $teal-400; }
-.bd-teal-500 { color: color-yiq($teal-500); background-color: $teal-500; }
-.bd-teal-600 { color: color-yiq($teal-600); background-color: $teal-600; }
-.bd-teal-700 { color: color-yiq($teal-700); background-color: $teal-700; }
-.bd-teal-800 { color: color-yiq($teal-800); background-color: $teal-800; }
-.bd-teal-900 { color: color-yiq($teal-900); background-color: $teal-900; }
+.bd-teal-100 { color: color-contrast($teal-100); background-color: $teal-100; }
+.bd-teal-200 { color: color-contrast($teal-200); background-color: $teal-200; }
+.bd-teal-300 { color: color-contrast($teal-300); background-color: $teal-300; }
+.bd-teal-400 { color: color-contrast($teal-400); background-color: $teal-400; }
+.bd-teal-500 { color: color-contrast($teal-500); background-color: $teal-500; }
+.bd-teal-600 { color: color-contrast($teal-600); background-color: $teal-600; }
+.bd-teal-700 { color: color-contrast($teal-700); background-color: $teal-700; }
+.bd-teal-800 { color: color-contrast($teal-800); background-color: $teal-800; }
+.bd-teal-900 { color: color-contrast($teal-900); background-color: $teal-900; }
 
-.bd-cyan-100 { color: color-yiq($cyan-100); background-color: $cyan-100; }
-.bd-cyan-200 { color: color-yiq($cyan-200); background-color: $cyan-200; }
-.bd-cyan-300 { color: color-yiq($cyan-300); background-color: $cyan-300; }
-.bd-cyan-400 { color: color-yiq($cyan-400); background-color: $cyan-400; }
-.bd-cyan-500 { color: color-yiq($cyan-500); background-color: $cyan-500; }
-.bd-cyan-600 { color: color-yiq($cyan-600); background-color: $cyan-600; }
-.bd-cyan-700 { color: color-yiq($cyan-700); background-color: $cyan-700; }
-.bd-cyan-800 { color: color-yiq($cyan-800); background-color: $cyan-800; }
-.bd-cyan-900 { color: color-yiq($cyan-900); background-color: $cyan-900; }
+.bd-cyan-100 { color: color-contrast($cyan-100); background-color: $cyan-100; }
+.bd-cyan-200 { color: color-contrast($cyan-200); background-color: $cyan-200; }
+.bd-cyan-300 { color: color-contrast($cyan-300); background-color: $cyan-300; }
+.bd-cyan-400 { color: color-contrast($cyan-400); background-color: $cyan-400; }
+.bd-cyan-500 { color: color-contrast($cyan-500); background-color: $cyan-500; }
+.bd-cyan-600 { color: color-contrast($cyan-600); background-color: $cyan-600; }
+.bd-cyan-700 { color: color-contrast($cyan-700); background-color: $cyan-700; }
+.bd-cyan-800 { color: color-contrast($cyan-800); background-color: $cyan-800; }
+.bd-cyan-900 { color: color-contrast($cyan-900); background-color: $cyan-900; }
index dcaa593f104cb9fbaffacfc6ea87584d511b92c9..e6ed6c1982f85fd611215cbe3d6a93c27829dc39 100644 (file)
@@ -191,14 +191,14 @@ In practice, you'd call the function and pass in two parameters: the name of the
 
 #### Color contrast
 
-An additional function we include in Bootstrap is the color contrast function, `color-yiq`. It utilizes the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) to automatically return a light (`#fff`) or dark (`#111`) contrast color based on the specified base color. This function is especially useful for mixins or loops where you're generating multiple classes.
+An additional function we include in Bootstrap is the color contrast function, `color-contrast`. It utilizes the [WCAG 2.0 algorithm](https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests) for calculating contrast thresholds based on [relative luminance](https://www.w3.org/WAI/GL/wiki/Relative_luminance) in a `sRGB` colorspace to automatically return a light (`#fff`) or dark (`#111`) contrast color based on the specified base color. This function is especially useful for mixins or loops where you're generating multiple classes.
 
 For example, to generate color swatches from our `$theme-colors` map:
 
 {{< highlight scss >}}
 @each $color, $value in $theme-colors {
   .swatch-#{$color} {
-    color: color-yiq($value);
+    color: color-contrast($value);
   }
 }
 {{< /highlight >}}
@@ -207,7 +207,7 @@ It can also be used for one-off contrast needs:
 
 {{< highlight scss >}}
 .custom-element {
-  color: color-yiq(#000); // returns `color: #fff`
+  color: color-contrast(#000); // returns `color: #fff`
 }
 {{< /highlight >}}
 
@@ -215,10 +215,16 @@ You can also specify a base color with our color map functions:
 
 {{< highlight scss >}}
 .custom-element {
-  color: color-yiq($dark); // returns `color: #fff`
+  color: color-contrast($dark); // returns `color: #fff`
 }
 {{< /highlight >}}
 
+{{< callout info >}}
+##### Accessibility
+
+In order to meet [WCAG 2.0 accessibility standards for color contrast](https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html), authors **must** provide [a contrast ratio of at least 4.5:1](https://www.w3.org/WAI/WCAG20/quickref/20160105/Overview.php#visual-audio-contrast-contrast), with very few exceptions.
+{{< /callout >}}
+
 #### Escape SVG
 
 We use the `escape-svg` function to escape the `<`, `>` and `#` characters for SVG background images.
index be953eca321bee17c51358bc9a8cc6579c2c15c2..e3d2e1b3beff2f0da83b7a2e8dca5e55dd76e7f1 100644 (file)
@@ -39,9 +39,12 @@ Changes to our source Sass files and compiled CSS.
 - The `theme-color-level()` function is renamed to `color-level()` and now accepts any color you want instead of only `$theme-color` colors. [See #29083](https://github.com/twbs/bootstrap/pull/29083)
 - `$enable-grid-classes` doesn't disable the generation of container classes anymore [See #29146](https://github.com/twbs/bootstrap/pull/29146)
 - Line heights are dropped from several components to simplify our codebase. The `button-size()` and `pagination-size()` do not accept line height parameters anymore. [See #29271](https://github.com/twbs/bootstrap/pull/29271)
-- The `button-variant()` mixin now accepts 3 optional color parameters, for each button state, to override the color provided by `color-yiq()`. By default, these parameters will find which color provides more contrast against the button state's background color with `color-yiq()`.
-- The `button-outline-variant()` mixin now accepts an additional argument, `$active-color`, for setting the button's active state text color. By default, this parameter will find which color provides more contrast against the button's active background color with `color-yiq()`.
+- The `button-variant()` mixin now accepts 3 optional color parameters, for each button state, to override the color provided by `color-contrast()`. By default, these parameters will find which color provides more contrast against the button state's background color with `color-contrast()`.
+- The `button-outline-variant()` mixin now accepts an additional argument, `$active-color`, for setting the button's active state text color. By default, this parameter will find which color provides more contrast against the button's active background color with `color-contrast()`.
 - Ditch the Sass map merges, which makes it easier to remove redundant values. Keep in mind you now have to define all values in the Sass maps like `$theme-colors`. Check out how to deal with Sass maps on the [theming documentation]({{< docsref "/getting-started/theming#maps-and-loops" >}}).
+- `color-yiq()` function is renamed to `color-contrast()` since it's not related to YIQ colorspace anymore — [See #30168](https://github.com/twbs/bootstrap/pull/30168/) — and related variables are renamed alongside:
+  - `$yiq-contrasted-threshold` is renamed `$min-contrast-ratio`,
+  - `$yiq-text-dark` and `$yiq-text-light` are respectively renamed `$color-contrast-dark` and `$color-contrast-light`.
 
 ## JavaScript