Skip to content
HyperDAF editorialUX & Accessibility

Color Contrast in WordPress: WCAG Compliance Guide

A client once asked me to review his new website, and the first thing I noticed was the body text: a light, elegant gray on a white background. “It looks…

Featured image for Color Contrast in WordPress: WCAG Compliance Guide
UX & AccessibilityEditor-curated guide
18 min12 sectionsIntermediate
Before you beginWhat this guide gives you
12Focused sections18Minutes to finishIntermediateExperience level8Article views
Start reading
Table of contents12

A client once asked me to review his new website, and the first thing I noticed was the body text: a light, elegant gray on a white background. “It looks premium,” he said proudly. I pulled out my phone, turned the brightness down halfway, and handed it to him. He squinted. He tilted the screen. He couldn’t read his own homepage. “Premium,” I said, “shouldn’t require perfect lighting and twenty-year-old eyes.”

I’m Ryan Clarke, and I audit WordPress sites for color contrast problems — the single most common accessibility failure on the web. It shows up on more pages than missing alt text, more than unlabeled forms, more than anything else. And it’s also one of the easiest to fix, because it’s just numbers: your colors either pass or they don’t, and free tools tell you in seconds.

This guide gives you the exact WCAG contrast requirements — the Web Content Accessibility Guidelines, the W3C’s shared rulebook — in plain language: what 4.5:1 actually means, which text gets the easier 3:1 bar, the failures I find on nearly every WordPress site, and how to build a color palette that stays compliant. If you’ve ever wondered whether your site’s colors are readable for everyone, this is for you. Let’s measure.

Abstract illustration of typography samples ranging from faint gray to bold black on white cards, representing text contrast levels, on a deep navy background with green shapes.

The objection I hear: “But my brand colors are my brand colors.” I get it — and here’s the truth that settles it. Accessibility doesn’t ask you to abandon your brand. It asks you to use your brand colors where they work and adjust where they don’t: darker text variants, compliant button styles, readable combinations. Every major brand you admire has an accessible palette. Yours can too, usually with smaller changes than you’d expect.

Here’s what this guide covers:

  • What a Contrast Ratio Actually Is (No Math Degree Required)
  • The Exact WCAG Requirements: 4.5:1, 3:1, and 7:1
  • What Counts as “Large Text” (It’s More Specific Than You Think)
  • The Usual Suspects: Failures I Find on Nearly Every Site
  • How to Test Your Colors in 60 Seconds
  • Building an Accessible Palette That Still Looks Like You
  • Buttons, Links, and Form Fields: The Interactive Elements
  • Text Over Images: The Trick That Fools Everyone
  • Dark Mode and the Contrast Traps Nobody Warns You About
  • Keeping Contrast Compliant Over Time
  • Frequently Asked Questions
  • Final Thoughts

Ready? Let’s get started.

What a Contrast Ratio Actually Is (No Math Degree Required)

A contrast ratio is a number from 1:1 to 21:1 that describes how different two colors look from each other. 1:1 means identical — white on white, completely invisible. 21:1 is black on white, the maximum difference. Everything readable lives somewhere between.

Here’s the deal: the ratio is calculated from the colors’ relative luminance — basically, how bright each color is to the human eye, weighted for how we actually perceive light (we’re more sensitive to green than blue, for instance). You don’t need to do this math. Nobody does it by hand. Free tools compute it instantly from two hex color values.

What matters is that the ratios are thresholds, not suggestions — and there’s no rounding. A ratio of 4.499:1 fails a 4.5:1 requirement. The line is the line. This strictness is actually good news: it means contrast is objective. Two people can argue about whether a design “feels” readable; nobody can argue with 4.6:1.

One more concept before the requirements: contrast is always about a pair — text color against its background. A color isn’t “accessible” or “inaccessible” by itself. That trendy light gray might fail on white and pass on dark navy. Always test the pair as it actually appears on your site.

The Exact WCAG Requirements: 4.5:1, 3:1, and 7:1

