oklch Color Science, Explained

Every CSS framework picks a color model. Bootstrap uses hex. Tailwind uses HSL. Stride uses oklch. This isn't a preference. It's a technical decision with measurable consequences for how your colors behave across states, modes, and contexts.

What "Perceptually Uniform" Means

In HSL, two colors at the same lightness value can appear drastically different to the human eye. Yellow at hsl(60, 100%, 50%) is visually much brighter than blue at hsl(240, 100%, 50%). Both have L: 50%, but your eyes disagree.

This happens because HSL's lightness channel is mathematically convenient but perceptually inaccurate. It treats all hues as equal in perceived brightness, which is objectively false.

oklch fixes this. Its L (lightness) channel is calibrated against human vision. Two colors at L: 0.7 will actually look equally bright to your eyes, regardless of hue. This is what "perceptually uniform" means: equal mathematical steps produce equal visual steps.

The eye is the final arbiter of color. A color model that ignores how humans see is broken by design. oklch is the first widely-supported CSS color space that takes perception seriously.

The Three Channels

oklch has three channels, each with a clear purpose:

L - Lightness (0 to 1)

How bright or dark the color appears. 0 is black. 1 is white. Every step between is perceptually equal. This is the channel that makes oklch revolutionary. You can generate a 9-step grayscale ramp by evenly spacing L values and they'll actually look evenly spaced.

C - Chroma (0 to ~0.4)

How vivid the color is. 0 is pure gray. Higher values are more saturated. Unlike HSL's saturation, chroma is bounded differently per hue. Yellows can reach higher chroma than blues. The model respects that human color perception has different saturation limits at different hues.

H - Hue (0 to 360)

The color wheel angle. 0 is red, 60 is yellow-orange, 120 is green, 240 is blue. Same concept as HSL's hue, but the perceptual uniformity of L and C means hue shifts don't cause unexpected brightness changes.

Practical Impact: Derived Colors

The real power of oklch shows up when you need to derive colors from a base value. Every design system needs hover states, focus rings, disabled variants, and dark mode alternatives. With HSL, generating these requires hand-tuning because the math doesn't match perception. With oklch, the math just works.

/* HSL: hover state is unpredictably bright */
.btn-hsl:hover {
  background: hsl(240, 80%, 55%);
  /* Looks too different from hsl(60, 80%, 55%) */
}

/* oklch: hover state is predictably lighter */
.btn-oklch:hover {
  background: color-mix(
    in oklch,
    var(--primary),
    white 15%
  );
  /* Looks consistently 15% lighter, any hue */
}

This is why Stride CSS defines every color in oklch and uses color-mix(in oklch, ...) for all derived states. The browser computes the color math natively. No preprocessor, no JavaScript, no color palette explosion.

@property and oklch Animations

CSS @property lets you register custom properties with a defined syntax. Combined with oklch, this unlocks smooth channel animations that are impossible with standard custom properties:

@property --hue {
  syntax: '<number>';
  inherits: false;
  initial-value: 60;
}

.element {
  background: oklch(0.7 0.15 var(--hue));
  transition: --hue 0.6s ease;
}

.element:hover {
  --hue: 280;
  /* Smooth hue rotation, no brightness jump */
}

In HSL, transitioning hue causes brightness flicker because different hues have different perceived brightness. In oklch, L stays constant while H rotates. The color shifts smoothly without visual artifacts.

Browser Support

oklch is supported in all modern browsers: Chrome 111+, Firefox 113+, Safari 15.4+, Edge 111+. As of March 2026, global support exceeds 95%. For the remaining edge cases, oklch gracefully falls back to the closest sRGB approximation.

The Bottom Line

oklch isn't just a better color notation. It's the foundation for building color systems that are mathematically coherent, perceptually accurate, and browser-native. If you're still defining colors in hex or HSL, you're leaving precision on the table.


See oklch in Action

Every color in Stride CSS is oklch-native. Explore the design system.

Explore Stride →

Get Early Access

Join the waitlist and be the first to try Gallop Builder.

No spam. Unsubscribe whenever.