Talking About TestingATT</>
WCAG 2.2 Level AA

Score 100% on the quiz to continue

Lesson
Free Preview

Contrast

1.4.3 and 1.4.11: 4.5:1 for text, 3:1 for large text, and 3:1 for field borders, states, focus indicators, icons, and charts.

Welcome to the contrast lesson. This one is free to read without an account, so it is also the best way to see how every lesson in the course is built: one or more criteria from a WCAG guideline, and inside each, the same five parts, ending with how to test it.

Contrast is the accessibility criterion everyone has heard of, and the most common failure on the web: year after year, large automated studies of popular home pages find low-contrast text on the vast majority of them. It is also Level AA, not Level A, which surprises almost everyone the first time.

This lesson covers both contrast criteria in guideline 1.4 Distinguishable: one for text, and one for everything else you need to see.

1.4.3 Contrast (Minimum)

What it requires

Text, and images of text, have a contrast ratio of at least 4.5:1 against their background. Large text needs at least 3:1.

The contrast ratio is a number from 1:1 (the same color twice) to 21:1 (black on white), calculated from the relative luminance of the two colors. You never compute it by hand: a contrast checker does it for you.

"Large text" has a precise meaning: at least 18 point (about 24 CSS pixels), or at least 14 point bold (about 18.66 CSS pixels bold).

📖 Understanding 1.4.3 Contrast (Minimum)

Who it helps

  • People with low vision, for whom pale text blurs into the background
  • People with color vision deficiencies, who may see less difference between two colors than the designer did
  • Older people, as contrast sensitivity declines with age
  • Everyone reading a phone outdoors, in bright sunlight, or on a cheap or dimmed screen

Before 🚫 / After ✅

Body text. Grey text on white is the classic failure.

<!-- Before 🚫: #999999 on white is 2.85:1 -->
<p style="color: #999999; background: #ffffff;">
  Free returns within 30 days.
</p>

<!-- After ✅: #595959 on white is 7.0:1 -->
<p style="color: #595959; background: #ffffff;">
  Free returns within 30 days.
</p>

The threshold is not rounded. #777777 on white is 4.48:1, and it fails: 4.48 is less than 4.5, however close it looks. #767676, one step darker, is 4.54:1 and passes. When a checker shows "4.5" with one decimal, look at the second one.

Placeholder text. Placeholder text is text, so if it carries information ("e.g. name@example.com"), it needs 4.5:1. Many default placeholder greys do not reach it.

