Algorithmic Theming Engines

mooreds1 pts0 comments

Algorithmic Theming Engines: Building Self-Correcting Color Systems With contrast-color() — Smashing Magazine<br>Skip to main content<br>Start reading the article<br>Jump to list of all articles<br>Jump to all topics

Clear Search

15 min read<br>CSS,<br>Coding,<br>Techniques<br>Share on Twitter, LinkedIn

About The Author<br>Durgesh Rajubhai Pawar is a freelance developer dedicated to building high-performance, accessible web applications. He specializes in orchestrating complex …<br>More about<br>Durgesh ↬

Email Newsletter<br>Your (smashing) email

Weekly tips on front-end & UX.<br>Trusted by 182,000+ folks.

See User Testing Live

Celebrating 10 million developers

Custom Web Forms for Angular, React, & Vue. Your backend.

How To Measure UX and Design Impact, 8h video + UX training

SmashingConf Freiburg 2026

How To Measure UX and Design Impact with Vitaly Friedman

Design Patterns For AI Interfaces, 30 lessons + UX training

Seventy percent of websites still fail basic WCAG contrast checks in 2025. After years of design system tooling, accessibility linters, and JavaScript libraries, nothing moved the needle. We didn’t need better libraries. We needed better CSS. contrast-color() is that better CSS.

The HTTP Archive Web Almanac has been tracking color contrast failures for years. The numbers have barely moved. After half a decade of design system tooling, accessibility linters, and entire JavaScript libraries dedicated to computing readable text colors, 70% of websites still fail basic WCAG contrast checks in 2025. The WebAIM Million paints an even grimmer picture — 83.9% of homepages flagged for low contrast text in 2026, up from 79.1% in 2025. The rate improves by maybe a few percentage points per year on one benchmark and actually gets worse on another. That’s not progress — that’s proof that relying on runtime JavaScript for something this fundamental doesn’t scale across the open web. We didn’t need better libraries. We’ve needed better CSS.<br>The contrast-color() function is that better CSS. One declaration. The browser runs the contrast math during style computation, before the page paints, and hands you the right text color. No library, no build step, no hydration flash.<br>Note : If you’ve seen it called color-contrast() in older articles and spec drafts — that name was changed, and the old syntax no longer works in any browser.<br>What It Does (And What It Doesn’t)<br>The Level 5 version is simple. You give it a color. It gives you back black or white, whichever has more contrast against your input.<br>.button {<br>background-color: var(--brand-color);<br>color: contrast-color(var(--brand-color));<br>Change --brand-color to neon green, text goes black. Change it to midnight navy, text goes white. Swap themes at runtime via JavaScript and the text adapts instantly — no event listeners, no recalculation.<br>A few things to know about the current version:<br>It returns a , not a number. You get an actual color value (black or white), you can use anywhere CSS accepts a color.<br>Black or white only , for now. Candidate color lists and target ratios are planned for Level 6.<br>No keywords. If you’ve seen max in older blog posts, that was stripped from the spec. Using it will silently break your declaration.<br>As mentioned above, this function used to be called color-contrast() in early drafts. That name is dead — the CSSWG renamed it to follow the convention that CSS functions are named for what they return. color-mix() returns a color. contrast-color() returns a color. The old color-contrast() name sounded like it returned a contrast ratio (a number like 4.5), which was misleading. Any tutorial from 2021–2023 showing color-contrast() syntax won’t work in current browsers.

Meet Smashing Workshops on front-end, design & UX , with practical takeaways, live sessions, video recordings and a friendly Q&A. With Brad Frost, Stéph Walter and so many others.<br>Jump to the workshops ↬

The Spec Split: Level 5 Versus Level 6<br>This function lives across two specifications. That’s unusual and worth understanding.<br>CSS Color Level 5 defines what browsers ship today. One color in, black or white out. The algorithm is deliberately marked “UA-defined”, meaning the browser decides what math to use internally. Right now, every engine uses WCAG 2.x relative luminance. But that “UA-defined” label isn’t accidental — it’s a planned escape hatch.<br>You’ll see APCA (Accessible Perceptual Contrast Algorithm ) mentioned a lot in this context. APCA models how human eyes actually perceive contrast, factoring in font weight, spatial frequency, and ambient light — a genuine improvement over the WCAG 2.x formula. By not locking “use WCAG 2.x” into the Level 5 spec, browser vendors could swap to APCA later without breaking any existing code. If the spec had shipped with a wcag2() keyword as the default, every site using it would’ve been stuck on the old math permanently.<br>But APCA’s future is far less certain than the hype suggests. Adrian Roselli’s “WCAG3 Contrast as of April 2026” lays out the current...

color contrast design better text level

Related Articles