Color Contrast and WCAG 2.2: Ratios, Formula and Fixes
WCAG 2.2 needs 4.5:1 contrast for normal text, 3:1 for large text and UI parts, 7:1 for AAA. See the formula, real colour pairs and how to fix failures.
WCAG 2.2, the current web accessibility standard, asks for a contrast ratio of at least 4.5:1 between normal text and its background, and 3:1 for large text and for the parts of buttons, form fields and icons that people need to see. The stricter AAA level asks for 7:1 for normal text and 4.5:1 for large text. Large text means at least 18 point (about 24 CSS pixels), or 14 point (about 18.5 px) if it is bold.
To test any pair, enter the two hex codes in the colour contrast checker. It shows the exact ratio and a pass or fail for each level. This guide explains the rules, works the formula by hand, lists real colour pairs with their results, and shows how to fix colours that fail.
It is worth the effort: WebAIM's 2026 scan of the top one million home pages found low-contrast text on 83.9% of them, the most common problem it detected.
The WCAG 2.2 contrast thresholds
Three success criteria in WCAG 2.2 deal with contrast. Level AA is the one laws and government guidelines usually point to; AAA is an extra level for sites that want more.
| What is on screen | Level AA | Level AAA | Criterion |
|---|---|---|---|
| Normal text and images of text | 4.5:1 | 7:1 | 1.4.3 and 1.4.6 |
| Large text (18 pt, or 14 pt bold) | 3:1 | 4.5:1 | 1.4.3 and 1.4.6 |
| UI components and meaningful graphics | 3:1 | No higher level | 1.4.11 |
Ratios run from 1:1 (two identical colours) to 21:1 (black on white). They are not rounded. W3C's guidance says 4.499:1 does not meet 4.5:1, so a tool that displays "4.5" can still be showing a fail.
What counts as large text
WCAG defines large-scale text as at least 18 point, or at least 14 point when bold. W3C's Understanding document gives the CSS equivalents as about 24 px and 18.5 px. So a 16 px paragraph needs 4.5:1, bold or not; a 24 px heading needs 3:1; and a 20 px subheading counts as large only if it is bold. The size that counts is the size you deliver, not what a reader gets by zooming in, and thin decorative fonts need more contrast than their size suggests.
How the contrast ratio is calculated
The ratio compares the relative luminance of the two colours: how bright each one is, on a scale from 0 for black to 1 for white. For a hex colour the steps are:
- Split the hex code into red, green and blue values from 0 to 255, and divide each by 255.
- Linearise each channel. If the value is 0.04045 or less, divide it by 12.92; otherwise calculate ((value + 0.055) ÷ 1.055) to the power 2.4. This undoes the brightness curve that screens apply.
- Weight the channels: L = 0.2126 × R + 0.7152 × G + 0.0722 × B. Green counts most because our eyes are most sensitive to it.
- Contrast ratio = (L of the lighter colour + 0.05) ÷ (L of the darker colour + 0.05).
Worked example 1: white text on purple #6D48F5. The channels are 109, 72 and 245.
- Red: 109 ÷ 255 = 0.4275, linearised to 0.1529
- Green: 72 ÷ 255 = 0.2824, linearised to 0.0648
- Blue: 245 ÷ 255 = 0.9608, linearised to 0.9131
- L = 0.2126 × 0.1529 + 0.7152 × 0.0648 + 0.0722 × 0.9131 = 0.0325 + 0.0463 + 0.0659 = 0.1448
- White has L = 1, so the ratio is (1 + 0.05) ÷ (0.1448 + 0.05) = 1.05 ÷ 0.1948 = 5.39:1
The contrast checker gives the same 5.39:1: a pass for AA at every size and for AAA large text, and a fail for AAA normal text.
Worked example 2: the lightest grey that passes on white. In a grey, all three channels are equal and the three weights add up to 1, so L is just the linearised channel. #767676 has channels of 118. 118 ÷ 255 = 0.4627, linearised to 0.1812, so the ratio is 1.05 ÷ 0.2312 = 4.54:1, a pass. One step lighter, #777777 (channels of 119), comes out at 4.48:1 and fails. If you like grey body text, #767676 is as light as it can go on white.
Before May 2021 the WCAG definition used 0.03928 instead of 0.04045 in step 2, and the site's checker still uses 0.03928. For hex colours this makes no difference at all, because no channel value from 0 to 255 falls between the two cut-offs.
Real colour pairs, checked
These results come from the site's contrast checker. The last column covers large text and UI components, since both need 3:1.
| Text on background | Ratio | Normal text (AA) | Large text and UI (AA) |
|---|---|---|---|
| Black on white | 21:1 | Pass, also AAA | Pass |
| Grey #595959 on white | 7:1 | Pass, also AAA | Pass |
| White on navy #000080 | 16.01:1 | Pass, also AAA | Pass |
| White on green #138808 | 4.61:1 | Pass, just | Pass |
| White on red #FF0000 | 4:1 | Fail | Pass |
| Grey #949494 on white | 3.03:1 | Fail | Pass, just |
| White on saffron #FF9933 | 2.13:1 | Fail | Fail |
| Black on saffron #FF9933 | 9.86:1 | Pass, also AAA | Pass |
| White on bright green #25D366 | 1.98:1 | Fail | Fail |
Two patterns stand out. Bright, warm colours such as saffron, orange, yellow and light green rarely work with white text, but they work well with black or very dark text. And pure red is a trap: white on #FF0000 looks bold but reaches only 4:1, which is fine for a large heading and a fail for a paragraph or a small button label.
Using the site's contrast checker
Type the text colour and the background colour as hex codes (three-digit codes such as #fff work, and the # is optional), then press Check contrast. You get a sample line in your colours, the ratio, and four rows: AA normal text (4.5), AA large text (3), AAA normal (7) and AAA large (4.5). For an input border, icon or focus outline, read the AA large text row, which uses the same 3:1 threshold as criterion 1.4.11. The order of the two colours does not matter.
- Hex only. It does not accept rgb() or hsl() values, colour names or 8-digit hex with transparency. Convert other formats first with the colour converter, and for a semi-transparent colour, test the solid colour it produces on your background.
- The ratio is shown to two decimals, but pass and fail use the exact value. Blue #0078D7 on white displays as 4.5:1 and still fails AA normal text, because the true ratio is 4.4989. That follows W3C's no-rounding rule; darken the colour slightly until the row says Pass.
Non-text contrast: fields, icons and focus
Criterion 1.4.11, added in WCAG 2.1, asks for 3:1 between the parts of an interface that people need to see and the colours next to them. It covers:
- the border of a text input or checkbox, when that border is what shows where the field is;
- icons that carry meaning without a text label, such as a search magnifier or a close cross;
- the focus indicator keyboard users follow, and the visual change that shows a toggle is on;
- chart lines and segments that a reader needs in order to understand the chart.
A light grey input border such as #E4E3E2 on white is only 1.28:1, so the field almost disappears for someone with low vision. #938D89 reaches 3.28:1 and passes. W3C's guidance does not require a visible boundary around a button whose text label already shows that it is a button, but the label text itself needs 4.5:1 against the button colour (3:1 if large), and the button still needs a visible focus indicator.
WCAG exempts text in a logo or brand name, purely decorative text and disabled controls. Everything else counts, including placeholder text in form fields, which W3C's guidance says the 4.5:1 rule applies to.
How to fix colours that fail
Change the lightness of one colour and keep its hue, so the design still looks like yours.
- Darken the darker colour, or lighten the lighter one. Run your brand colour through the shades and tints generator and test each step. Orange #E85D04 with white text is 3.50:1: fine for large headings, not for a 16 px button label. Its 20% shade, #BA4A03, reaches 5.16:1 and passes AA while still reading as the same orange.
- Swap white text for dark text on bright colours. Black on saffron is 9.86:1, where white is 2.13:1.
- Put text on a solid panel or dark overlay when it sits on a photo or gradient.
- Do not rely on colour alone. WCAG 1.4.1 asks that colour is not the only way information is shown. Pair a red error border with an error message, and make links in body text recognisable without colour, for example with an underline.
Fix colours once, at the palette level, and every page inherits the fix. The guides to building a brand colour palette and tints, shades and colour scales show how to plan passing pairs from the start.
APCA and WCAG 3: what is changing
Some design tools show an "APCA" score (Accessible Perceptual Contrast Algorithm). APCA tries to model perceived contrast more closely, for example treating light text on dark backgrounds differently from dark text on light. It is not part of any W3C standard. It was explored for WCAG 3 but dropped from the drafts in 2023, and the WCAG 3.0 Working Draft of 10 September 2026 still says "the contrast algorithm used in WCAG 3 is yet to be determined".
W3C says the WCAG 3 draft should not be cited as anything other than work in progress. Until that changes, WCAG 2.2 AA is the standard to meet; APCA can be an extra check, not a replacement for the WCAG 2 ratios.
Accessibility rules in India
The Rights of Persons with Disabilities Act, 2016 requires the government to take measures so that content in audio, print and electronic media is available in accessible formats (section 42). For government websites and apps, NIC's Guidelines for Indian Government Websites and Apps (GIGW 3.0), which name the Act as one of their bases, require conformity with WCAG 2.1 Level AA. WCAG 2.1 has the same contrast criteria as 2.2: 4.5:1 for text, 3:1 for large text and 3:1 for interface parts.
In November 2024 the Supreme Court, in Rajive Raturi v Union of India, directed the Union government to frame mandatory accessibility rules under the Act, so if you build for a government body, check the rules in force at the time. For a business site, check whether your regulator or client contract names a standard. Where none is named, WCAG 2.2 AA is the sensible benchmark, and contrast is the cheapest part of it to get right.
Frequently asked questions
What contrast does a button need?
The label needs 4.5:1 against the button colour, or 3:1 if the label is large. The button's shape needs 3:1 against the page only when nothing else, such as its text, shows it is a button. Its focus indicator needs 3:1 as well.
Does dark mode need the same contrast?
Yes. The thresholds are the same in both themes, so check every pair again. A colour can fail on white and pass on dark grey: orange #E85D04 is 3.50:1 on white but 5.11:1 on the near-black #181716.
How do I check text on a photo or gradient?
Find the lightest area behind light-coloured text (or the darkest area behind dark text), read its hex code with the eyedropper in your design app or your browser's developer tools, and check that colour against the text. If it fails, add a solid or semi-transparent dark panel behind the text.
Do I need AAA?
Laws and GIGW point to AA. W3C does not recommend requiring AAA for entire sites, because some content cannot meet every AAA criterion. Aiming for 7:1 on long reading text is still a good habit where your design allows it.
Sources: W3C, Web Content Accessibility Guidelines (WCAG) 2.2, W3C Recommendation, 12 December 2024, and Understanding SC 1.4.3 and 1.4.11; W3C, WCAG 3.0 Working Draft, 10 September 2026; WebAIM Million report, 2026; NIC, Guidelines for Indian Government Websites and Apps (GIGW 3.0); Rights of Persons with Disabilities Act, 2016, section 42; ratios from the site's contrast checker, October 2026.
- #colour contrast
- #WCAG 2.2
- #accessibility
- #contrast ratio
- #web design