<!-- Before 🚫: a pale placeholder is the only hint of the expected format -->
<style> input::placeholder { color: #aaaaaa; } </style>
<label for="email">Email</label>
<input id="email" placeholder="name@example.com">

<!-- After ✅: the hint is real text with enough contrast, and stays visible -->
<label for="email">Email</label>
<p id="email-hint" style="color: #595959;">For example, name@example.com</p>
<input id="email" aria-describedby="email-hint">

Text over an image. Measure the contrast against the lightest part of the image behind light text (or the darkest behind dark text), not an average. A semi-transparent dark overlay behind the text, or a solid background on the text block, is the usual fix.

Exceptions

  • Large text needs only 3:1. Check the size and weight first, then pick the threshold
  • Incidental text: text in an inactive (disabled) control, text that is pure decoration, text that is not visible to anyone, and text that is part of a picture with significant other visual content (a street sign in a photo) have no contrast requirement
  • Logotypes: text that is part of a logo or a brand name has no contrast requirement
👨🏻‍🏫 "Disabled" is the exception teams lean on most, and it only covers controls that genuinely cannot be used right now. A button styled pale grey to look "secondary", but fully clickable, is not disabled. It needs 4.5:1 like any other text.

How to test it

  1. Run your scanner first. This is the criterion axe-core is best at: it measures the contrast of every text element in seconds. Fix what it reports
  2. Then look for what it cannot measure, and check each with a contrast checker or an eyedropper:

- text over images, gradients, and videos - text on elements layered over other elements (sticky headers, cards, modals) - text that only appears in a state: hover, focus, selected, error, placeholder, and tooltip text - images of text: banners, buttons, and infographics with text baked into the picture

  1. For each, decide whether the text is large (24 CSS pixels, or 18.66 bold) to pick 4.5:1 or 3:1
  2. Check whether an exception really applies: is that control truly disabled? Is that text truly part of a logo?

Automated: partly. axe-core's color-contrast rule checks most text against a solid background, and marks text over images, gradients, and overlapping elements as "needs review", which means a person has to check it. It does not check images of text, and only checks states (hover, focus, error) if your test puts the page into that state before scanning.

1.4.11 Non-text Contrast

What it requires

Two kinds of things that are not text need a contrast ratio of at least 3:1 against the colors next to them:

  1. User interface components: the visual information required to identify a component and its states. The border of a text field when the border is what shows you where to type, a checkbox's box and its check mark, a toggle's on and off positions, the focus indicator
  2. Graphical objects: the parts of a graphic required to understand the content. The lines and bars of a chart, the segments of a pie chart, an icon that carries meaning on its own

📖 Understanding 1.4.11 Non-text Contrast

Who it helps

  • People with low vision, who cannot find a text field whose pale border disappears into the page, or tell a checked checkbox from an unchecked one
  • People with color vision deficiencies, reading a chart whose lines are close in brightness
  • Everyone on a bad screen, in sunlight, or with the brightness turned down

Before 🚫 / After ✅

A text field. When the border is the only thing that shows where the field is, the border needs 3:1.

<!-- Before 🚫: #d1d5db on white is 1.47:1, so the field nearly disappears -->
<style> input { border: 1px solid #d1d5db; background: #ffffff; } </style>
<label for="city">City</label>
<input id="city">

<!-- After ✅: #8a8a8a on white is 3.45:1 -->
<style> input { border: 1px solid #8a8a8a; background: #ffffff; } </style>
<label for="city">City</label>
<input id="city">

A state. A toggle that shows "on" with a light green track, #4caf50, against a white page (2.78:1), and "off" with a light grey one. Darken the "on" color (#2e7d32 is 5.13:1 against white) and add a second cue, such as the knob's position or an "On" label, so the state does not rely on one hue (that second cue is also what 1.4.1 Use of Color, at Level A, asks for).

A chart. A line chart whose four lines are pale pastels on white. Each line that carries data needs 3:1 against the background. Adjacent pie segments need 3:1 against each other, or a visible border between them, unless every segment is also labelled with its value.

Exceptions

  • Inactive components: a disabled control has no requirement, just like disabled text in 1.4.3
  • Appearance set by the browser: a native checkbox or a default focus ring, unmodified by the author, is the browser's responsibility. Once the page restyles it, the page is responsible
  • Essential presentation: when the colors are the information, as in a heat map, a photograph, a flag, or a screenshot of someone else's interface
  • Not everything needs 3:1. A button identified by its text does not need its background to contrast with the page, because the text (checked under 1.4.3) already identifies it. And a graphic that also shows its data as text, such as a chart with values labelled on every bar, does not depend on the bars' contrast
👨🏻‍🏫 Focus indicators are the case to remember. A custom focus ring in a pale color that barely differs from the unfocused state fails here, under 1.4.11, even though the focus is technically "visible". The lesson on focus comes back to it with 2.4.7.

How to test it

  1. List what you need to see to use the page: field boundaries, checkboxes, radio buttons, toggles, sliders, focus indicators, icons without text, and the meaningful parts of charts and diagrams
  2. For each, find the colors that make it identifiable, and the colors next to them (usually the background), and measure the ratio with an eyedropper
  3. Check every state too: checked and unchecked, on and off, selected and not, focused and not
  4. Decide whether an exception applies: is it disabled? Unmodified by the page? Labelled with text anyway?

Automated: no. axe-core has no rule for non-text contrast. Borders, icons, states, focus indicators, and chart lines are all checked by eye and with an eyedropper.

Try it yourself 🔍

  1. Run an automated scanner on a site you use often and note how many contrast issues it reports. Then find two that it marks for review, or misses, and measure them yourself
  2. Find a form with "minimal" styling and check the contrast of its field borders, checkboxes, and placeholders against the page
  3. Find a chart on a news or dashboard site. Could you tell each line or segment apart if it were all slightly darker or lighter? Measure the palest one

Show the world what you learned 🌎

To show your professional network what you have learned in this lesson, post the following on LinkedIn.

I am taking the "WCAG 2.2 Level AA" course by @Bruno Pulis at the @Talking About Testing School, where I learned that contrast is Level AA, not Level A: text needs 4.5:1, or 3:1 when large, and 4.48 fails (1.4.3 Contrast (Minimum)), while field borders, checkboxes, focus indicators, and chart lines need 3:1 (1.4.11 Non-text Contrast). A scanner checks most text, and none of the rest. #TalkingAboutTesting #TATSchool #WCAG22LevelAA #Accessibility #ColorContrast

👨🏻‍🏫 Remember to tag me in your post. Here is my LinkedIn profile.

Quiz

Question 1 of 2
Score: 0

Body text (16 pixels, normal weight) has a contrast ratio of 4.48:1 against its background. What is the verdict under 1.4.3 Contrast (Minimum)?

Score 100% on the quiz to continue