Back to all posts
CSSDesignOKLCH

OKLCH: The Future of CSS Colors

OKLCH: The Future of CSS Colors
5 min read

OKLCH is perceptually uniform, HDR-ready, and makes theming easier. Here's why you should switch from HSL/RGB.

I switched my entire portfolio to OKLCH colors. Here's why it matters.

What's Wrong with HSL/RGB?

RGB is for Computers

color: rgb(100, 150, 200);

What does this look like? No idea. RGB describes light output, not perceptual color.

HSL is Better, But Flawed

color: hsl(210, 60%, 50%);

Better — we can reason about hue and saturation. But lightness is inconsistent:

/* Same lightness value, different perceived brightness */
background: hsl(200, 80%, 50%); /* Looks darker */
background: hsl(80, 80%, 50%);  /* Looks brighter */

Yellow at 50% lightness appears much brighter than blue at 50%. This makes theming painful.

Enter OKLCH

OKLCH is designed for perceptual uniformity:

color: oklch(65% 0.15 250);
  • L = Lightness (0-100%)
  • C = Chroma (color intensity)
  • H = Hue (0-360)

The key insight: equal lightness = equal perceived brightness.

Real Example: Theming

HSL Version (Inconsistent)

:root {
  --bg-primary: hsl(220, 20%, 10%);
  --bg-secondary: hsl(220, 20%, 15%);
  --bg-tertiary: hsl(220, 20%, 20%);
}

Looks fine until you add accent colors:

/* These don't match visually */
.accent-yellow { background: hsl(60, 80%, 50%); }
.accent-blue { background: hsl(220, 80%, 50%); }

OKLCH Version (Consistent)

:root {
  --bg-primary: oklch(20% 0.02 250);
  --bg-secondary: oklch(25% 0.02 250);
  --bg-tertiary: oklch(30% 0.02 250);
 
  /* These match perfectly */
  .accent-yellow { background: oklch(80% 0.18 100); }
  .accent-blue { background: oklch(80% 0.18 250); }
}

Both accents at 80% lightness look equally bright.

Browser Support

OKLCH is supported in:

  • ✅ Chrome 111+
  • ✅ Safari 15.4+
  • ✅ Firefox 113+
  • ✅ Edge 111+

That's ~92% of users globally. For older browsers, provide a fallback:

.button {
  background: hsl(220, 80%, 50%); /* Fallback */
  background: oklch(65% 0.18 250); /* Modern */
}

My Portfolio Color System

I use OKLCH for everything:

:root {
  /* Neutrals */
  --bg-dark: oklch(12% 0.01 250);
  --bg-card: oklch(18% 0.01 250);
  --text-primary: oklch(95% 0.01 250);
  --text-secondary: oklch(70% 0.01 250);
 
  /* Accent */
  --accent: oklch(91.7% 0.201 117); /* #e2f658 green */
  --accent-dim: oklch(70% 0.15 117);
 
  /* Semantic */
  --success: oklch(70% 0.18 145);
  --warning: oklch(75% 0.18 85);
  --error: oklch(65% 0.18 25);
}

Light/dark mode? Just adjust L:

@media (prefers-color-scheme: dark) {
  :root {
    --bg-base: oklch(12% 0.01 250);
    --text-base: oklch(95% 0.01 250);
  }
}
 
@media (prefers-color-scheme: light) {
  :root {
    --bg-base: oklch(98% 0.01 250);
    --text-base: oklch(20% 0.01 250);
  }
}

Converting Colors

Use oklch.com to visually convert colors, or use libraries like colorjs.io for programmatic conversion.

Why It Matters

  1. Accessible theming: Consistent contrast ratios
  2. HDR support: OKLCH can display wider gamut colors
  3. Future-proof: Designed for modern displays

Start Simple

Replace one color system at a time:

/* Before */
--primary: hsl(220, 80%, 50%);
 
/* After */
--primary: oklch(65% 0.18 250);

Your future self (and your users) will thank you.


Switched to OKLCH in 2024 · Colors finally make sense