WCAG color contrast requirements: ratios, rules and fixes
WCAG contrast rules in plain English: 4.5:1 for text, 3:1 for large text, buttons and icons, what's exempt, and how to fix colors that fail.
WCAG asks for a contrast ratio of at least 4.5:1 between normal text and its background, and 3:1 for large text. Buttons, form field borders, icons and other graphics that people need to see must reach 3:1 against the colors next to them. Both are Level AA requirements, and you can check any pair of colors with our free contrast checker.
What contrast ratio does WCAG require?
Four WCAG success criteria deal with color. Three of them set contrast ratios:
| Success criterion | Level | Normal text | Large text | Other |
|---|---|---|---|---|
| 1.4.3 Contrast (Minimum) | AA | 4.5:1 | 3:1 | |
| 1.4.6 Contrast (Enhanced) | AAA | 7:1 | 4.5:1 | |
| 1.4.11 Non-text Contrast | AA | 3:1 for UI components and graphics |
The fourth, 1.4.1 Use of Color (Level A), isn’t about ratios. It says color can’t be the only way you show information. More on that below.
Most sites aim for Level AA, so 4.5:1 and 3:1 are the numbers to remember. W3C chose 4.5:1 because it compensates for the loss of contrast sensitivity usually experienced by people with vision loss equivalent to about 20/40 vision.
What counts as large text?
WCAG defines large-scale text as at least 18 point, or at least 14 point and bold. On the web, W3C uses 1pt = 1.333px, so:
- 18pt regular is 24 CSS pixels
- 14pt bold is about 18.66 CSS pixels (W3C’s Understanding page rounds this to approximately 18.5px)
The size that counts is the size you deliver, not the size after someone zooms in. Thin or decorative fonts can look fainter than their color suggests, so give them extra margin. If your text sits close to the cutoff, use 4.5:1 and remove the doubt.
How is the contrast ratio calculated?
The ratio compares the relative luminance of two colors: how bright each one is, on a scale from 0 for black to 1 for white. For an sRGB color, each channel is first converted to a linear value, then weighted by how sensitive our eyes are to it:
For each channel (R, G, B), with c = channel value / 255:
if c <= 0.04045: linear = c / 12.92
else: linear = ((c + 0.055) / 1.055) ^ 2.4
L = 0.2126 * R + 0.7152 * G + 0.0722 * B
contrast ratio = (L1 + 0.05) / (L2 + 0.05)
where L1 is the lighter color and L2 the darker one
Ratios run from 1:1 (two identical colors) to 21:1 (black on white). Older material uses 0.03928 instead of 0.04045 in the first step. W3C changed the value in May 2021, and it makes no practical difference for 8-bit colors.
Which colors pass?
Here’s how a few common grays do as text on a white (#FFFFFF) background:
| Text color | Ratio | Normal text (AA) | Large text (AA) | Normal text (AAA) |
|---|---|---|---|---|
#999999 |
2.84:1 | Fails | Fails | Fails |
#949494 |
3.03:1 | Fails | Passes | Fails |
#777777 |
4.47:1 | Fails | Passes | Fails |
#767676 |
4.54:1 | Passes | Passes | Fails |
#595959 |
7.00:1 | Passes | Passes | Passes |
Notice how close #777777 and #767676 are. One step on a single hex digit is the difference between failing and passing, which is why you should check every pair rather than judge by eye. Paste yours into the contrast checker to see the exact ratio.
Do buttons, icons and form fields need contrast too?
Yes. 1.4.11 Non-text Contrast (Level AA) requires a ratio of at least 3:1 against adjacent colors for:
- User interface components: the visual information people need to identify a control and its state. Think of the border of a text field when that border is the only thing showing where the field is, a checkbox’s box and tick, or a toggle’s on and off positions.
- Graphical objects: the parts of a graphic needed to understand it, such as the lines in a chart or an icon that carries meaning.
It also covers focus indicators. When a control has keyboard focus, the indicator must have enough contrast against the background next to it.
A very common failure is the pale input border. A #E0E0E0 border on white is only 1.32:1. Darkening it to #8A8A8A gives 3.45:1:
/* Fails 1.4.11: 1.32:1 against the white page */
.field {
border: 1px solid #e0e0e0;
}
/* Passes: 3.45:1 */
.field {
border: 1px solid #8a8a8a;
}
There are exceptions: inactive (disabled) components, controls whose look comes from the browser and hasn’t been changed by you, and graphics where a particular presentation is essential to the information. Text inside a graphic still follows the text rules in 1.4.3.
Can I use color alone to show meaning?
No. 1.4.1 Use of Color (Level A) says color must not be “the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element.” People with color vision deficiencies, and anyone on a washed-out screen, can miss a color difference.
Common examples, and how to fix them:
- A form error shown only as a red border. Add an error icon and a text message that says what’s wrong.
- Required fields marked only in red. Add the word “required” or an asterisk that’s explained above the form.
- Links in body text that differ only by color. The simplest fix is to underline them.
If you’d rather not underline links, W3C’s technique G183 describes giving link text a contrast ratio of at least 3:1 against the surrounding text. The link and the body text both still need 4.5:1 against the background. With dark body text on white, only a narrow range of colors can do both, which is why underlines are usually easier.
What is exempt from contrast requirements?
Under 1.4.3, these have no contrast requirement:
- Logotypes: text that is part of a logo or brand name.
- Inactive components: text in a disabled button or field.
- Pure decoration: text that’s there only for visual effect and carries no meaning.
- Invisible text: text that isn’t visible to anyone.
- Incidental text in pictures: text that’s part of a picture containing significant other visual content, such as a street sign in a photo of a busy street.
Brand guidelines are not an exemption. W3C says text with insufficient contrast because of corporate identity or brand rules still fails. If your brand color is too light for text, keep it for large shapes and backgrounds, and use a darker shade for text and links.
Does placeholder text need to meet contrast?
Yes. W3C states that 1.4.3 applies to placeholder text and to text that appears when you hover over something. Many browser and theme defaults are lighter than 4.5:1, so set the color yourself:
input::placeholder,
textarea::placeholder {
color: #767676; /* 4.54:1 on a white field */
opacity: 1; /* some browsers fade placeholders by default */
}
A placeholder also disappears as soon as someone types, so it shouldn’t replace a visible label above the field.
How do I check text over images?
Contrast is measured against the background the text actually sits on. For text over a photo, that’s every part of the photo behind the letters, and the lightest area is usually the one that fails. W3C lists background images without enough contrast as a documented failure (F83).
The most reliable fixes:
- Put the text on a solid panel in front of the image.
- Add a dark overlay between the image and the text.
- Move the text beside or below the image.
A black overlay at 60% opacity turns even pure white parts of a photo into #666666, and white text on #666666 is 5.74:1:
.hero {
position: relative;
}
.hero::before {
content: "";
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.6); /* darkens every part of the photo */
}
.hero__text {
position: relative; /* sits above the overlay */
color: #ffffff;
}
Check the result on narrow screens too. When a layout reflows, text often ends up over a different part of the image.
How do I fix colors that fail?
- Keep the hue, change the lightness. You rarely need a different color. A darker version of the same blue or orange usually passes. White text on
#3B82F6is 3.67:1 and fails for normal text; on#2563EBit’s 5.16:1 and passes. Orange text#FF6600on white is 2.93:1, while#C2410Cis 5.17:1. - Fix it once, in your design tokens. Store colors as CSS custom properties so a fix applies everywhere.
- Check every state. Hover, focus, visited, error and selected states each need their own check, and so does dark mode if you have one.
:root {
--color-text: #1a1a1a;
--color-text-muted: #595959; /* 7.00:1 on white */
--color-link: #2563eb; /* 5.16:1 on white */
--color-border-input: #8a8a8a; /* 3.45:1 on white */
}
What do contrast checkers miss?
A contrast checker tells you the ratio between two colors you give it. It can’t tell you whether you picked the right two. Automated page scanners do well with plain text on solid backgrounds, but they often can’t judge:
- text over images, gradients or video
- hover, focus and other states that only appear on interaction
- text inside images
- the borders, icons and chart lines covered by 1.4.11
- information shown by color alone
They also don’t know which text is a logo or a disabled control. Use automated results as a first pass, then check the rest by eye with a checker, in both light and dark mode.
Related guides
- What is WCAG 2.2?
- Keyboard accessibility: how to test and fix, including visible focus styles
- How to write alt text
Frequently asked questions
What contrast ratio does WCAG AA require?
Success criterion 1.4.3 Contrast (Minimum), Level AA, requires at least 4.5:1 for normal text and 3:1 for large text. Success criterion 1.4.11 Non-text Contrast, also Level AA, requires 3:1 for the parts of buttons, form fields, icons and graphics that people need to see to use or understand them.
What size counts as large text in WCAG?
Text that is at least 18 point (24 CSS pixels), or at least 14 point (about 18.66 CSS pixels) and bold. W3C's Understanding page rounds the bold size to approximately 18.5px. The size is measured as delivered, not after a user zooms in.
Is a contrast ratio of 4.49:1 close enough?
No. WCAG says the computed ratio should not be rounded up, so a ratio just under 4.5:1 fails the 4.5:1 requirement. Darken or lighten one of the colors slightly until it clears the threshold.
Does my logo need to meet contrast requirements?
No. Text that is part of a logo or brand name has no contrast requirement. Brand guidelines don't exempt the rest of your text, though, so headings, buttons and body copy in brand colors still need to pass.
Do disabled buttons need enough contrast?
Text and parts of inactive user interface components, such as a disabled button, have no contrast requirement under 1.4.3 or 1.4.11. Many teams still keep disabled controls readable so people can tell what they would do.
Sources
- Understanding Success Criterion 1.4.3: Contrast (Minimum)
- Understanding Success Criterion 1.4.6: Contrast (Enhanced)
- Understanding Success Criterion 1.4.11: Non-text Contrast
- Understanding Success Criterion 1.4.1: Use of Color
- WCAG 2.2: definitions of contrast ratio, relative luminance and large scale text
- Technique G183: Using a contrast ratio of at least 3:1 to distinguish inline text links from surrounding text
- Failure F83: Using background images that do not provide sufficient contrast with foreground text