WCAG success criterion 1.4.3 (Contrast Minimum) sets the core requirements at Level AA — the level most laws and contracts mean when they say “accessible”:

Normal text: at least 4.5:1. This is your body copy, your paragraphs, your list items — the text people actually read. Gray text on white is the classic failure: that “elegant” #999999 on white manages only about 2.85:1. It fails. Badly.

Large text: at least 3:1. Larger, bolder text is easier to read, so it gets a lower bar. But “large” has a precise definition (next section), and most of your text won’t qualify.

UI components and meaningful graphics: at least 3:1, under success criterion 1.4.11 (Non-text Contrast). This is the one people miss: button outlines, form field borders, focus indicators, checkboxes, toggle switches, and icons that convey meaning all need 3:1 against their adjacent colors. That hairline light-gray border around your form fields? Probably failing.

Enhanced contrast: 7:1 for normal text, under 1.4.6 (Contrast Enhanced) — but that’s Level AAA, the strictest level, which the W3C doesn’t recommend as a general target. Nice to have, not required. If you hit 7:1 naturally with dark text on white, great; don’t redesign around it.

A few things are exempt: logos and brand marks (WCAG doesn’t make you redesign your logo), purely decorative elements, and text that’s part of an inactive disabled control. Everything else — every word a visitor needs to read — plays by these numbers.

Bonus Tip: When someone on your team says “the contrast police won’t let us use this gray,” reframe it: the requirement isn’t anti-design, it’s pro-reader. Your most loyal readers include people with aging eyes, cheap screens, and sunlight. Designing for them is designing for your actual audience.

What Counts as “Large Text” (It’s More Specific Than You Think)

“Large text gets 3:1” is only useful if you know what counts as large. WCAG defines it precisely: 18pt or larger (about 24px), or 14pt or larger (about 18.66px) if bold. Anything smaller — or 18px regular weight — is normal text and needs 4.5:1.

This trips people up constantly. Your 20px regular-weight subheadings? Normal text — 4.5:1. Your 16px bold callout? Normal text — 4.5:1. Only genuinely large display text qualifies for the easier ratio, and on most WordPress sites that’s just the main headings and hero text.

Here’s my practical advice: don’t design around the 3:1 exception. Aim for 4.5:1 on everything textual, and treat 3:1 as the floor for the few large elements where your brand color genuinely can’t go darker. Sites that target 4.5:1 everywhere never have to think about which text qualifies — and they look sharper for it. The exception exists for cases like large colored headlines where darkening would kill the design, not as a general strategy.

Also note: the definition uses points, a print unit, and the px equivalents depend on context — 18pt ≈ 24px, 14pt ≈ 18.66px. When in doubt, test the pair and read the ratio; the tools don’t care about your font size, they just report the number against both thresholds.

The Usual Suspects: Failures I Find on Nearly Every Site

After auditing dozens of WordPress sites, I can predict the failures before I open the tools. Check your site for each of these — I’d bet on at least two.

Light gray body text on white. The number one offender. “Elegant,” “minimal,” “premium” — and unreadable. #999999 on white is 2.85:1; even #767676 only just scrapes 4.54:1. If your body text is any gray lighter than roughly #595959 on white, it’s failing. Darken it. Your readers’ eyes will thank you, and honestly, so will your bounce rate.

Placeholder text in form fields. Browser default placeholder colors are famously too faint — most fail 4.5:1 out of the box. If you use placeholder hints (and you shouldn’t use them as labels), set the placeholder color explicitly to something that passes. This is a five-minute CSS fix.

Brand-colored buttons with white text. Orange, light green, bright cyan, gold — brand colors that look great as accents often fail with white text on top. That orange button might be 2.5:1. Solutions: darken the button color, use dark text on the light button instead of white, or reserve the brand color for large text and borders while buttons use a darker variant.

White text over photos. Readable over the dark part of the image, invisible over the bright part. Hero sections with text laid directly on photography fail constantly — and automated checkers often miss them, because they can’t evaluate text over complex backgrounds reliably.

