oklch()

Gabriel Shoyombo on

Get affordable and hassle-free WordPress hosting plans with Cloudways — start your free trial today.

The CSS oklch() function brings a fresh approach to defining colors located in the Oklab color space. It specifies colors with three components — Lightness (L), Chroma (C), and Hue (H) — offering a perceptually uniform system, which is a fancy way of saying that it is closely aligned with how humans perceive color. Unlike other color functions based on the sRGB color space, like rgb() and hsl(), the oklch() function taps into a wider range of colors, making it a game-changer for web developers aiming for precise and vibrant colors.

This function is part of the CSS Color Module Level 4 specification and promises better gradients, intuitive adjustments, and compatibility with modern displays.

Syntax

The oklch() function uses a space-separated list to define its values, similar to lab() and lch(). Here’s the breakdown:

oklch( [<percentage> | <number> | none]
       [ <number> | none]
       [ <hue> | none]
       [ / [<alpha-value> | none] ]?
)

Arguments

  • Lightness (L): Controls how “light” the color is, ranging from 0% (fully black) to 100% (fully white). It can also be a decimal value between 0 to 1 (e.g. .7).
  • Chroma (C): Defines the vividness or “pureness” of the color a lot like saturation. It is a unitless number typically ranging from 0 (muted) to about 0.5 (vibrant), though it can be higher.
  • Hue (H): Specifies a color along the color wheel expressed in degrees, from 0deg (red) to 360deg (back to red). The hue is cyclic which means that 360deg loops back to 0deg. In other words, instead of going to 361deg, the value cycles back and equals 1deg.
  • Alpha transparency (optional): Sets transparency either as a decimal value between 0 to 1 (e.g. .7), or a percentage between 0% and 100%.
/* A soft blue */
color: oklch(70% 0.15 240);

/* A vibrant purple with transparency */
color: oklch(60% 0.2 280 / 75%);

/* Using numbers instead of percentages */
color: oklch(0.7 0.15 240);

/* No chroma for a grayscale tone */
color: oklch(50% 0 0);

Understanding oklch()

Here’s why it stands out:

  • Perceptual uniformity: Changes in values match how your eye perceives shifts—no surprise gray zones like in sRGB gradients.
  • Wider gamut: It supports P3 colors, unlocking vibrant shades modern screens can display (think newer Apple devices).
  • Intuitive controls: Hue picks the color, chroma sets its intensity, and lightness adjusts the brightness.

Think of it as a 3D color cylinder: lightness moves up and down, chroma stretches outward from the center, and hue spins around the wheel. Compared to rgb()’s sRGB constraints or hsl()’s uneven brightness, oklch() offers a richer, more predictable palette.

OKLCH pros and cons

oklch() builds on the scientific foundation of CIE Lab while addressing many of its limitations. While other color functions like rgb() and hsl() suffer from perpetual uniformity, oklch() aligns with human vision.

