Theme and contrast lab
Edit a handful of design tokens and get light, dark and high-contrast themes with live WCAG contrast ratios, a colour-blind check and CSS you can export.
Runs in your browser. Nothing is uploaded.
Tool
Light tokens
OKLCH sliders
OKLCH sliders
OKLCH sliders
OKLCH sliders
OKLCH sliders
OKLCH sliders
OKLCH sliders
OKLCH sliders
OKLCH sliders
Preview
A sample card, button, link, input, alerts and chart in the selected theme. It is for visual review only and is not interactive. The colour-vision simulation affects this preview only.
Order summary
Two items, delivered in three days.
View delivery details
Error: the card number is not valid.
Success: your address was saved.
Contrast matrix: Light
Every pair meets its target. Ratios are truncated, never rounded up. This reports ratios and thresholds; it does not say a theme is compliant.
| Pair | Ratio | AA text (4.5:1) | AA large text (3:1) | UI components (3:1) | AAA text (7:1) | APCA (advisory) | Fix |
|---|---|---|---|---|---|---|---|
| text on bg#18181b on #f8f8f5; target 4.5:1 | 16.65:1 | Pass | Pass | Pass | Pass | Lc 100 | Meets target |
| text on surface#18181b on #ffffff; target 4.5:1 | 17.71:1 | Pass | Pass | Pass | Pass | Lc 105 | Meets target |
| text-muted on bg#52525b on #f8f8f5; target 4.5:1 | 7.26:1 | Pass | Pass | Pass | Pass | Lc 83 | Meets target |
| text-muted on surface#52525b on #ffffff; target 4.5:1 | 7.72:1 | Pass | Pass | Pass | Pass | Lc 87 | Meets target |
| accent on bg#1d4ed8 on #f8f8f5; target 4.5:1 | 6.29:1 | Pass | Pass | Pass | Fail | Lc 78 | Meets target |
| danger on bg#b42318 on #f8f8f5; target 4.5:1 | 6.17:1 | Pass | Pass | Pass | Fail | Lc 77 | Meets target |
| success on bg#166534 on #f8f8f5; target 4.5:1 | 6.70:1 | Pass | Pass | Pass | Fail | Lc 80 | Meets target |
| border on bg#71717a on #f8f8f5; target 3:1 | 4.54:1 | Pass | Pass | Pass | Fail | Lc 69 | Meets target |
| focus on bg#1d4ed8 on #f8f8f5; target 3:1 | 6.29:1 | Pass | Pass | Pass | Fail | Lc 78 | Meets target |
Colour-blind check
Do the state colours stay apart under each simulation? A pair counts as distinct when its OKLab distance is at least 0.1. That threshold is this tool's own heuristic, not a standard. State must also never rely on colour alone: use icons and text as well.
| Pair | Normal vision | Protanopia | Deuteranopia | Tritanopia | Achromatopsia |
|---|---|---|---|---|---|
| danger and success | Distinct (0.26) | Hard to tell (0.07) | Hard to tell (0.09) | Distinct (0.30) | Hard to tell (0.02) |
| danger and accent | Distinct (0.35) | Distinct (0.30) | Distinct (0.31) | Distinct (0.30) | Hard to tell (0.00) |
| success and accent | Distinct (0.28) | Distinct (0.27) | Distinct (0.26) | Hard to tell (0.09) | Hard to tell (0.01) |
Export
:root {
--color-bg: #f8f8f5;
--color-surface: #ffffff;
--color-text: #18181b;
--color-text-muted: #52525b;
--color-accent: #1d4ed8;
--color-border: #71717a;
--color-focus: #1d4ed8;
--color-danger: #b42318;
--color-success: #166534;
}
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #121315;
--color-surface: #1b1c1f;
--color-text: #ececee;
--color-text-muted: #a1a1aa;
--color-accent: #8ab4ff;
--color-border: #8b8b93;
--color-focus: #8ab4ff;
--color-danger: #ff8f85;
--color-success: #6fd48a;
}
}
@media (prefers-contrast: more) {
:root {
--color-bg: #ffffff;
--color-surface: #ffffff;
--color-text: #000000;
--color-text-muted: #52525b;
--color-accent: #1a4ad4;
--color-border: #71717a;
--color-focus: #1d4ed8;
--color-danger: #af1c12;
--color-success: #166534;
}
}The high-contrast values are derived from the Light tokens and exported under prefers-contrast: more. The forced-colors block hands control to the user's own system colours.
Import
Names such as --color-bg and --color-text-muted, with hex values. Values inside a prefers-color-scheme: dark block, or the second value of light-dark(), set the dark theme.
How it works
Pick Light or Dark and edit the nine tokens, by hex or with OKLCH sliders. The matrix shows the WCAG 2 contrast ratio for each pair, with pass or fail for AA text (4.5:1), AA large text (3:1), UI components (3:1) and AAA text (7:1). Ratios use the relative luminance definition in the current WCAG 2.2 text, with the 0.04045 threshold.
When a pair misses its target, auto-fix proposes the nearest colour that passes by changing OKLCH lightness while keeping hue and chroma where the sRGB gamut allows. If no colour can pass on that background, it says so.
The high-contrast theme is derived from the Light or Dark tokens. The tokens, and nothing else, are stored in the URL hash, so a link restores the same lab.
Colour-vision simulations use the Machado, Oliveira and Fernandes (2009) matrices at severity 1.0, applied in linear RGB through SVG filters on the preview only. Achromatopsia is luminance only.
Keyboard and text equivalent
Everything works from the keyboard: Tab through the controls, arrow keys move the theme choice and the sliders, and Enter or Space press buttons. Every colour has a hex field, so the native colour picker is optional. The preview shows a card, a button, a link, an input, an error and a success message, a focus ring and a three-bar chart in the selected theme; the matrix lists the same information as text.
What this can't check
- It reports ratios and thresholds. It does not say a theme is compliant: compliance involves more than colour.
- It checks the token pairs listed in the matrix, not every combination your design uses, and not text over images or gradients.
- The colour-vision simulations are approximations of dichromacy at full severity. They are not a clinical or user-research result.
- The colour-blind check uses an OKLab distance threshold chosen for this tool, not a standard.
- APCA values are advisory. APCA is part of a WCAG 3 draft and is not a WCAG 2 conformance requirement.
- The high-contrast theme is derived from your tokens with this tool's own targets (7:1 for text, 4.5:1 for UI). Users in forced-colors mode get their own system colours.
References
- WCAG 2.2: Understanding 1.4.3 Contrast (Minimum)
- WCAG 2.2: Understanding 1.4.11 Non-text Contrast
- WCAG 2.2: relative luminance definition
- MDN: forced-colors
- MDN: light-dark()
- Machado, Oliveira and Fernandes (2009): colour vision deficiency simulation, with the authorsβ matrices
- OKLab colour space (BjΓΆrn Ottosson)
- APCA (APCA-W3 project)