Pale form field borders. The 1.4.11 requirement catches these: a barely-visible light gray border around inputs that low-vision users can’t see at all. Borders need 3:1 against the background. Darken them.

“Disabled-looking” active buttons. If your active button looks faded — low opacity, washed out — users can’t tell whether it’s clickable. Either it’s disabled (exempt, but then it shouldn’t look clickable) or it’s active (and needs full contrast). Pick one.

Abstract illustration of a color palette fan with only some swatches glowing bright, representing an accessible color palette, on a deep navy background with green shapes.

How to Test Your Colors in 60 Seconds

Testing is embarrassingly easy, which is why there’s no excuse for skipping it. Three tools cover everything:

WebAIM Contrast Checker (free, in your browser): enter your foreground and background hex values, get the ratio instantly with pass/fail against AA and AAA for normal and large text. This is my daily driver — bookmark it.

Colour Contrast Analyser by TPGi (free desktop app): the eyedropper tool lets you sample any pixel on your screen. Invaluable for text over images, gradients, and “what color is that actually” mysteries. When a client says “but it’s dark gray,” the eyedropper settles it.

Browser DevTools (built into Chrome and Firefox): inspect any text element, and the color picker shows the contrast ratio against its background right there. Perfect for checking elements in context without copying hex values around.

The 60-second routine: open your homepage, DevTools-inspect your body text, headings, buttons, links, and form labels. Note every pair under 4.5:1 (or under 3:1 for genuinely large text and UI components). That’s your fix list. Most sites have between five and fifteen failing pairs, and most fixes are darkening a color by a few shades.

Note: Automated page scanners are great for finding text contrast failures across a whole site at once, but they miss text over images and gradients, interactive states like hover and focus, and dark mode variants. Pair automation with the eyedropper for full coverage — the tools complement each other.

Building an Accessible Palette That Still Looks Like You

Here’s where design meets compliance, and it’s more creative than people expect. The goal: a defined palette where every text-background combination passes, documented so anyone working on the site uses the right pairs.

Start by listing every color combination your site actually uses: body text on background, headings, links, buttons (normal, hover, and disabled states), form labels, placeholder text, error messages, footer text, and any text over images. Yes, every state — hover and focus variants fail surprisingly often because someone lightened the button for the hover effect.

For each combination, test the ratio and adjust the failing ones. The adjustments are usually small: darken the gray from #999 to #595959, deepen the brand orange for button backgrounds while keeping the bright version for large headlines and decorative accents, darken error red so the message text passes. You’re not abandoning colors — you’re defining which variant goes where.

Then document it. A simple table — color name, hex, where it’s used, what it pairs with, the ratio — saves every future argument. When a new team member or a page builder introduces a new combination, the table is the test: does this pair pass? If not, pick a documented pair instead.

The professional move is semantic naming: instead of “gray-3,” name colors by role — text-body, text-muted, button-primary-bg. Then “muted text” is defined once as a passing pair, and nobody has to re-verify it on every page. This is also how you survive theme updates: your palette is a specification, not a collection of one-off choices.

For a safe workflow when changing colors across your site, the guide to customizing WordPress without breaking it walks through testing changes before they go live. And if your theme’s color options are limited, the WordPress custom CSS recipes show how to override specific colors without touching theme files.

Buttons, Links, and Form Fields: The Interactive Elements

Text contrast gets all the attention, but interactive elements have their own requirement — 1.4.11 (Non-text Contrast), 3:1 against adjacent colors — and they fail in ways text checkers don’t catch.

Buttons: the button’s text needs 4.5:1 against the button background (it’s normal text), and the button’s boundary needs 3:1 against the page background so users can perceive it as a button. A common failure: a white button with a hairline gray border on a white page — the text passes, but the button itself is invisible as a control. Also test hover, focus, and active states separately; I’ve seen buttons that pass at rest and fail on hover because the hover lightens the background.

