Color Contrast and Accessibility: WCAG Basics

Meet WCAG AA/AAA contrast ratios for text, fix brand-color failures, and convert hex/RGB/HSL with practical design checks.

Published 2025-03-01. From the Vastorae team.

Why contrast is an accessibility essential

Text that barely differs from its background strains everyone in bright sunlight, on dim trains, or on low-quality panels—and it can make content unusable for people with low vision or certain color-vision deficiencies. Web Content Accessibility Guidelines (WCAG) define minimum contrast ratios so foreground and background remain distinguishable.

Contrast ratio compares relative luminance of the lighter color to the darker, expressed like 4.5:1 or 7:1. Higher ratios generally mean easier reading. Pure black on pure white sits at 21:1; light gray on white can fall near 1.5:1 and fail for body text.

Color alone should not carry meaning. Pair error red with icons or text labels; mark required fields with more than a colored outline. Contrast fixes readability; redundant cues fix color-dependent comprehension.

WCAG AA and AAA thresholds in practice

For WCAG 2.x contrast of normal-sized text, Level AA commonly requires at least 4.5:1; Level AAA requires 7:1. Large text (typically 18 pt regular or 14 pt bold and above, with CSS equivalents) has lower thresholds—often 3:1 for AA. UI components and graphical objects also have contrast expectations in WCAG 2.1/2.2 non-text contrast criteria.

Example: `#6B7280` gray text on `#FFFFFF` may hover near the AA borderline depending on exact luminance—always measure rather than eyeball. Darkening to `#4B5563` or pairing medium gray with an off-white cream background can push a failing pair over 4.5:1. AAA is stricter; marketing sites that insist on pale brand pastels for body copy often need a separate “accessible text” shade.

AA is the usual legal and procurement target in many jurisdictions’ references to WCAG 2.x Level AA. AAA is a higher bar—excellent for long-form reading modes—but can constrain vivid brand palettes. Aim for AA everywhere text must be read; push AAA on core reading surfaces where feasible.

Measuring pairs instead of guessing

Designers often approve colors on calibrated cinema displays that flatter subtle contrast. Users read on phones with automatic brightness, cheap TN panels, or outdoor glare. A contrast checker that implements the WCAG relative-luminance formula beats subjective judgment.

Workflow: sample the exact foreground hex and background hex from production CSS (not from a compressed screenshot). Paste both into a contrast checker, read the ratio and AA/AAA pass/fail for normal and large text, then adjust one color at a time. Changing both simultaneously makes it harder to learn which lever fixed the failure.

Example adjustment path: brand blue `#3B82F6` on white may pass for large headings but fail for 16px body text. Options include a darker blue for text (`#1D4ED8`), white text on a solid blue button (check the inverse pair), or a heavier font weight categorized as large text—font size and weight interact with which threshold applies.

Brand colors that fail—and how to keep the brand

When a beloved brand hex fails on white, you rarely must abandon the brand. Create a functional token set: `brand.primary` for decorative fills and `brand.primaryText` for readable type. Many design systems expose `text`, `textMuted`, and `textOnBrand` separately from raw swatches.

Worked idea: logo orange `#F97316` might be fine as a 4px accent bar but fail as small label text on `#FFF7ED`. Use the orange for icons sized large enough to meet non-text contrast against adjacent colors, and use a deeper burnt tone for captions. Document the rule so marketing does not reintroduce pale orange body copy in the next campaign.

Disabled controls are a special case: they can appear weaker, but essential information should not rely on disabled styling alone. Placeholder text contrast is a frequent failure—lighten placeholders carefully and never use placeholder copy as the only visible label.

Colour formats: hex, RGB, HSL, and why converters help

Hex (`#RRGGBB` or `#RGB`) dominates CSS brand handoffs. RGB makes channel math explicit. HSL (hue, saturation, lightness) is convenient when you need a darker text sibling of the same hue: reduce lightness until contrast passes, keeping hue steady so the color still “feels” on-brand.

Example: start from `hsl(221 83% 53%)` (a vivid blue). Dropping lightness toward `hsl(221 83% 35%)` often yields a text-capable shade while remaining recognizably related. Converters that show hex, RGB, and HSL side by side speed this dance between design tools and code reviews.

Alpha transparency complicates contrast: semi-transparent text over a photograph has an effective color that depends on what sits behind it. Flatten against the real background (or test multiple backdrop regions) before claiming a pass. Overlays on hero images are classic failure zones.

Beyond ratio: focus states, charts, and dark themes

Keyboard focus rings need visible contrast against both the component and the surrounding page. A 1px light-gray outline on a pale background fails users who do not use a mouse. Prefer a dual-ring or high-contrast outline token tested like text pairs.

Data visualizations should not encode categories by color alone; use patterns, labels, or shapes. Adjacent series in a line chart need sufficient contrast against the plot background and each other when lines thin out. Tooltip text must meet contrast on its floating surface.

Dark themes invert the problem space: desaturated dark grays on black can fail just as pale gray on white does. Test each theme’s tokens independently. Copying light-theme hexes into a dark palette without re-checking ratios reintroduces AA failures overnight.

A lightweight QA checklist for shipping UI

Before release, sample primary body text, muted helper text, link defaults and visited states, button labels on filled and outline variants, error messages, and table headers. Check mobile CSS if font sizes change breakpoints—large-text thresholds may apply on desktop but not on smaller mobile type.

Automate where possible with linting or CI contrast audits, but still spot-check branded marketing modules that bypass the design system. One hero banner with translucent text can undo a clean component library.

  • Body and muted text on default surfaces
  • Primary/secondary button labels (each variant)
  • Links and focus indicators
  • Form labels vs placeholders vs errors
  • Text over images or gradients (flatten and retest)

Tools to verify and convert colors

Use the Contrast Checker to evaluate foreground/background pairs against AA and AAA thresholds before you ship. Use the Color Converter to move among hex, RGB, HSL, and related formats when design and engineering disagree on notation. Both run in the browser for quick iteration.

Pair these utilities with real-device previews and, when stakes are high, user testing with people who have low vision. Meeting a ratio is necessary for WCAG contrast success criteria—it is not the entire accessibility story, but it removes a large, avoidable class of failures.

FAQ

Do I need AAA contrast everywhere?
Usually no. Many organizations target WCAG 2.x Level AA for compliance. AAA contrast (7:1 for normal text) is stricter and excellent for long reading, but it can limit bright brand accents. Prioritize AA on all readable text and interactive labels; apply AAA on core articles or reader modes when the design allows.
What if my brand colour fails contrast checks?
Keep the brand color for large decorative areas, logos at sufficient size, or backgrounds with white/dark text that passes. Introduce a darker or lighter companion token for small text. Adjust the other half of the pair (background) if the brand hue must stay exact. Reserve failing pairs for non-essential ornamentation only.
Does bold text change the requirements?
Yes, because WCAG’s “large text” definition includes bold text at a somewhat smaller size than regular-weight large text. A bold 14 pt (or CSS equivalent) style may qualify as large text with a 3:1 AA threshold, whereas the same size at regular weight may still need 4.5:1. Measure with your actual rendered size, not the design file’s nominal label alone.
How do I test text on a photo background?
Sample multiple regions under the letters—bright sky vs dark jacket—because the effective contrast changes across the image. Scrim layers (semi-opaque panels behind text) create a stable background you can test as a flat color. If the photo still shows through unevenly, strengthen the scrim until body text passes AA.
Are hex short codes like #abc okay to test?
Yes if your tool expands them correctly (`#abc` → `#aabbcc`). Be careful with eight-digit hex that includes alpha; contrast should consider the composited result against what is behind the transparent color. When sharing tokens, prefer six-digit hex for opaque UI text to avoid ambiguity.
Does contrast fix color blindness by itself?
Adequate contrast helps many low-vision scenarios but does not replace non-color cues. Deuteranomaly and similar conditions especially struggle when red/green coding is the only signal—even if both colors are vivid. Use labels, icons, patterns, and text status in addition to meeting ratio thresholds.

Related tools

Browse Color Tools