Check WCAG Color Contrast Online: AA, AAA and Large Text

Check WCAG Color Contrast Online: AA, AAA and Large Text

Insufficient text-to-background contrast is the most common accessibility failure on the web. Check AA/AAA compliance by pasting two colors, no plugin or extension required.

13.09.2026
11 min read
Share this article:
accessibilitywcagcolor-contrastCSSTutorial

Contrast, the most common accessibility failure on the web

Every year, the WebAIM Million audit ranks insufficient text contrast as the top WCAG failure detected, ahead of missing alt text or unlabeled links. The audit analyzes the most-visited home pages on the web. Contrast is also one of the few accessibility criteria you can verify without a screen reader or a full audit. The FastMinify contrast checker computes the WCAG 2.2 ratio between two CSS colors (HEX, RGB, HSL, OKLCH, color() or named colors). As you type, it shows AA and AAA verdicts for normal text, large text and non-text elements. Nothing is sent to a server. It goes beyond a single color pair: a matrix mode lets you cross an entire foreground palette against an entire background palette in one pass. The rest of the tools sit on the Color & CSS hub.

Live WCAG 2.2 verdicts: AA, AAA and non-text 3:1 (SC 1.4.11) for every color pair
Matrix mode with up to 16 colors per axis, to audit a whole design system palette in one pass
Opacity slider to check semi-transparent text composited against its real background
Experimental APCA overlay (WCAG 3 candidate) alongside the classic WCAG 2.2 ratio
Shareable URL: send the exact check to a designer or paste it into a PR
100% in the browser, no brand color ever leaves your tab

The contrast mistakes that come up again and again

The "elegant" light gray text on white

A #999999 gray on white gives a ratio of roughly 2.85:1, well below the AA threshold of 4.5:1. Yet it is one of the most common design choices for secondary text, placeholders and captions.

Form placeholder text in a gray that's too light (often under 3:1)
Captions and metadata ("2h ago", "250 views") in pale gray on a light background
Copying a "neutral" gray from a Figma mockup without checking the actual ratio
Confusing "it reads fine on my screen" with a compliant ratio (brightness, calibration, eye fatigue all vary)
Low-vision users, people in bright environments (outdoors, poorly calibrated screens) and colorblind users lose part of the content. An axe or Lighthouse audit also fails in CI when contrast is checked automatically.
A brand-colored button that quietly fails

"Soft" brand colors (pastel blue, mint green, light orange) are often chosen for visual identity without ever being tested with white text on top.

Light blue primary button + white text: the ratio is sometimes under 3:1
A "disabled" state that visually looks like a poorly contrasted active state
Monochrome icons on a colored background without checking non-text contrast (3:1)
Testing only the default button state, never hover/focus/disabled
An unreadable or barely visible call-to-action drops click-through rates. Beyond accessibility, it is also a conversion problem.
Text placed on an image with no scrim

A white headline works over the dark part of a hero photo's sky, but becomes unreadable over the bright part of a cloud. Contrast varies depending on where the text sits on the image.

No dark gradient or overlay (scrim) under the text
Text tested only on the desktop crop of the image, never on the mobile crop
A light drop shadow used as the only guarantee of readability
A changing background image (carousel, user upload) with no guaranteed contrast
Add a semi-opaque gradient (black at 40–60%) between the image and the text. Then check contrast against the composited gradient color, not against the raw image.
Visible focus removed to "clean things up"

outline: none with no replacement breaks keyboard navigation. Non-text contrast (SC 1.4.11) also covers focus indicators.

`outline: none` with no alternative focus ring
A custom focus ring that's too pale against the background (often under 3:1)
Visible focus tested only in light mode, forgotten in dark mode
No contrast check on form field borders
Keyboard users and switch-access users completely lose their visual bearing on the page.

Which ratio to target for AA, AAA and large text

Normal text, AA (4.5:1) or AAA (7:1)

WCAG 1.4.3 (Contrast Minimum) requires a ratio of at least 4.5:1 for normal text at level AA. The stricter AAA level (criterion 1.4.6) raises the bar to 7:1. Nearly every legal accessibility requirement targets AA (Section 508/ADA in the US, EN 301 549 in Europe, RGAA in France). AAA remains recommended but is rarely mandated site-wide.