The key improvements in OKLCH over other color functions include:

  • Large range of colors: Also, wide-gamut Display P3 colors are compatible with it. For example, newer devices (like Apple products) can display more colors than older sRGB monitors, and these new colors can be specified, thanks to OKLCH.
  • Perceptual lightness: OKLCH is superior to hsl() and lch() for color changes and palette creation. It’s the consistent range of saturation in HSL that leads to inconsistent levels of lightness between colors. That’s not the case with OKLCH, which measures lightness authentically by varying levels of chroma (which is like saturation).
  • Better accessibility: It offers superior accessibility due to its consistent lightness. It is legible by humans, in contrast to rgb() or hexadecimal color value (e.g. #ca0000). Just by looking at the numbers, you may quickly and readily determine which hue an OKLCH value represents.
  • Web compatibility: OKLCH is supported in modern browsers with CSS Color Module Level 4, making it practical for web development.

oklch() vs lch()

Both oklch() and lch() are polar color functions in CSS, using Lightness, Chroma, and Hue to define colors. They sound similar, but they’re built on different foundations—oklch() lives in the Oklab color gamut, while lch() relies on CIELAB. Here’s how they stack up:

oklch()lch()
Color gamutWorks in Oklab, a modern color gamut designed for better perceptual uniformity that can access more color through today’s displays.Based on CIELAB, an older standard from 1976, widely used in color science but less optimized for web needs.
Perceptual accuracyChanges in values (e.g., Lightness from 70% to 50%) match how your eye sees them—gradients stay clean, with no surprise grays.Aims for uniformity but stumbles, especially in blues, where shifts can look uneven or exaggerated.
ChromaChroma (0 to ~0.5 in practice) is tuned for real screens, supporting wide-gamut Display P3 colors without overreaching.Chroma (0 to ~150) can get wilder, but this often leads to out-of-gamut colors that don’t display consistently.
HueHue spacing is even, making transitions (e.g., blue at 240deg to red at 0deg) smooth and predictable.Hue can feel cramped in some regions (like purples), thanks to CIELAB’s quirks.
Use casesPerfect for web design, as it is intuitive, display-friendly, and gradient-ready. Think oklch(70% 0.15 240) for a soft blue that you can easily tweak.Better for niche cases tied to CIELAB’s legacy, but less practical for everyday CSS (e.g., lch(70 30 240) might overshoot your monitor’s range).

Let’s look at a quick example comparing the two:

.gradient-oklch {
  background: linear-gradient(to right, oklch(70% 0.15 240), oklch(70% 0.15 0));
}

.gradient-lch {
  background: linear-gradient(to right, lch(70 30 240), lch(70 30 0));
}
  • oklch(): A smooth blue-to-red shift, no fuss.
  • lch(): Vibrant but riskier—some colors might not render as expected.

Basic usage

Now that we have seen why OKLCH is a game-changer, let’s get our hands on it to get a feel for how it works. Using oklch() is as straightforward as any CSS color function. It works anywhere a color value is accepted, including backgrounds, text, borders, you name it. Here’s a quick example that sets a background-color:

.button {
  background-color: oklch(70% 0.15 240); /* Soft blue */

  &:hover {
    background-color: oklch(70% 0.15 280); /* Shift to purple */
  }
}

Adjusting hue shifts the color naturally while keeping lightness and chroma steady ensures consistency. This is perfect for creating subtle hover effects or defining consistent color theme palettes.

Gradient example

Say goodbye to the “dead gray zone” in gradients:

.hero {
  background: linear-gradient(
    to right,
    oklch(70% 0.15 240), /* Light blue */
    oklch(50% 0.15 240)  /* Darker blue */
  );
}

The result? A smooth, vibrant transition where no unwanted grays sneak in.

Relative colors

oklch() supports CSS relative color syntax, letting you transform colors from other spaces:

.original {
  background-color: hsl(240deg 50% 70%);
}

.converted {
  background-color: oklch(from hsl(240deg 50% 70%) l c 280deg);
}

Use the from keyword followed by a color, then tweak l, c, or h (and alpha) to inherit and modify values. It’s a handy way to adapt existing palettes.

Math functions in oklch()

You can use calc() to dynamically adjust values:

.element {
  background-color: oklch(
    calc(var(--base-lightness) + 10%) 0.15 240 / 0.8
  );
}

Or tweak relative colors:

.element {
  background-color: oklch(from rgb(100, 149, 237) calc(l + 20%) c h);
}

This flexibility makes oklch() a powerhouse for dynamic designs.

Browser support

As of today, oklch() is supported in modern browsers like Chrome, Edge, Firefox, and Safari. This is great news — it is ready for prime time. But what about older browsers or stragglers that have not caught up?

CSS has your back with the @supports rule. Here is how to use it to provide a fallback (say, a basic RGB color) for browsers that don’t understand OKLCH:

.element {
  background-color: rgb(100, 149, 237); /* Fallback: cornflower blue */
}

@supports (color: oklch(0% 0 0)) {
  .element {
    background-color: oklch(70% 0.15 240); /* OKLCH soft blue */
  }
}

If the browser supports OKLCH, it’ll use the oklch() value; if not, it sticks with the RGB fallback. You can also explore polyfills like the postcss-oklab-function plugin for broader compatibility, though native support is strong enough now that fallbacks alone often suffice.

More information