If you’re reading this you probably know what a contrast checker does but here is a quick refresher: a contrast checker is a tool to compare the contrast between two colors like the foreground and background color to check accessibility.

Why is this important?

Well, people perceive color in different ways, what’s red to you might not look the same to someone else. There are people who are color blind and depending on the text and background color used the text may not be readable to other people. A contrast checker helps compare the ratio of the two colors, if it’s below the minimum recommended the developer or designer should make the adjustment.

Below is the minimum ratio recommended for different text sizes:

Text Type Font Size Minimum Contrast Ratio
Small/Normal Text Under 18pt regular / 14pt bold 4.5:1
Large Text 18pt+ regular / 14pt+ bold 3.1
Small Text (AAA Compliance) Same as small text 7:1
Large Text (AAA Compliance) Same as large text 4.5:1

NOTE: Even though the emphasis so far is on text, the contrast used is just as important on UI components like icons/buttons as it is for texts. For full guideline please refer w3 and accessibleweb

Luminance

Luminance can be described as the perceived brightness of a color. Not just raw light intensity, but how bright it looks to the human eye based on how our brains process red, green, and blue. We’ll get back on how to calculate luminance but first we need to know how to represent color on the web.

There are different ways to represent color on the web, but one of the most common methods is the rgb function, which stands for red, green, and blue. By combining these three colors at different intensities, we can create almost any color imaginable. The rgb function allows us to specify the amount of each color using values ranging from 0 to 255, where 0 means no intensity and 255 denotes full intensity. For example, the color pure red can be defined as rgb(255, 0, 0), while a shade of gray can be achieved with equal values, such as rgb(128, 128, 128).

It is believed green is the most sensitive to the human eye at around 71.52%, then red at 21.26% and finally blue at 7.22%, in decimal we can represent this as 0.2126 for red, 0.7152 for green and 0.0722 for blue. This is important to know when calculating luminance.

Below is a simplified function for calculating luminance using JavaScript for WCAG 2.x (to be explained later):

function getLuminance(red, green, blue) {
  function correct(color) {
    color /= 255;
    return color <= 0.03928
      ? color / 12.92
      : Math.pow((color + 0.055) / 1.055, 2.4);
  }

  const r = correct(red);
  const g = correct(green);
  const b = correct(blue);

  return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}

Function explanation:

You don’t have to memorize this function as it’s a common function you can always copy but it doesn’t hurt to understand.

On line 2 using the helper function (correct), we first normalize the color value from 0-255 to 0-1.

On line 4 to 6 it’s gamma correction function:

  • If the normalized color is dark (≤ 0.03928), it’s divided by 12.92.

  • If it’s lighter, it’s processed through a power curve (** 2.4)—a standard from the sRGB (a common color space used for digital images and web content) spec.

The math nerds discovered 0.03928 is erratic so you may see 0.04045 used in newer version (WCAG 3) but the difference isn’t that big. See the discussion on https://github.com/w3c/wcag/issues/360#issuecomment-498615230.

Getting the contrast ratio

To get the contrast ratio, we need to check the luminance between the light ratio and dark ratio.

/**
 * l1 - first luminance (number)
 * l2 - second luminance (number)
 * Returns the contrast ratio between two luminance values e.g. 4.5:1
 */
function getContrastRatio(l1, l2) {
    const lighter = Math.max(l1, l2);
    const darker = Math.min(l1, l2);
    return (lighter + 0.05) / (darker + 0.05);
}

On line 9, 0.05 is like a safety cushion to prevent division by 0 when one of the luminance value is pure black(0).

By combining the luminance function and contrast ratio, you’ll be able to build a contrast checker.

Resources used: