Color Contrast Ratio (WCAG)

easy
By FrontendAtlas Editorial · Updated Oct 19, 2026
Implement contrastRatio(foreground, background): return the WCAG 2 contrast ratio between two hex colors (#rgb or #rrggbb), from 1 for identical colors up to 21 for black on white. Convert each sRGB channel to linear light, compute relative luminance with the weights 0.2126, 0.7152 and 0.0722, and divide the lighter luminance plus 0.05 by the darker luminance plus 0.05. A public interview report of a Tesla front end developer loop (Los Angeles, January 2022) lists "Calculate the contrast between certain colors" among the onsite tasks; this practice version fixes the input format and the error rule so the tests can check the math. Concepts: accessibility, color, math, validation.

What you'll practice:

  • Turning a published accessibility formula into small, testable functions
  • Parsing and validating hex colors, including the three-digit shorthand
  • Keeping full precision when a threshold decides pass or fail

Expected behavior

Your contrastRatio() implementation should:

  • Accept #rgb and #rrggbb strings in any letter case
  • Convert each channel to linear light with the 0.04045 threshold before weighting it
  • Return (lighter + 0.05) / (darker + 0.05), so the order of the arguments does not matter
  • Return 21 for black on white and 1 for any color against itself
  • Return the unrounded ratio so a value just under 4.5 never rounds up to a pass
  • Throw a TypeError when either argument is not a valid hex color string

Arguments

  • foreground: string — A hex color, #rgb or #rrggbb.
  • background: string — A hex color, #rgb or #rrggbb.

Returns

number — The contrast ratio, from 1 to 21, unrounded.

Solution idea

Interview answer: split the formula into three small functions. parseHex validates the string and returns three channel values from 0 to 255. toLinear undoes the sRGB gamma curve: divide by 255, then use c / 12.92 at or below 0.04045 and ((c + 0.055) / 1.055) ** 2.4 above it. relativeLuminance weights the linear channels 0.2126, 0.7152 and 0.0722, because the eye is most sensitive to green. The ratio is (lighter + 0.05) / (darker + 0.05) and runs from 1 to 21. Compare that raw number with the WCAG thresholds: 4.5 for normal text, 3 for large text and 7 for AAA. Rounding first can turn a failing 4.48 into a passing 4.5.

Examples
contrastRatio('#000000', '#ffffff'); // => 21
contrastRatio('#767676', '#ffffff'); // => about 4.54, passes AA for normal text
contrastRatio('#777777', '#ffffff'); // => about 4.48, fails AA (never round up)

contrastRatio('#fff', '#2563eb'); // => about 5.17
contrastRatio('#2563eb', '#fff'); // => the same value
contrastRatio('red', '#fff'); // throws TypeError

Public interview reports

These public, self-reported interview accounts informed this practice version. The exercise is modelled on reported rounds, not copied from them, and the reports are not verified official questions or endorsements.