Skip to main content
Back to Blog
Accessibility8 min readDecember 17, 2025

How to Check and Calculate Contrast Ratios for Accessibility

Written by Dann B.

Frontend Developer and Designer

Share:

Every accessible color decision comes down to one number: the contrast ratio. It is a single, objective figure you can compute, check, and defend - no eyeballing required. This guide shows exactly how contrast ratios work, how to calculate one by hand, and how to use calculators and testing tools to keep every color combination compliant.

What a Contrast Ratio Actually Measures

The WCAG contrast ratio compares the relative luminance of two colors: the text or graphic against its background. Luminance is the perceived brightness of a color on a scale from 0 (pure black) to 1 (pure white). The ratio formula is:

(L1 + 0.05) / (L2 + 0.05)

where L1 is the lighter color's luminance and L2 is the darker color's. The +0.05 term accounts for real-world viewing conditions where even black is never perfectly dark. The result ranges from 1:1 (identical colors) to 21:1 (black on white).

How to Calculate Luminance Step by Step

Calculating luminance requires converting sRGB values to linear light before weighting them. Here is the full procedure:

  1. Take the RGB channels of each color, each on a 0-255 scale. For example, #404040 is R=64, G=64, B=64.
  2. Divide each channel by 255: 64 / 255 = 0.25098.
  3. Apply the gamma expansion: for each channel c, if c <= 0.04045 then c/12.92, otherwise ((c + 0.055) / 1.055)^2.4. For 0.25098, the result is about 0.0509.
  4. Weight the channels: L = 0.2126 × R_lin + 0.7152 × G_lin + 0.0722 × B_lin. Since our example is gray, all channels are equal, so L ≈ 0.0509.
  5. Compute the ratio against the background luminance.