Links: link text needs 4.5:1 against the page background like any text, but it also needs to be distinguishable from surrounding body text. If your links are only identifiable by color, that color difference needs 3:1 against the body text — or simpler and better, underline your links. Underlined links are distinguishable without any color math, and they match what users expect.

Form fields: borders, checkboxes, radio buttons, and toggle switches need 3:1 against the background. Focus indicators on fields need to be visible too — and they need contrast against the field background in both their focused and unfocused states. Placeholder text needs 4.5:1 like any text. Error messages need 4.5:1 — light red on white routinely fails, so use a darker red.

Icons that convey meaning: a warning triangle, an info icon, a checkmark that means “done” — if the icon carries information, it needs 3:1. Purely decorative icons are exempt, but be honest about which is which. If removing the icon would lose meaning, it’s meaningful.

Abstract illustration of glowing buttons and form field outlines with high-visibility borders, representing UI component contrast, on a deep navy background with green shapes.

Text Over Images: The Trick That Fools Everyone

Text over images is the contrast problem that looks fine in the design mockup and fails on the live site. The mockup used one perfect photo; the live site rotates images, or the CMS crops differently, or the user’s screen renders it brighter. The text that was readable over the dark left side of the image is invisible over the bright right side.

I test these with the eyedropper, sampling the lightest area behind the text — because contrast must hold for the worst case, not the average. If any part of the text sits over a bright patch, it fails.

The fixes, in order of reliability. Best: don’t put text over images — use a solid or gradient overlay behind the text. A dark gradient rising from the bottom of a hero image, with white text in the darkened zone, is the industry standard for a reason: it’s bulletproof across images. Good: add a semi-transparent dark layer over the whole image (around 40-60% black) — it unifies the background and guarantees the ratio. Acceptable: use text with a subtle shadow or backing plate, but verify with the eyedropper on the actual lightest pixels. Avoid: thin white text directly on photography with no overlay. It fails more often than not.

Also watch carousels and sliders where the background image changes: the text must pass against every image in the rotation, not just the first one. If you can’t guarantee that, the overlay approach isn’t optional — it’s required.

This connects to image performance too: if you’re re-exporting hero images to add overlays, keep them web-optimized. The lazy loading images guide covers keeping image weight down while you’re at it.

Dark Mode and the Contrast Traps Nobody Warns You About

Dark mode isn’t exempt from contrast requirements — and it has its own failure patterns that catch teams who only tested their light theme.

Secondary text on elevated surfaces. Your muted gray might pass against the page background but fail against a slightly lighter card background. In dark mode, you have multiple surfaces — base, cards, inputs, modals — and every text color must be tested against every surface it appears on, not just the base.

Placeholder and disabled states. The opacity trick — making disabled text 50% opacity of the active color — works acceptably on white backgrounds and produces unreadable ghosts on dark ones. Define explicit disabled colors instead of relying on opacity.

Focus indicators. The default blue focus ring can vanish against dark surfaces. Test your focus style on every background, and consider a two-color indicator (a dark inner ring plus a light outer ring) that stays visible everywhere. This also satisfies the keyboard accessibility requirement — visible focus is non-negotiable regardless of theme.

Pure black and pure white. Ironically, maximum contrast can cause its own problems: pure white text on pure black causes halation (glare) for some readers, especially those with astigmatism. Slightly off-white text on a very dark gray is more comfortable and still passes easily. Comfort matters — contrast minimums are floors, not ideals, and readability is the actual goal.

If your theme offers a dark mode toggle or auto-switches, test both modes completely. They’re effectively two sites sharing content, and each needs its own passing palette.

Abstract illustration of a phone in bright sunlight beside a dark mode phone, representing readability in different lighting conditions, on a deep navy background with green shapes.

Keeping Contrast Compliant Over Time

Contrast decays. A marketer adds a campaign banner with brand colors that fail. A new plugin injects a widget with light gray text. A page builder’s new template uses white text over a photo. The palette document from the last section is your defense — but only if checking becomes habit.

