Tags: ux concept

Colour Contrast

Date: 2026-08-17


The luminance difference between foreground and background, expressed as a ratio. It’s the most commonly failed accessibility requirement, it’s entirely computable, and it affects far more people than any other single criterion.


Contrast ratio compares the relative luminance of two colours, from 1:1 (identical) to 21:1 (black on white).

The thresholds

NORMAL TEXT           4.5:1   AA
                      7:1     AAA

LARGE TEXT            3:1     AA
  ≥18pt, or ≥14pt bold  4.5:1 AAA

UI COMPONENTS AND     3:1     AA
GRAPHICS
  borders, icons,
  focus indicators,
  chart elements

DECORATIVE / DISABLED  no requirement

“Large text” is bigger than people assume — roughly 24px, or 18.66px bold, in CSS pixels. Body copy at 16px never qualifies.

[CHECK: the exact WCAG size thresholds and the current status of any newer contrast algorithm before treating a borderline value as passing.]

Who it affects

Far more people than “visually impaired” suggests:

low vision
colour vision deficiency
  → roughly 1 in 12 men
age-related contrast sensitivity loss
  → everyone, eventually
bright sunlight on a phone
cheap or dimmed screens
tired eyes

Contrast is the accessibility criterion with the widest ordinary benefit. Almost everyone reading a phone outdoors is temporarily in the affected group.

Build it into the palette

The approach that makes this a solved problem rather than a recurring audit:

                    on white
blue.400   2.6:1    ✗ fails body text
blue.500   3.9:1    ✗ fails body, ok for UI
blue.600   5.2:1    ✓
blue.700   7.4:1    ✓ AAA

Publish that table with the palette. A colour scale with no contrast figures guarantees someone uses blue.400 for body text — and the failure won’t be noticed by anyone who can read it — Colour Systems, Design Tokens.

Never colour alone

A separate requirement, and separately failed:

FAILS
  a red border as the only error
    indicator
  green "in stock" / red "out of
    stock" with no text
  a chart distinguished only by
    colour
  links coloured but not underlined

PASSES
  colour PLUS an icon
  colour PLUS text
  colour PLUS underline or shape

Test by taking a greyscale screenshot. Anything that becomes ambiguous is failing — Affordances and Signifiers.

Where it’s commonly failed

PLACEHOLDER TEXT      grey on white,
                      almost always failing
                      — another reason not
                        to use placeholders
                        as labels
                        — Form Design

DISABLED STATES       exempt from the
                      requirement, and often
                      unreadable
                      — Component States

TEXT ON IMAGES        contrast varies across
                      the image
                      → use a scrim or a
                        solid panel

BRAND COLOURS         a brand accent that
                      fails on white is a
                      real conflict, and
                      "it's our brand" is
                      not an exemption

LIGHT GREY BODY TEXT  #999 on white is
                      2.8:1 and extremely
                      common

FOCUS INDICATORS      need 3:1 against BOTH
                      the component and its
                      background
                      — Focus Management

See: Form Design · Component States · Focus Management

#999 on white is the single most common contrast failure on the web, and it’s usually a deliberate aesthetic choice to make secondary text look secondary.

Dark mode needs rechecking

Contrast doesn’t transfer between themes:

LIGHT   blue.600 on white   5.2:1  ✓
DARK    blue.600 on #16181c 2.9:1  ✗
        → needs blue.400 in dark

Every token pair must be checked in every theme. This is why the semantic layer matters — the theme swaps the value, and the check has to swap with it — Theming.

Tooling

DevTools          contrast shown in the
                  colour picker and the
                  accessibility panel
automated scans   catch text contrast
                  reliably
                  ← one of the things
                    automation IS good at
design tools      contrast plugins
CI                enforce it on the token
                  set, not per component

Contrast is one of the few accessibility criteria automation catches well. There is no good reason to ship a failure — WCAG.