Take white (#FFFFFF), luminance 1.0, against this #404040 gray. The ratio is (1.0 + 0.05) / (0.0509 + 0.05) = 1.05 / 0.1009 ≈ 10.4:1. That comfortably passes AA and even AAA.

A Practical Worked Example

Compare #FFFFFF text on #FFEB3B (bright yellow). Yellow's channels are R=255, G=235, B=59. After the conversion, its luminance is about 0.7742. The ratio is (0.7742 + 0.05) / (1.0 + 0.05)... wait, white is lighter here, so the ratio is (1.0 + 0.05) / (0.7742 + 0.05) = 1.05 / 0.8242 ≈ 1.27:1. That fails every threshold. White text on yellow is effectively invisible - and now you know the exact number behind the intuition.

The Thresholds in One Table

  • 4.5:1 - normal text (under 18pt/24px, or under 14pt bold), WCAG AA
  • 3:1 - large text (18pt+ or 14pt+ bold), WCAG AA
  • 7:1 - normal text, WCAG AAA
  • 4.5:1 - large text, WCAG AAA
  • 3:1 - UI components, graphical objects, and focus indicators

A useful rule of thumb: any pair where the lighter color is at least about 7.5 times brighter (in linear luminance terms) than the darker will pass 4.5:1. In practice, near-black text on near-white backgrounds passes easily; mid-tones need checking.

Using Contrast Ratio Calculators

You do not need to do the math by hand. The standard tools:

  • WebAIM Contrast Checker (webaim.org/resources/contrastchecker): enter two hex codes, see the ratio, and get immediate AA/AAA pass or fail at normal and large sizes. The reference tool for most teams.
  • Stark (Figma, Sketch, browser): inline contrast checking plus a color-blind simulator in your design tool.
  • Contrast App (contrast.app): a free macOS picker that samples colors directly from your screen.
  • Chrome DevTools: the color picker in the Styles panel displays the contrast ratio for the current element and warns below AA.
  • axe DevTools and Lighthouse: automated audits that scan an entire page and list every contrast failure with the specific ratio.

Testing Steps for a Real Project

  1. List your semantic colors: every text color, every background, every accent used on text or UI.
  2. Build a matrix: check each text color against every background it can appear on - including hover, focus, error, dark mode, and image overlays.
  3. Fix the worst pairs first: the failures with the largest audience impact (body text, primary buttons) rank above decorative accents.
  4. Set palette guardrails: if a color keeps failing, replace it with an accessible derivative rather than creating one-off overrides.
  5. Automate the check: add a contrast lint to CI so future color changes fail the build instead of the audit.

Contrast for Non-Text Elements

Remember that 3:1 applies beyond text. Check borders, icons, form outlines, chart segments, and focus rings. A practical tip: your default focus indicator should be checked against every background in the interface, because it travels across the whole page. Many teams standardize on a high-contrast ring (for example, a dark outline offset from a light one) that works everywhere.

Common Calculation Mistakes

  • Forgetting the gamma step: using the raw RGB values without the sRGB expansion produces wildly wrong ratios. Always convert to linear luminance first.
  • Mixing up which color is lighter: the formula divides the lighter by the darker; reversing them gives the same ratio only because it is symmetric, but the check against thresholds needs the correct orientation.
  • Ignoring the background behind the text: with images or gradients, the worst-case region behind the glyphs defines the ratio, not the average background color.
  • Trusting perception over math: your monitor's brightness and calibration affect what you see, not the computed ratio. The ratio is the standard; use tools calibrated to it.

Relative Luminance: The Math Behind the Ratio

The WCAG contrast ratio formula depends on relative luminance, and understanding the calculation reveals why the ratio does not match intuitive brightness perception. The process has three steps. First, each sRGB channel value (0-255) is normalized to 0-1 by dividing by 255. Second, each normalized value undergoes linearization: if the value is less than or equal to 0.04045, it is divided by 12.92; otherwise, it is raised to the power of 2.4 after subtracting 0.055 and dividing by 0.055. This nonlinear curve (the sRGB transfer function) accounts for the fact that human vision perceives brightness logarithmically, not linearly. A pixel value of 128 is not half as bright as 255 - it is roughly 21% as bright. Third, the linearized RGB values are combined using the luminance weights: 0.2126 for red, 0.7152 for green, and 0.0722 for blue. Green dominates because the human eye's M-cones (medium wavelength) are most sensitive. The contrast ratio is then (L1 + 0.05) / (L2 + 0.05) where L1 is the lighter luminance and L2 the darker. The 0.05 offset prevents division by zero and accounts for ambient light. For example, pure green (#00FF00) has a linear luminance of approximately 0.7152, while pure blue (#0000FF) has only 0.0722 - explaining why green text on white passes contrast ratios that blue text at the same saturation fails.

Contrast Ratio in Motion Design

Motion design introduces unique contrast challenges because elements change position, size, and visibility over time. A text element that has sufficient contrast when stationary may become unreadable during transitions if it passes through a low-contrast zone of the background. When animating content over multi-colored backgrounds or images, the safest approach is to place a semi-transparent scrim behind text that maintains minimum contrast throughout the entire animation path. For UI micro-interactions like button hover states and form field focus indicators, the contrast ratio must be maintained not just in the resting and final states but at every frame of the transition. Testing motion contrast requires scrubbing through animations frame-by-frame in your design tool and checking contrast at the beginning, middle, and end of each transition, as well as at any point where the moving element crosses a background color boundary.

The Takeaway

The contrast ratio is the most objective quality gate in accessible design. Compute it with the luminance formula or a trusted calculator, compare it against the WCAG thresholds for the element's size and role, and re-check whenever any color changes. Adopt that habit and every color you ship will be backed by a number - the same number that accessibility audits, laws, and screen-reader users all rely on.

Contrast in Context: Beyond the Numbers

A passing ratio is the floor, not the finish line. Large text can pass at 3:1 yet feel weak in long paragraphs, and a 4.5:1 ratio computed on a flat background changes the moment a subtle gradient or image sits behind the text. Check contrast against the real surface - sample the darkest and lightest pixels of any background pattern - and add a 10-15% margin above the minimum for body copy. Accessibility targets keep everyone safe; measured reality keeps readers comfortable.

Frequently Asked Questions

How is the WCAG contrast ratio calculated?

The ratio is (L1 + 0.05) / (L2 + 0.05), where L1 and L2 are the relative luminances of the lighter and darker colors. Luminance is computed from sRGB channels after applying the gamma expansion and weighting them 0.2126 red, 0.7152 green, 0.0722 blue.

What is a good contrast ratio for body text?

At least 4.5:1 for normal text under WCAG AA. For AAA, aim for 7:1. As a practical target, most designers use near-black text on near-white backgrounds, which typically lands between 12:1 and 21:1.

Can I check contrast ratios for free?

Yes. WebAIM's Contrast Checker is free and is the community reference tool. Chrome DevTools shows live contrast ratios in the color picker, and open-source tools like axe DevTools can audit whole pages automatically.

Subscribe to Color Insights

Get weekly color tips and design insights delivered to your inbox.