AA (4.5:1): the legal floor in most accessibility regulations
AAA (7:1): recommended for critical content such as payment forms or medical and legal content
A ratio of 21:1 (pure black on pure white) is the theoretical maximum, so there is no point going higher
A ratio that looks fine at a glance (for example 4.2:1) can fail AA by a hair, so always check the exact number, not the visual impression
Large text, where the threshold drops to 3:1 (AA) or 4.5:1 (AAA)

WCAG defines “large text” as text of at least 24px, which is 18pt. Text of at least 18.67px, which is 14pt, also counts when it is bold (weight 700 or more). Below those thresholds, text counts as normal even if it looks visually imposing. FastMinify works out which threshold applies from the size and weight you enter.

≥ 24px, any weight: large text → AA = 3:1, AAA = 4.5:1
≥ 18.67px AND weight ≥ 700 (bold): large text → same reduced thresholds
17px bold does NOT count as large text, a common trap
A 40px H1 benefits from the reduced threshold; a 12px bold badge never does
Non-text contrast (SC 1.4.11), 3:1 for the interface

Since WCAG 2.1, criterion 1.4.11 (Non-text Contrast) requires a ratio of at least 3:1 between UI components and their adjacent color. That covers form field borders, checkboxes, meaningful icons and focus indicators.

Unfocused form field border: 3:1 minimum against the page background
Focus ring (outline/box-shadow): 3:1 minimum against both the background AND the element
Purely decorative icons (carrying no information) are exempt from this criterion
The FastMinify checker shows this verdict separately, so a pair can pass non-text while failing normal-text contrast

How the contrast ratio is actually calculated

The WCAG formula measures relative luminance, ignoring hue

The WCAG 2.x ratio compares the relative luminance of the two colors. That is a value from 0 to 1 derived from linearized RGB channels, weighted 0.2126 for red, 0.7152 for green and 0.0722 for blue. The human eye perceives green far more intensely than blue. The final ratio is (L1 + 0.05) / (L2 + 0.05), where L1 is the lighter color's luminance. That is why two colors that look “clearly different” can end up with a close ratio. Two hues that look similar can have very different luminances.

Before

color: #999999; background: #ffffff; /* Ratio ≈ 2.85:1 → fails AA (normal text) */

After

color: #595959; background: #ffffff; /* Ratio ≈ 7.0:1 → passes AAA (normal text) */
The result ranges from 1:1 for identical colors to 21:1 for pure black on pure white
Green carries more weight than blue in the formula, so a bright blue on white often fails sooner than a green of similar perceived brightness
The formula ignores perceived hue, and only luminance matters for the classic WCAG ratio
FastMinify accepts HEX, RGB, HSL, OKLCH and color() as input and converts them to sRGB before computing (via colorjs.io)
APCA, the WCAG 3 candidate (experimental preview)

The WCAG 2.x ratio has a known limitation: it treats “black on white” and “white on black” symmetrically, which does not always match real perception. APCA (Advanced Perceptual Contrast Algorithm), a candidate for WCAG 3, accounts for polarity, meaning light text on a dark background versus the reverse. It also accounts for font size, which gives a finer-grained judgment. FastMinify offers an optional APCA overlay alongside the official WCAG 2.2 ratio, not as a replacement, since WCAG 3 is not a published standard yet.

APCA returns an "Lc" (Lightness Contrast) score rather than a classic ratio
Polarity (normal or reversed) affects the score, so the same color pair has a different Lc depending on which color is foreground and which is background
As of today, only the WCAG 2.2 ratio at AA or AAA counts for legal compliance under Section 508, ADA, EN 301 549 and RGAA
Useful for anticipating a future move to WCAG 3, not for a current compliance audit

From a color pair to a full palette with the contrast checker

Check a color pair

Open the contrast checker and paste your foreground and background colors in any CSS format (HEX, RGB, HSL, OKLCH, named). The ratio and the AA, AAA and non-text results update live. Adjust text size and weight to see the “large text” threshold apply automatically.

1

First, paste both colors

Foreground and background, in any valid CSS format. No manual conversion needed.

2

Then, set text size and weight

16px/400 by default (normal text). Switch to 24px or 18.67px+bold to test a heading, and the “large text” threshold (3:1/4.5:1) applies automatically.

