Colour, Contrast and Motion

Contrast ratios that meet the guidelines, never relying on colour alone, and honouring the reduced motion preference. Mostly CSS, entirely part of the job.

Contrast

Low contrast text is the most commonly detected accessibility failure on the web, found on a large majority of home pages surveyed each year. It is also among the easiest to fix.

The requirements

ContentLevel AALevel AAA
Body text4.5 to 17 to 1
Large text (24px, or 19px bold)3 to 14.5 to 1
Interface components and graphics3 to 1-
Focus indicators3 to 1-
Disabled controlsNo requirement-

The ratio is calculated from relative luminance, so it is not the same as how different two colours look. Two colours can feel very distinct and still fail.

/* fails: about 2.8 to 1 */
.muted { color: #a0aec0; background: #ffffff; }

/* passes AA: about 4.6 to 1 */
.muted { color: #6b7280; background: #ffffff; }

/* comfortably passes: about 8.6 to 1 */
.body  { color: #334155; background: #ffffff; }

Check with the DevTools colour picker, which shows the ratio and the pass or fail marks directly as you adjust a colour.

Where it usually fails

  • Grey placeholder and helper text.
  • Text over a photograph, where the contrast varies across the image.
  • Brand colours used for links or buttons.
  • Light grey borders on form fields.
  • Dark mode themes converted by inverting colours.
/* text over an image: guarantee the contrast with a scrim */
.hero {
  position: relative;
  color: #ffffff;
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(15,23,42,0.75), rgba(15,23,42,0.25));
}
.hero > * { position: relative; }

Never rely on colour alone

Around one in twelve men and one in two hundred women have some form of colour vision deficiency. Anything communicated only by colour is invisible to them - and to anyone using a monochrome display or printing the page.

<!-- colour only -->
<span class="status-red">Rejected</span>
<span class="status-green">Approved</span>

<!-- colour plus text plus a shape -->
<span class="status status-rejected">
  <svg aria-hidden="true"><use href="#icon-cross"/></svg> Rejected
</span>
<span class="status status-approved">
  <svg aria-hidden="true"><use href="#icon-tick"/></svg> Approved
</span>

The same applies to:

  • Links in body text. Underline them, or add another non colour difference.
  • Form errors. A red border is not enough; add text and an icon.
  • Required fields. Mark them with text or an asterisk, not colour.
  • Charts. Use patterns, direct labels or different shapes as well as colour.

Motion

Animation causes real problems for people with vestibular disorders: parallax scrolling, large moving elements and zooming transitions can trigger dizziness and nausea. Operating systems carry a preference for this, and CSS can read it.

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

Those five lines are the single highest value accessibility snippet available. Include them in every project.

A more considered approach reduces rather than removes - a fade instead of a slide, for instance:

.panel { transition: transform 250ms, opacity 250ms; }

@media (prefers-reduced-motion: reduce) {
  .panel { transition: opacity 150ms; transform: none; }
}

In JavaScript:

const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (!reduce) startCarouselAutoplay();

Anything that moves for more than five seconds needs a pause control

Auto playing carousels, scrolling tickers and looping background video all fall under this. A visible pause button is required, not optional.

Other preference queries

@media (prefers-color-scheme: dark) {
  :root { --bg: #0f172a; --text: #e2e8f0; }
}

@media (prefers-contrast: more) {
  :root { --border: #000000; --text: #000000; }
}

@media (forced-colors: active) {
  /* Windows high contrast mode: the system replaces your palette */
  .card { border: 1px solid; }
}

In forced colours mode the operating system overrides colours entirely. Backgrounds set as images disappear, so anything that conveys meaning through a background needs a border or text as well.

Text sizing and zoom

  • Pages must remain usable at 200 percent zoom. Fixed pixel heights and overflow: hidden are the usual causes of failure.
  • Text must be resizable to 200 percent without loss of content.
  • Setting font sizes in px overrides the browser default a reader has chosen. Use rem.
  • Comfortable line length is around sixty to seventy five characters, which max-width: 65ch expresses directly.
  • Line height of at least 1.5 for body text.
body {
  font-size: 1rem;
  line-height: 1.6;
}
p, li { max-width: 65ch; }

Important rules

  • 4.5 to 1 for body text, 3 to 1 for large text and interface components.
  • Never convey information by colour alone.
  • Honour prefers-reduced-motion.
  • Anything moving for over five seconds needs a pause control.
  • Pages must work at 200 percent zoom.
  • Use rem for text so browser settings are respected.

Common mistakes

  • Light grey placeholder text well below the required ratio.
  • Text over an image with no scrim.
  • Removing link underlines in body text.
  • Status shown only by colour.
  • Parallax and large transitions with no reduced motion query.
  • Auto playing carousels with no pause.
  • Font sizes in pixels.
  • Fixed heights that clip content at high zoom.

Best practices

  • Check contrast while choosing colours, not afterwards.
  • Build a palette that passes and use it as tokens.
  • Always pair colour with text or a shape.
  • Add the reduced motion block to every project stylesheet.
  • Use rem for type and ch for line length.
  • Test at 200 percent zoom and in high contrast mode.

Practice

  1. Check every text colour in one of your stylesheets against its background and record the ratios.
  2. Find a status indicator that uses colour alone and add a second signal.
  3. Add the reduced motion block and confirm animations stop when the system setting is on.
  4. Zoom a page to 200 percent and list everything that breaks.

Useful resources

Hand picked references for this topic
Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All HTML notes →

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.