Build contrast checks into your existing workflows. When anyone proposes new colors — a campaign, a seasonal banner, a new section — the question is “what’s the ratio,” asked before it goes live, not after someone complains. Keep the WebAIM checker bookmarked on every team member’s browser. It takes thirty seconds per pair.

Run an automated scan monthly; most accessibility scanners flag contrast failures across the whole site at once. And re-verify manually after theme updates, because themes occasionally adjust their color variables — a “minor” update can shift your body text from passing to failing without anyone noticing.

One more habit: when you fix a contrast failure, fix the palette, not just the instance. If light gray body text failed on the blog, it’s probably failing on the landing pages too. Find every use of the failing pair and update them together. Systematic beats whack-a-mole, every time.

Frequently Asked Questions

Do I really need 4.5:1? My site looks fine to me.

“Looks fine to me” is the most expensive sentence in accessibility. You have your eyes, your screen, your lighting. Your visitors include people with low vision, cataracts, aging eyes, cheap monitors, and phones in bright sunlight — for them, the difference between 3:1 and 4.5:1 is the difference between reading and guessing. The ratio isn’t about your experience; it’s about theirs. And it’s objective: test it, don’t eyeball it.

Are logos exempt from contrast requirements?

Yes. WCAG explicitly exempts logotypes — the guidelines don’t require you to redesign your logo. But the exemption is narrow: it covers the logo itself, not text styled to look like part of the branding elsewhere on the site. Your logo can stay as-is; your body text, buttons, and headings still need to pass.

What about text in images, like infographics?

Text inside images must meet the same contrast requirements as regular text — and it’s worse, because you can’t zoom it, reflow it, or restyle it, and screen readers can’t read it at all without alt text. The real answer: don’t put important text in images. Use real HTML text styled with CSS. It scales, it reflows, it meets contrast, and assistive technology can read it. Save images for what images are good at.

Does dark mode change the requirements?

No — the ratios are the same. 4.5:1 for normal text, 3:1 for large text and UI components, regardless of whether the text is dark-on-light or light-on-dark. What changes are the failure patterns: secondary text on elevated surfaces, opacity-based disabled states, and focus rings that disappear on dark backgrounds. Test both modes as if they were separate sites.

My brand color fails with white text. What are my options?

Four, in order of preference: use a darker variant of the brand color for the button background (keeps the brand, passes the ratio); put dark text on the brand color instead of white (works when the brand color is light); reserve the brand color for large text, borders, and accents while interactive elements use a darker companion color; or add a dark outline/shadow that brings the effective contrast up (fragile — verify carefully). What you can’t do is ship the failing combination and hope nobody notices. Someone always notices.

Final Thoughts

That client’s “premium” gray text? We darkened it two shades. He couldn’t tell the difference — and I mean that literally; I showed him before and after and he shrugged. His readers could tell, though. The ones who’d been squinting, zooming, or just leaving. Two shades. That’s how small most contrast fixes are, and how large their impact is.

You now know the exact numbers — 4.5:1 for text, 3:1 for large text and components, 7:1 if you’re feeling ambitious — the usual suspects to check, the 60-second testing routine, and how to build a palette that stays compliant. It’s all measurable, all fixable, and most of it is darkening a gray.

One honest line: contrast is the least glamorous accessibility work and the most universally felt. Nobody writes a testimonial about readable text. They just stay, read, and come back. That’s the whole game.

If you run the 60-second test and find a failing pair, tell me about it in the comments — especially if the fix was smaller than you expected. Those stories are my favorite.

Written by

Ryan Clarke

Ryan runs WordPress infrastructure for high-traffic stores. His 9 years in hosting and DevOps shape his guides on servers, staging workflows, backups, and deployment.

7 published articles
View all articles

Related articles

View all articles

Join the discussion

Your email address will not be published. Required fields are marked *

Keep comments relevant and respectful.