About this contrast checker
A small, fast, dependency-free tool for one job: telling you the exact WCAG 2.x contrast ratio between two colours and whether it passes. No account, no upload, and nothing you type is ever recorded.
Why it exists
Contrast is the accessibility problem that is easiest to get right and most often got wrong. It has a closed-form answer — there is no judgement involved — yet plenty of tools round before they compare, mishandle three-digit hex, silently render NaN on bad input, or quietly disagree with each other at the boundary. When a build is going to be audited, or when a designer and a developer are arguing about a grey, you want a number you can trust and a threshold you can point at.
So this site does exactly that, and then explains the reasoning around it properly: what the formula is doing, what large text actually means, what is exempt, and which level anyone is realistically going to hold you to.
How the calculation is implemented
Straight from the WCAG 2.x definition of relative luminance, with no shortcuts:
Two implementation details that matter more than they sound:
- Rounding is display-only. The pass/fail comparison always uses the full double-precision ratio. A pair computing to 4.4996 displays as “4.50” and is still reported as failing AA for normal text, because it is.
- Input is validated, never coerced. Hex is accepted as
#RGBor#RRGGBB, with or without the hash, in any case, with surrounding whitespace trimmed. Anything else produces a specific message explaining what is wrong. Nothing ever renders asNaN, and an invalid keystroke never silently changes your result.
How it was verified
The luminance function was run against reference values with known answers before the site shipped:
| Pair | Expected | Computed | Result |
|---|---|---|---|
| #FFFFFF on #000000 | 21 | 21.000000 | exact |
| Any colour on itself | 1 | 1.000000 | exact |
| #777777 on #FFFFFF | ≈ 4.48 | 4.478089 | match |
| #767676 on #FFFFFF | ≈ 4.54 | 4.542225 | match |
Beyond those fixed vectors, three thousand random colour pairs were checked for two invariants: the ratio is symmetric (swapping the arguments never changes it) and the result always lands within the closed range 1 to 21. Zero failures. Shorthand parsing was checked to expand correctly (#0a7 and 00aa77 must produce identical output), and malformed input — four digits, five digits, non-hex characters, empty string — was checked to be rejected rather than partially parsed.
You can verify it yourself in the browser console on any page of this site: WCAGContrast.contrastRatio([255,255,255],[0,0,0]) returns exactly 21.
How the site is built
- Static HTML, one small stylesheet, one small script. No framework, no build step, no bundler.
- The checker needs nothing from the network. It uses no CDN framework, no web font and no remote image of its own; the favicon is an inline SVG data URI. Once a page has loaded it works offline, and works if you save it to disk and open it directly.
- System font stack. Your operating system's UI font, so nothing has to download and nothing shifts as it loads.
- Nothing you type is transmitted. The whole calculation happens in your browser, and the colours you enter are never uploaded to anything. They appear in the URL fragment only so a specific pair can be bookmarked or shared, and fragments are never sent to a server.
- Dark mode follows your system setting via
prefers-color-scheme.
The site's own contrast
It would be embarrassing to ship a contrast checker that fails its own test, so every colour pair in this interface was measured before release. Body text is 15.6:1 in light mode and 15.3:1 in dark mode. The muted grey used for secondary text is 5.8:1 on white and 8.5:1 on the dark background. The green used for links and headings is 7.07:1 on white and 10.4:1 on dark. Button labels, badge text, table headers, form borders and focus rings all clear AA, and most clear AAA. Every control is reachable and operable by keyboard, every input has a real <label> associated with it, and results are announced to screen readers through a polite live region.
If you find a pair on this site that does not meet AA, that is a bug worth reporting — see contact.
Scope and honesty about limits
This implements WCAG 2.x, the version referenced by essentially every accessibility law and procurement standard currently in force. It does not implement APCA, the perceptual model drafted for WCAG 3.0, because WCAG 3.0 remains a working draft and nobody is being audited against it yet.
The tool takes two flat colours. It cannot evaluate text over images, gradients or video, it says nothing about colour vision deficiency, and it is not a substitute for a full accessibility review. It is not legal advice and no conformance claim is made on your behalf.