3

Finally, read the verdict

Exact ratio such as 4.87:1, an AA, AAA, AA large or fail level for text, and a separate verdict for non-text contrast (3:1, SC 1.4.11).

Auditing a button and its disabled state

A primary button usually has three color variants (normal, hover, disabled) that often go untested individually.

Test the button text on the “normal” background and aim for at least AA (4.5:1)
Test the same pair on the “hover” state, since the color often changes and so does the ratio
Test the “disabled” state separately. A low ratio is acceptable there if the state is genuinely non-interactive and announced as such (aria-disabled)
Check the button border (if visible) against the page background, which is non-text contrast with a 3:1 threshold
Matrix mode, auditing an entire palette at once

Instead of testing a design system's combinations one by one, paste your text colors in Row colors and your background colors in Column colors. Use one color per line, up to 16 per axis. The result is a grid with a verdict for every intersection, which you can filter by level (AAA, AA, Large AA or Failures).

Useful for validating every color token in a design system in a single pass
Filter by level: quickly isolate only the combinations that fail
Catches "borderline" pairs (e.g. 4.4:1, just under the AA threshold) that a manual pair-by-pair check would easily miss
Works with the same color formats as pair mode (you can mix HEX/RGB/HSL within a single list)
Share a check with your team

Every check (colors, text size, matrix or pair mode, APCA options) is encoded into the URL. Copy the link from the address bar, or use the Share these settings button. Then paste it into a pull request, a ticket or a message to your designer. The page reopens in exactly the same state.

No data stored server-side: the entire state lives in URL parameters
Handy for documenting a contrast failure found during review
The link stays valid indefinitely as long as the tool is online

Making contrast a CI gate rather than a design back-and-forth

Automate detection with axe-core or Lighthouse CI

A manual checker suits palette design. To prevent regressions, contrast should also be verified automatically on every pull request. axe-core and Lighthouse CI catch most contrast failures on static text. They struggle more with text over images or gradients.

Basic example

// axe-core with Playwright — fails the test on insufficient contrast import { test, expect } from '@playwright/test' import AxeBuilder from '@axe-core/playwright' test('no contrast regression', async ({ page }) => { await page.goto('/') const results = await new AxeBuilder({ page }) .withTags(['wcag2aa']) .analyze() const contrastIssues = results.violations.filter( (v) => v.id === 'color-contrast' ) expect(contrastIssues).toEqual([]) })
FastMinify contrast checker

Fast manual checks, no install, no data sent anywhere. The matrix mode, unique among these options, lets you audit a whole design system in a single pass, and the shareable URL makes design and dev collaboration easy. Trade-off: it is a manual check that does not replace an automated CI audit. It also does not detect contrast on an image or a complex gradient.

Browser DevTools (Chrome/Firefox)

The built-in color picker shows the contrast ratio directly on the selected element on the live page, with computed styles, so no external tool is needed. Trade-off: one element at a time, which gets tedious across a full palette, with no matrix mode or link sharing.

axe-core / Lighthouse CI

An automated audit built into the CI pipeline systematically catches contrast regressions on every pull request, and covers accessibility beyond just contrast. Trade-off: it doesn't replace the upfront palette design phase, and can produce false negatives on text overlaid on an image.

Conclusion

Color contrast remains the most common accessibility failure on the web, and one of the easiest to fix once detected. AA (4.5:1) for normal text and 3:1 for large text and non-text elements are the two thresholds worth remembering before you ship a palette. The FastMinify contrast checker gives you the verdict as you type, in pair mode or in matrix mode for an entire design system. It never sends your brand colors to a server. An axe-core audit in CI prevents regressions, and the rest of the Color & CSS hub helps you build a consistent palette end to end.

Target AA (4.5:1) for normal text, and 3:1 for large text and non-text elements such as borders, focus and icons
Test every state of an interactive component (normal, hover, focus, disabled), including the default one
Use matrix mode to validate an entire design system rather than pair by pair
Add axe-core or Lighthouse CI to your pipeline to prevent contrast regressions after shipping
The WCAG 2.2 ratio is what counts legally today, so treat APCA as a preview of the future, not a compliance reference
Share this article
Share this article: