Bookmarks for Devs

Colour contrast checker with WCAG suggestions

Check any two colours against WCAG 2 — normal text, large text and UI components — see the ratio and live samples, and get the nearest passing colour when a pair fails, adjusted in OKLCH so the hue stays yours. Free, runs in your browser.

Free · no sign-up · runs in your browser

Any hex — #b9471b, b9471b or #abc.

Normal text at 16px — the size most of your copy actually is.

Large text, 24px

UI component / border

Contrast ratio

5.19:1

WCAG 2

  • Normal text · AA · 4.5:1Pass
  • Normal text · AAA · 7:1Fail
  • Large text · AA · 3:1Pass
  • Large text · AAA · 4.5:1Pass
  • UI & graphics · 3:1Pass

Nearest passing

Aim for

This pair already clears the target.

Copy the pair

CSS

color: #b9471b;
background-color: #fefdfb;

Most contrast checkers tell you a pair fails and leave you guessing by how much or what to do about it. This gives you the ratio against all five WCAG thresholds at once, shows the pair at the sizes those thresholds are actually about, and — when it fails — works out the closest colour that would pass by moving lightness only, so the result is still recognisably your colour rather than a different one.

How it works

  1. 01The ratio is WCAG 2's own formula: relative luminance of the lighter colour plus 0.05, over the darker plus 0.05. It runs from 1:1 (identical) to 21:1 (black on white).
  2. 02Five thresholds are checked at once. Normal text needs 4.5:1 for AA and 7:1 for AAA. Large text — 24px regular or 18.66px bold, a size rule rather than a judgement call — needs 3:1 and 4.5:1. UI components and graphics need 3:1 under 1.4.11, which is the one people forget: a form field's border has to clear it whatever the label does.
  3. 03The samples render your two colours at each of those sizes, because a ratio is abstract and a paragraph is not.
  4. 04When a pair fails, the suggestion moves lightness in OKLCH and nothing else. Contrast is a function of luminance, which OKLCH's lightness tracks almost directly — so hue and saturation stay put and the result still reads as your brand colour, which is not true of nudging a hex channel by channel.
  5. 05Both directions are searched, and the smaller change wins. On a light page that is nearly always a darker text colour, but on a mid-tone background the shorter road can go either way.
  6. 06You get two options — change the text, or change the background — because which one you can actually change is a design question, not a maths one.

Use cases

  • Checking a brand colour against your page background before it ships.
  • Finding the closest accessible version of a colour you are not allowed to abandon.
  • Working out whether a heading passes at large-text thresholds even though the body copy does not.
  • Checking a border, icon or focus ring against 1.4.11's 3:1, which text-only checkers skip.
  • Fixing an audit finding without redesigning the palette.
  • Comparing a light and a dark theme's version of the same pairing.

Frequently asked questions

What contrast ratio does WCAG require?

4.5:1 for normal text at AA and 7:1 at AAA. Large text — 24px regular or 18.66px (14pt) bold and above — needs 3:1 at AA and 4.5:1 at AAA. Non-text things that carry meaning, like input borders, icons and focus indicators, need 3:1 under success criterion 1.4.11. All five are shown above at once, because the same pair can pass one and fail another.

What counts as large text?

24px or larger at a normal weight, or 18.66px (14pt) or larger at bold. It is a size threshold, not a judgement about importance — which is why a heading can legitimately use a colour its own body copy cannot. If your heading is smaller than that it is normal text, whatever it is called in the design file.

Why change lightness instead of the hex value?

Because contrast is driven by relative luminance, and in OKLCH lightness maps to that almost directly while hue and chroma stay where they are. Nudging a hex channel by channel changes the hue as a side effect, so you end up with a colour that passes but is no longer the one you were asked to use. Adjusting lightness gets you the smallest change that fixes the problem while the colour stays recognisably itself.

Does a 3:1 ratio pass for body text?

