Engineering

Why OKLCH Changes Everything About Color in UI

P

Prim UI Team

Prim UI · Feb 15, 2026 · 6 min read

If you've ever generated a color palette in HSL and wondered why your yellows look washed out while your blues feel heavy, you've discovered HSL's dirty secret: its lightness channel lies.

An HSL lightness of 50% produces wildly different perceived brightness depending on the hue. Yellow at hsl(60, 100%, 50%) looks blazing bright. Blue at hsl(240, 100%, 50%) looks like midnight. Same lightness value, completely different visual weight.

OKLCH fixes this with a perceptually uniform lightness channel. When you set L=0.65 for blue and L=0.65 for yellow, they actually look equally bright to human eyes. This isn't a minor improvement — it's the difference between palettes that feel intentional and palettes that feel random.

For design systems, this property is transformative. You can define a single lightness curve (say, 0.97 for shade-50 down to 0.25 for shade-900) and apply it to any hue. Every resulting shade will have consistent visual weight. Your blue-500 and your red-500 will feel like they belong together because they literally have the same perceptual lightness.

example.ts
// HSL: "50% lightness" means different things per hue
"hsl(60, 100%, 50%)"   // Yellow — looks very bright
"hsl(240, 100%, 50%)"  // Blue — looks much darker

// OKLCH: L=0.65 means the same perceived brightness
"oklch(0.65 0.25 90)"  // Yellow — balanced
"oklch(0.65 0.25 260)" // Blue — same perceived brightness

// Prim's scale generation leverages this:
function generateScale(anchor: string) {
  const { c, h } = parseOklch(anchor);
  return {
    50:  `oklch(0.97 ${(c * 0.15).toFixed(3)} ${h})`,
    500: anchor,
    900: `oklch(0.27 ${(c * 0.55).toFixed(3)} ${h})`,
  };
}
PropertyTypeDefault
FeatureHSLOKLCH
Perceptual uniformityNoYes
Consistent contrastManual tuningAutomatic
Dark mode conversionHeuristicSystematic
Palette generationPer-hue adjustmentSingle curve
Browser supportUniversalModern browsers

Chroma (the C channel) replaces HSL's saturation with a more predictable measure of color intensity. Low chroma values produce muted, sophisticated tones. High chroma values produce vivid, attention-grabbing colors. Unlike HSL saturation, chroma changes don't shift perceived lightness.

Prim uses OKLCH for all color generation. When you pick a primary color using the HSL picker (because HSL is more intuitive for human selection), Prim immediately converts to OKLCH for scale generation. The result is palettes where every shade feels balanced, contrast ratios are predictable, and dark mode conversions just work.

prim ui
EditorBlogPrivacy PolicyTerms
© 2026 prim ui