How To Generate WCAG Compliant Contrast Color in Bootstrap


Author profile picture

What is the importance of achieving the prescribed contrast ratio?

The intent of this Success Criterion is to provide enough contrast between text and its background so that it can be read by people with moderately low vision.

$theme-colors: (
  "primary":    $primary,
  "secondary":  $secondary,
  "success":    $success,
  "info":       $info,
  "warning":    $warning,
  "danger":     $danger,
  "light":      $light,
  "dark":       $dark
) !default;

Let us take example of a simple button. Based on the

$theme-colors

set, buttons are generated for each theme color variant in

scss/_button.scss

using

button-variant

mixin. This mixin receives a background color for which we need to generate corresponding contrast text color using

color-contrast

function. This function uses

$min-contrast-ratio

, which defaults to

4.5

to achieve WCAG 2 AA contrast ratio.

@each $color, $value in $theme-colors {
  .btn-#{$color} {
    @include button-variant($value, $value);
  }
}

In

color-contrast

function, the background color’s

contrast-ratio

is compared with foreground colors in following order:

  • $color-contrast-light
  • $color-contrast-dark
  • $white
  • $black

We can override the values of

$color-contrast-light

and

$color-contrast-dark

which is set to default as

$white

and

$black

respectively. All these values are looped to find the suitable match.

@function color-contrast($background, $color-contrast-dark: $color-contrast-dark, $color-contrast-light: $color-contrast-light, $min-contrast-ratio: $min-contrast-ratio) {
  $foregrounds: $color-contrast-light, $color-contrast-dark, $white, $black;
  $max-ratio: 0;
  $max-ratio-color: null;

  @each $color in $foregrounds {
    $contrast-ratio: contrast-ratio($background, $color);
    @if $contrast-ratio > $min-contrast-ratio {
      @return $color;
    } @else if $contrast-ratio > $max-ratio {
      $max-ratio: $contrast-ratio;
      $max-ratio-color: $color;
    }
  }

  @warn "Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$background}...";

  @return $max-ratio-color;
}

When the value of contrast ratio is greater than

$min-contrast-ratio

, that color is returned. Contrast ratio can be calculated by finding out relative luminance of both background and foreground color in current loop.

@function contrast-ratio($background, $foreground: $color-contrast-light) {
  $l1: luminance($background);
  $l2: luminance(opaque($background, $foreground));

  @return if($l1 > $l2, ($l1 + .05) / ($l2 + .05), ($l2 + .05) / ($l1 + .05));
}

WCAG algorithm to calculate relative luminance is used, which replaces yiq contrast algorithm in Bootstrap.

relativeLuminance (c) {
  c = c / 255;
  return c < 0.03928 ? c / 12.92 : 
  Math.pow((c + 0.055) / 1.055, 2.4);
}

SCSS implementation:

@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);
}

Here,

$_luminance-list

is a list of all possible value for

Math.pow((c + 0.055) / 1.055, 2.4)

where

c

lies between [0, 255], which is the range for any channel. This method is used to overcome the difficulty of not having a power function in SCSS as mentioned here. The same list is maintained in Bootstrap as well, with 4th decimal point. Refer here for more precise value. This

The

red()

,

green()

and

blue()

are SCSS in-built functions to extract each channel’s value for calculation.

opaque

is function, to remove the alpha channel by truncating it and mixing it with white in a ratio equal to alpha channel’s value.

@function opaque($background, $foreground) {
  @return mix(rgba($foreground, 1), $background, opacity($foreground) * 100);
}

Few PRs are already resolved to achieve this contrast ratio like mentioned here and here.

References

  1. https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.htm
  2. https://github.com/twbs/bootstrap/pull/30168

Tags

Join Hacker Noon

Create your free account to unlock your custom reading experience.



Source link

New PS5 games: upcoming PS5 game release dates Previous post New PS5 games: upcoming PS5 game release dates
The RetroBeat: River City Girls is a beat-’em-up delight Next post The RetroBeat: River City Girls is a beat-’em-up delight