No. 3:1 is the threshold for large text and for non-text UI elements. Body copy needs 4.5:1 at AA. A pair sitting at 3:1 will show as passing for large text and for UI while failing for normal text above — that combination is normal and is exactly what the separate rows are for.

Is WCAG 2 contrast the same as APCA?

No. APCA is a newer perceptual model being developed for WCAG 3, and it disagrees with WCAG 2 in places — particularly on light text over dark backgrounds, which WCAG 2 tends to score generously. WCAG 2 is what current accessibility law and audits actually reference, so it is what this checks. If your organisation is targeting APCA, use a dedicated APCA tool alongside it.

Does contrast apply to disabled controls and logos?

No, both are exempt from the contrast requirements — disabled elements and pure logotypes have no minimum. That is a legal exemption, not design advice: a disabled button nobody can read is still a usability problem, and it is worth clearing 3:1 anyway.

Related resources

Related reading

More tools

Tailwind CSS color palette generator

Open →

Turn one hex code into a full Tailwind color scale — 11 OKLCH-tuned shades from 50 to 950, with contrast ratios, ready to paste into Tailwind v4's @theme block or a v3 config. Free, no sign-up, runs in your browser.

CSS clamp() calculator for fluid typography

Open →

Generate a responsive CSS clamp() font size from a minimum and maximum size and the viewport range they should grow across — with the slope and intercept shown, a live preview, and the rendered size at every common screen width. Free, no sign-up.

SVG to JSX converter for React components

Open →

Paste an SVG and get a React component back — attributes camelCased, class turned into className, style strings converted to objects, xmlns removed, with optional currentColor, a size prop and TypeScript output. Runs entirely in your browser; nothing is uploaded.

Meta tag generator with Google SERP preview

Open →

Fill in a title, description, canonical and Open Graph image and get the complete <head> snippet — with a live Google result preview that measures your title and description in pixels, not characters, so you can see exactly where they will be cut.

Favicon generator — .ico, PNG set and manifest

Open →

Turn a PNG or SVG, or just a couple of letters, into the full favicon set: 16, 32, 48, 180, 192 and 512 PNGs, a real multi-size favicon.ico, a web app manifest and the <head> tags. Everything runs in your browser — nothing is uploaded.

JSON-LD schema generator and validator

Open →

Build valid JSON-LD structured data for Article, FAQPage, Product, Organization and BreadcrumbList from a form, or paste existing markup to have it pretty-printed and checked for the mistakes that stop a rich result appearing. Free, runs in your browser.

robots.txt generator with validation

Open →

Build a robots.txt from user-agent groups, allow and disallow rules, crawl-delay and sitemap URLs — with presets for allowing everything, blocking AI crawlers, or locking down a staging site, and warnings for the mistakes that quietly block your whole site.

UTM link builder and campaign URL generator

Open →

Build correctly encoded UTM tracking links from a URL and your source, medium and campaign — with the existing query string and fragment preserved, values properly percent-encoded, and warnings for the capitalisation and spacing that split one campaign across several rows in an analytics report.

Image converter — WebP, AVIF, JPEG and PNG

Open →

Convert and resize images to WebP, AVIF, JPEG or PNG at the quality you choose, see exactly how many bytes each one saved, and download them one at a time or as a zip. Everything happens in your browser — no image is uploaded.

JSON formatter and validator — free, in your browser

Open →

Format, minify and validate JSON in your browser. Broken documents get the exact line and column of the error. Nothing is uploaded, and there is no size limit but your machine.

JSON to TypeScript — generate interfaces from a payload

Open →

Paste a JSON payload and get TypeScript interfaces: merged array shapes, optional properties, and real unions instead of any. Runs in your browser — nothing is uploaded.

OG image generator — free 1200×630 social cards

Open →

Generate an Open Graph image for any page: type a title, pick a theme, download a 1200×630 PNG. Runs entirely in your browser — no account, no upload, no watermark.