You shipped the feature. The code works. But something feels off.
You squint at the screen, toggle between breakpoints, and that… yeah. The button doesn't quite pop. The text feels muddy against the background. The dark mode version looks like someone just inverted everything and called it a day.
You're not imagining it. And you're not alone — this is one of the most common threads on r/webdev and in design-focused Discord servers. The gap between "technically valid CSS colors" and "colors that actually look right" is wider than most developers realize.
The good news? You don't need a design degree to close it. You need to understand three things: contrast, color space, and systematic palette building.
1. Contrast: The Problem Most Developers Underestimate
Many developers assume contrast is only about accessibility audits.
It's not.
Contrast is one of the biggest factors influencing whether an interface feels clear, professional, and trustworthy. Users often can't explain why a design feels difficult to use—but poor contrast is frequently the reason.
Consider this example:
/* Looks modern, but fails readability */
.text-muted {
color: #8a8a8a;
background: #ffffff;
}
At first glance, it seems fine. In reality, many users will struggle to read it, especially on mobile devices, low-quality screens, or bright environments.
A better version:
.text-muted {
color: #595959;
background: #ffffff;
}
The difference appears subtle to developers but significant to users.
Before shipping, always test your foreground and background combinations against WCAG guidelines.
If you don't have one bookmarked, ColorUI's WCAG & APCA Contrast Checker lets you paste in hex values and instantly tells you if you pass AA, AAA, or both:
https://colorui.io/contrast-checker
The entire process takes less than a minute and can dramatically improve usability.
2. You're Probably Using the Wrong Color Space
For years, most frontend developers worked exclusively with HEX, RGB, and HSL.
The problem?
These formats weren't designed around how humans actually perceive color.
That's why creating a color scale often feels unpredictable:
/* HSL example */
hsl(220 90% 60%)
hsl(220 90% 50%)
hsl(220 90% 40%)
The visual jumps between shades aren't consistent. Some colors become muddy. Others become overly saturated.
This is where OKLCH changes everything.
OKLCH is a perceptually uniform color space. In simple terms, equal numerical adjustments produce more predictable visual changes.
Modern CSS supports it directly:
.primary-500 {
color: oklch(65% 0.18 250);
}
.primary-600 {
color: oklch(58% 0.18 250);
}
.primary-700 {
color: oklch(50% 0.18 250);
}
Notice how only the lightness value changes while chroma and hue remain stable.
The result is a smoother, more professional color scale.
If you're still working primarily in HEX values, learning OKLCH is probably the highest-leverage color skill you can pick up this year.
And when you need to move between formats, a tool like ColorUI's format converter handles hex-to-OKLCH instantly:
https://colorui.io/color-converter
No manual calculations. No browser experiments.
3. Stop Picking Colors One by One
A surprisingly common workflow looks like this:
- Choose a primary color.
- Pick a slightly darker version.
- Pick another one.
- Adjust until it "looks right."
This works for prototypes.
It doesn't scale.
Instead, think in systems.
A professional palette typically contains:
- 50
- 100
- 200
- 300
- 400
- 500 (base)
- 600
- 700
- 800
- 900
Each step serves a purpose.
Example:
--blue-50: #eff6ff;
--blue-100: #dbeafe;
--blue-200: #bfdbfe;
--blue-300: #93c5fd;
--blue-400: #60a5fa;
--blue-500: #3b82f6;
--blue-600: #2563eb;
--blue-700: #1d4ed8;
--blue-800: #1e40af;
--blue-900: #1e3a8a;
Now every component can reference tokens instead of arbitrary colors.
.button {
background: var(--blue-600);
}
.button:hover {
background: var(--blue-700);
}
Consistency becomes automatic.
4. Dark Mode Is Not Light Mode Inverted
One of the biggest UI mistakes is treating dark mode like a simple inversion problem.
Developers often do this:
background: #000000;
color: #ffffff;
Technically correct.
Visually harsh.
Pure black and pure white create excessive contrast and eye strain.
Most mature design systems use softened values instead:
--bg-dark: #121212;
--surface-dark: #1e1e1e;
--text-primary: #f5f5f5;
--text-secondary: #cfcfcf;
The experience feels dramatically more comfortable.
Even better, create separate design tokens for light and dark themes:
:root {
--surface: #ffffff;
--text: #111111;
}
[data-theme="dark"] {
--surface: #1e1e1e;
--text: #f5f5f5;
}
This approach keeps your design system maintainable as the product grows.
The 10-Minute Color Audit
The next time a UI feels "off," run through this checklist:
Minute 1–2
Check text contrast against WCAG standards.
Minute 3–4
Verify primary actions stand out from surrounding elements.
Minute 5–6
Inspect dark mode separately rather than relying on inversion.
Minute 7–8
Review your palette for consistent shade progression.
Minute 9–10
Convert your main brand colors to OKLCH and compare the results.
Most interfaces improve noticeably after this simple review.
Final Thoughts
Great color choices aren't about artistic talent.
They're about using the right systems.
When developers struggle with UI colors, the issue usually isn't creativity—it's relying on outdated color spaces, inconsistent palettes, and unchecked contrast ratios.
Master those three areas and you'll immediately create interfaces that feel clearer, more professional, and easier to use.
The best part? It doesn't require a redesign.
Just ten focused minutes and a better workflow.
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.