WCAG color contrast is measured as a contrast ratio between 1:1 and 21:1, calculated from the relative luminance of the text color and the background color. To meet WCAG 2.2 Level AA, normal text needs a ratio of at least 4.5:1 and large text at least 3:1; Level AAA raises those to 7:1 and 4.5:1.

Low-contrast text is one of the most common accessibility failures on the web, and one of the easiest to fix once you know the numbers. This guide covers the exact formula from WCAG 2.2, what counts as large text, the separate 3:1 rule for icons and form borders, a set of computed example pairs, and the mistakes that make a color pair fail an audit even when it looks fine on your screen. To test your own colors, use the Contrast Checker.

What a contrast ratio is

The W3C defines the contrast ratio as:

contrast ratio = (L1 + 0.05) / (L2 + 0.05)

Here L1 is the relative luminance of the lighter color and L2 is the relative luminance of the darker one. Luminance runs from 0 for black to 1 for white, so the result ranges from 1:1 (two identical colors) to (1 + 0.05) / (0 + 0.05) = 21:1 (black on white). Because the lighter color always goes on top, the ratio doesn't care which color is text and which is background: white text on blue scores exactly the same as blue text on white.

The ratio comes from measured luminance, not from how different two colors look. Two colors with very different hues, like red and green, can have similar luminance and a low ratio.

WCAG contrast requirements: AA and AAA

WhatLevel AALevel AAASuccess criterion
Normal text4.5:17:11.4.3 (AA), 1.4.6 (AAA)
Large text3:14.5:11.4.3 (AA), 1.4.6 (AAA)
UI components and graphics3:1No separate AAA level1.4.11 Non-text Contrast (AA)

The W3C's Understanding 1.4.3 explains that 4.5:1 was chosen because it compensates for the loss in contrast sensitivity typical of people with vision of roughly 20/40. It also makes two rules explicit:

AA is the level legal and procurement rules reference in practice. In the EU, EN 301 549 incorporates WCAG 2.1 Level AA for web content. In the U.S., the ADA itself doesn't name a technical standard, but the Department of Justice's 2024 rule for state and local government websites adopts WCAG 2.1 Level AA. AAA is a stricter bar that's hard to hit with many brand palettes and isn't usually required.

What counts as large text

WCAG defines large-scale text as at least 18 point, or at least 14 point bold. Understanding 1.4.3 gives the CSS conversion as 1pt = 1.333px, so:

Anything smaller is normal text and needs the full 4.5:1 at AA. That means a typical 16px body font, or an 18px regular heading, is not large text, even though it may look generous on screen. The sizes refer to the rendered text, so the W3C advises getting the size from the browser rather than from a design file.

How to calculate relative luminance

The WCAG 2.2 definition of relative luminance works on sRGB colors in three steps:

  1. Scale each channel to 0–1: divide the 8-bit value by 255.
  2. Linearize it: if the value is at or below 0.04045, divide by 12.92; otherwise compute ((c + 0.055) / 1.055) ^ 2.4.
  3. Weight the channels: L = 0.2126 × R + 0.7152 × G + 0.0722 × B.

Older versions of WCAG used 0.03928 as the cutoff in step 2. The W3C updated it in May 2021 and notes that the change has no practical effect. We checked: no 8-bit channel value (0 to 255) falls between the two cutoffs, so both give identical results for every hex color. The whole calculation fits in a few lines of Python:

def lin(v):
    c = v / 255
    return c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4

def luminance(hex_color):
    r, g, b = (int(hex_color.lstrip("#")[i:i+2], 16) for i in (0, 2, 4))
    return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b)

def contrast(a, b):
    hi, lo = sorted([luminance(a), luminance(b)], reverse=True)
    return (hi + 0.05) / (lo + 0.05)

contrast("#767676", "#FFFFFF")   # 4.542...

A worked example: #767676 on white

  1. Hex 76 is 118 in decimal, and 118 ÷ 255 ≈ 0.4627. It's a gray, so all three channels are the same.
  2. 0.4627 is above 0.04045, so linearize: ((0.4627 + 0.055) / 1.055)2.4 ≈ 0.1812.
  3. With all three channels at 0.1812 the weights sum to 1, so L ≈ 0.1812. White is 1.
  4. (1 + 0.05) / (0.1812 + 0.05) ≈ 4.54:1, a pass for normal text at AA.

One step lighter, #777777, gives 4.478:1 and fails. A single hex digit separates pass from fail, and no one can see that difference by eye.

Contrast ratio examples

Every ratio below was computed with the Python above and rounded to two decimals for display. Pass or fail is judged on the unrounded value.

ForegroundBackgroundRatioResult
#000000#FFFFFF21:1Maximum possible
#333333#FFFFFF12.63:1Passes AA and AAA
#595959#FFFFFF7.00:1Just passes AAA normal text
#767676#FFFFFF4.54:1Passes AA normal text
#777777#FFFFFF4.48:1Fails AA normal text; passes large
#999999#FFFFFF2.85:1Fails even large text
#FFFFFF#2563EB5.17:1Passes AA at any size
#FFFFFF#3B82F63.68:1Large text only
#FFFFFF#DC26264.83:1Passes AA
#000000#DC26264.35:1Large text only
#0000FF#FFFFFF8.59:1Passes AAA
#00FF00#FFFFFF1.37:1Fails everything

A few lessons from the table. Green carries most of a color's luminance, which is why pure green on white is nearly invisible while pure blue passes AAA. The step from #3B82F6 to #2563EB is small in HSL lightness (60% to 53%) but moves a button label from "large text only" to a pass at any size. And a 50% black overlay on the white parts of a photo produces #808080, on which white text manages only about 3.95:1, so test text on images against the lightest area it actually crosses.

Non-text contrast (1.4.11)

Text isn't the only thing that needs contrast. Success criterion 1.4.11 Non-text Contrast, a Level AA requirement added in WCAG 2.1, requires a ratio of at least 3:1 against adjacent colors for:

Inactive components are exempt, as are controls whose appearance is set by the browser and not modified by the author, and graphics where a particular presentation is essential to the information. In practice, a #949494 input border on white measures 3.03:1 and passes, while a popular pale #CCCCCC border measures only 1.61:1, leaving the field hard to find for some users.

Common fixes when a pair fails

Mistakes that slip through reviews

A quick contrast checklist

Check your colors

Enter a text and background color to get the exact ratio and AA/AAA pass or fail.

Open Contrast Checker →

If you're pulling colors from a screenshot or mockup, the Image Color Picker gives you the exact HEX value to test.

Frequently asked questions

What contrast ratio does WCAG AA require?

WCAG 2.2 Level AA requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text, which is at least 18 point (about 24px) or 14 point bold (about 18.5px). User interface components and meaningful graphics need at least 3:1 against adjacent colors.

How is the contrast ratio calculated?

Compute the relative luminance of both colors, then divide the lighter one plus 0.05 by the darker one plus 0.05. Relative luminance weights linearized red, green and blue as 0.2126, 0.7152 and 0.0722. The result runs from 1:1 to 21:1.

What counts as large text in WCAG?

Text that is at least 18 point, or at least 14 point and bold. Using the W3C conversion of 1pt = 1.333px, that is about 24px for regular text and about 18.5px for bold text. A 16px or 18px regular font is not large text.

Does WCAG 2.2 change the color contrast requirements?

No. The contrast criteria — 1.4.3 Contrast (Minimum), 1.4.6 Contrast (Enhanced), and 1.4.11 Non-text Contrast — carry over from WCAG 2.1 with the same 4.5:1, 7:1, and 3:1 thresholds. The criteria that WCAG 2.2 added focus on other areas, such as focus visibility, target size, and accessible authentication.

Is 4.49:1 close enough to pass WCAG AA?

No. WCAG treats 4.5:1 as a hard threshold, and the W3C's guidance says computed ratios should not be rounded, so even 4.499:1 fails. If a pair lands just under the line, darken or lighten one of the colors slightly until the unrounded ratio reaches 4.5:1.

Do logos and disabled buttons need to meet contrast requirements?

No. Text that is part of a logo or brand name has no contrast requirement, and neither do inactive user interface components such as a disabled button. Purely decorative text is also exempt, but any text a user needs to read, including captions and helper text, is covered.

Related tools