WCAG color contrast explained
A contrast ratio is a number from 1:1 to 21:1 that compares the brightness of two colors. White on black is 21:1, and any color on itself is 1:1. The W3C’s Web Content Accessibility Guidelines (WCAG) set minimum ratios so that people with low vision, or anyone in bad light, can read and use what you build.
Hue plays almost no part. The W3C explains that contrast is calculated from the difference in lightness, so a vivid red and a vivid green can fail badly while two dull grays pass.
Checked against the W3C’s WCAG 2.2 Understanding documents on November 12, 2026.
The thresholds
- 4.5:1 for normal text (success criterion 1.4.3, level AA).
- 3:1 for large text (also 1.4.3, level AA).
- 7:1 for normal text at the enhanced level (1.4.6, level AAA).
- 4.5:1 for large text at the enhanced level (also 1.4.6, level AAA).
- 3:1 for user interface components and graphical objects (1.4.11 Non-text Contrast, level AA).
These are hard thresholds. The W3C states that computed ratios are not rounded, so 4.499:1 fails the 4.5:1 requirement.
What counts as large text
Large text is at least 18 point, or at least 14 point if it is bold. The W3C equates 1 point with 1.333 pixels, so 18 point is 24 px and 14 point bold is about 18.5 px.
Some text has no requirement: text in an inactive control, pure decoration, text no one can see, text inside a photo with other significant content, and logotypes.
What counts as non-text
Criterion 1.4.11 asks for 3:1 against adjacent colors for two kinds of thing:
- User interface components: the visual information needed to identify a control and its state. A text input’s border, a checkbox outline, and a selected or focused state all count when nothing else identifies the control. Focus indicators must reach 3:1.
- Graphical objects: the parts of a graphic you need in order to understand it, such as the lines in a chart or the shape of an icon.
Disabled controls, decorative graphics, and logos whose colors are required by brand guidelines are exempt. A control that has visible text or a clearly contrasting icon does not also need a 3:1 border. Text inside graphics is judged under 1.4.3 instead.
The formula
WCAG defines the ratio from relative luminance, a 0 to 1 brightness for each color. For an sRGB color:
- Divide each 8-bit channel (red, green, blue) by 255 to get a value c between 0 and 1.
- Linearize it: if c is 0.04045 or less, use c / 12.92. Otherwise use ((c + 0.055) / 1.055) raised to the power 2.4.
- Combine: L = 0.2126 × R + 0.7152 × G + 0.0722 × B, using the linearized values.
- The ratio is (L1 + 0.05) / (L2 + 0.05), where L1 is the lighter color’s luminance and L2 the darker one’s.
A W3C wiki page for relative luminance still shows an older threshold of 0.03928, and its errata notice says 0.04045 is the correct value. The difference does not matter for 8-bit colors.
A worked example
Take mid-gray #767676 on white. Each channel is 118, and 118 / 255 is 0.4627. Linearized, that is ((0.4627 + 0.055) / 1.055) to the power 2.4, which is 0.1812. A gray has equal channels, and the three coefficients add up to 1, so L is 0.1812. White has L = 1.
The ratio is (1 + 0.05) / (0.1812 + 0.05), which is 1.05 / 0.2312, or 4.54:1. It passes the 4.5:1 requirement for normal text.
Now nudge the gray one step to #777777. Its luminance is 0.1845, and the ratio is 1.05 / 0.2345, or 4.48:1. That fails, though the two grays look identical. This is why you calculate rather than eyeball.
A few more, all checked with a script against white: #6D00FF scores 6.79:1, which passes AA but not AAA. #595959 scores 7.00:1, just enough for AAA. #949494 scores 3.03:1, enough for an icon or a control border but not for body text.
Checking in practice
Check every text color against every background it actually sits on, including hover, disabled-looking, and dark mode states. Check borders, icons, and focus rings against their surroundings at 3:1. If a pair fails, change lightness rather than hue, because lightness is what the ratio measures. The guide to checking a whole palette at once shows how to do this for every pair.
Opalite’s contrast checker reports the ratio for a pair and sorts the results into two groups: text (AA and AAA, normal and large) and non-text (UI components, 3:1). It also shows APCA lightness contrast alongside, and can nudge a color’s lightness until text passes AA. You can do all of this by hand with the formula above.
Quick answers
- What contrast ratio does body text need?
- At least 4.5:1 to meet WCAG 2.2 level AA (criterion 1.4.3), and 7:1 for level AAA (criterion 1.4.6).
- Does 4.499:1 count as 4.5:1?
- No. The W3C says computed contrast ratios are not rounded, so a ratio just under a threshold fails.
- Do icons and button borders need contrast?
- Yes, when they are needed to identify a control or understand a graphic. Criterion 1.4.11 asks for at least 3:1 against adjacent colors. Disabled controls and decorative graphics are exempt.
Want these checks built into your palette?
Opalite checks contrast, simulates color blindness, and exports palettes to code on iPhone, iPad, Mac, and more. Free to start.
Opalite is an independent app from Molargik Software. WCAG is published by the W3C, which is not affiliated with and does not endorse Opalite.