WCAG Color Contrast Explained: Ratios, Thresholds and a Worked Example
By the ToolWorld Online team · Published 2026-10-29 · Updated 2026-10-29 · 7 min read
Color contrast is one of the most common accessibility problems on the web, and also one of the easiest to fix once you understand how it is measured. The Web Content Accessibility Guidelines, usually shortened to WCAG, define contrast as a single number called the contrast ratio, which ranges from 1:1 for two identical colors to 21:1 for pure black on pure white. This guide explains where that number comes from, what the AA and AAA thresholds actually require, how large text and non-text elements are treated differently, and how to calculate a real ratio by hand so the result from any checker makes sense.
Why contrast matters
Text that looks perfectly readable on a designer's calibrated monitor can become hard to read for many people in ordinary conditions. Low vision, age-related changes in the eye, color vision deficiencies, cheap or dim screens, and bright sunlight on a phone all reduce the difference a reader perceives between text and its background. Light gray body copy on a white page is a classic example: it looks refined in a mockup and turns into a strain for a large share of real visitors.
WCAG addresses this with measurable success criteria rather than vague advice. Because the requirement is a number, a team can test it, record it, and agree on it. Contrast requirements also appear in accessibility laws and procurement rules in many countries, which usually reference WCAG 2.1 or 2.2 at level AA, so getting contrast right is both a usability improvement and a common compliance requirement.
Relative luminance: the building block
The contrast ratio is built on relative luminance, which is a measure of how bright a color appears to the human eye, scaled from 0 for black to 1 for white. It is not the same as the lightness value in HSL. A pure yellow and a pure blue can share the same HSL lightness, yet yellow looks far brighter, and relative luminance captures that difference.
Calculating it takes three steps. First, take each of the red, green and blue channel values, which run from 0 to 255 in a hex color, and divide by 255 to get a number between 0 and 1. Second, convert each of those gamma-encoded sRGB values to linear light. If the value is 0.04045 or less, divide it by 12.92. Otherwise, add 0.055, divide by 1.055, and raise the result to the power of 2.4. Some versions of the WCAG text, and many tools, use 0.03928 as the cutoff instead, a figure inherited from an older sRGB draft; the difference never changes a real result for 8-bit colors.
Third, combine the three linear values with weights that reflect how sensitive the eye is to each primary: luminance equals 0.2126 times red plus 0.7152 times green plus 0.0722 times blue. Green dominates because our eyes are most sensitive to it, while blue contributes very little, which is why dark blue text can pass easily while bright blue links sometimes fail.
The contrast ratio formula
Once you have the relative luminance of both colors, the contrast ratio is calculated as the lighter luminance plus 0.05, divided by the darker luminance plus 0.05. The 0.05 added to each side accounts for ambient light reflecting off a screen, and it also keeps the formula from dividing by zero when one color is pure black.
The order of the colors does not matter, because the formula always puts the lighter one on top. White text on navy gives exactly the same ratio as navy text on white. What matters is the pair. The result is written as a ratio such as 4.5:1, and it is compared against the thresholds in the next section without rounding up. A pair that computes to 4.47:1 does not pass a 4.5:1 requirement, even though it might display as 4.5 in a tool that rounds to one decimal place.
AA and AAA thresholds and the definition of large text
WCAG sets two levels for text contrast. Success criterion 1.4.3, Contrast (Minimum), is level AA and requires at least 4.5:1 for normal text and at least 3:1 for large text. Success criterion 1.4.6, Contrast (Enhanced), is level AAA and raises those figures to 7:1 for normal text and 4.5:1 for large text. Most organizations target AA across the board and use AAA for long-form reading content where they can.
Large text has a precise definition: at least 18 point, or at least 14 point if the text is bold. Because one CSS point equals 1.333 CSS pixels, that works out to roughly 24 pixels for regular weight and about 18.66 pixels for bold. A 20 pixel heading in a normal weight is therefore not large text and must meet 4.5:1, a detail that trips up many design systems.
There are a few exemptions. Text that is purely decorative, text that is part of an inactive user interface component such as a disabled button, text inside a photograph that is incidental, and text in logos or brand names have no contrast requirement. Placeholder text, error messages, and link text are not exempt and must meet the same thresholds as body copy.
Non-text contrast
WCAG 2.1 added success criterion 1.4.11, Non-text Contrast, at level AA. It requires a contrast ratio of at least 3:1 against adjacent colors for the visual information needed to identify user interface components and their states, and for the parts of graphics needed to understand the content.
In practice this covers the border of a text input when the border is the only thing showing where the field is, the outline of a checkbox or radio button, the keyboard focus indicator, icons that act as buttons without a text label, and the lines or segments in a chart that carry meaning. A pale gray input border on white is one of the most frequent failures. If a chart uses color to separate data series, each series should reach 3:1 against its neighbors or be distinguished another way, such as with labels or patterns. Separately, WCAG says color must never be the only way information is conveyed, so a required field should not be marked by red text alone.
Worked example: blue text on a white background
Suppose you want to use the blue #2563EB for link text on a white page. Split the hex code into channels: 25 is 37, 63 is 99, and EB is 235. Dividing by 255 gives 0.1451 for red, 0.3882 for green and 0.9216 for blue.
All three are above 0.04045, so each uses the power formula. Red becomes ((0.1451 + 0.055) divided by 1.055) to the power of 2.4, which is about 0.0185. Green becomes about 0.1248, and blue becomes about 0.8308. Applying the weights, luminance equals 0.2126 times 0.0185, plus 0.7152 times 0.1248, plus 0.0722 times 0.8308. That is 0.0039 plus 0.0892 plus 0.0600, or about 0.1532. White has a luminance of exactly 1.
The contrast ratio is (1 + 0.05) divided by (0.1532 + 0.05), which is 1.05 divided by 0.2032, or about 5.17:1. That passes AA for normal text and AAA for large text, but falls short of the 7:1 needed for AAA body text. For comparison, the darker blue #1D4ED8 reaches about 6.70:1 on white, the mid gray #767676 reaches about 4.54:1, which is about the lightest gray that still passes AA on white, and the lighter gray #949494 manages only about 3.03:1, enough for large text but not for body copy.
Checking and fixing contrast with ToolWorld tools
The ToolWorld Color Contrast Checker performs exactly the calculation described above. You choose a foreground and a background color with a color picker or by typing hex codes, and it shows the contrast ratio to two decimal places along with a live preview of large and small sample text on your chosen background. It reports whether normal text passes AA and AAA and whether large text passes AA, so you can test a pair in seconds rather than working through the arithmetic. It checks text pairs; for non-text elements, compare the ratio it shows against the 3:1 target yourself.
When a pair fails, the usual fix is to keep the hue and change the lightness: darken the text or lighten the background until the ratio clears the threshold. The ToolWorld Color Palette Generator can help here, because its monochrome scheme produces lighter and darker variations of a single base color, while its analogous, complementary, triadic and tetradic schemes suggest related hues. Copy a candidate into the contrast checker, test it against your background, and keep the shades that pass. Building a palette this way, with tested text and background pairs noted from the start, saves far more time than auditing finished pages.
A final tip: test real combinations, not just your primary brand color against white. Hover states, text on colored banners, links inside callout boxes, and dark mode variants each create a new pair that needs its own check.
