Skip to main content Accessibility Feedback

Generating colors with the CSS oklch() function

Did you know CSS is a programming language, actually?

A few weeks ago, I wrote about creating an accessible color palette using LCH. Today, I wanted to share how the CSS oklch() function makes that even easier!

Let’s dig in!

The CSS oklch() function

The CSS oklch() function is a CSS-based way to generate a color using the Oklab color space. You pass in the Lightness, Chroma, and Hue as arguments, and it generates the color.

This example generates a dark blue background from a base hue of 263, which translates to #004cff in hex.

I’m setting the lightness to 18.5%, and the chroma (how much color to include) to .1 or 10%.

.hero {
	background-color: oklch(18.5% .1 263);
	color: white;
}

You’ll notice the hue isn’t a hex code. It’s the hue value on a 360 degree color wheel.

Newer browsers support relative colors with oklch(), where you can pass in a hex value and the function will convert it into LCH for you so that you can modify it.

.hero {
	background-color: oklch(from #004cff 18.5% .1 h);
	color: white;
}

Creating a palette with oklch()

As I explained in my article on accessible color palettes, by adjusting the lightness and chroma, we can create a range of shades for a single color.

The oklch() function makes that even easier!

The original version of my theme builder for Kelp used JavaScript to generate a full suite of color variables from a hex value.

If you entered #0088cc, it would spit out something like this…

:root {

	--color-blue-base: #0088cc;
	--color-blue-05: #001432;
	--color-blue-10: #002149;
	--color-blue-20: #003671;
	--color-blue-30: #004b94;
	--color-blue-40: #005fb7;
	--color-blue-50: #007ee0;
	--color-blue-60: #009ef6;
	--color-blue-70: #59b7f9;
	--color-blue-80: #97d0fc;
	--color-blue-90: #cee9fd;
	--color-blue-95: #e7f4fe;

}

You would then need to copy/paste that into your customizations file.

But using oklch(), all we need is the hue for the hex code. CSS can handle the rest.

:root {

	--color-blue-base: #004cff;
	--color-blue-hue: 263.27;
	--color-blue-05: oklch(18.5% .08 var(--color-blue-hue));
	--color-blue-10: oklch(24% .1 var(--color-blue-hue));
	--color-blue-20: oklch(32.5% .135 var(--color-blue-hue));
	--color-blue-30: oklch(40% .16 var(--color-blue-hue));
	--color-blue-40: oklch(47% .185 var(--color-blue-hue));
	--color-blue-50: oklch(57% .2 var(--color-blue-hue));
	--color-blue-60: oklch(67% .175 var(--color-blue-hue));
	--color-blue-70: oklch(75% .13 var(--color-blue-hue));
	--color-blue-80: oklch(83.5% .085 var(--color-blue-hue));
	--color-blue-90: oklch(92% .04 var(--color-blue-hue));
	--color-blue-95: oklch(96% .02 var(--color-blue-hue));

}

If you wanted to change the color, all you need to do now is update the --color-blue-hue variable, and oklch() handles the rest.

(The --color-blue-base variable is there for reference only.)

:root {
	--color-blue-base: #0088cc;
	--color-blue-hue: 241.55;
}

I’ve already update the Kelp Theme Builder to use this approach.

Adjusting brightness/saturation

One other aspect of color is how saturated it is. The same hue looks a lot more muted with the chroma turned down, and looks a lot more vibrant with it turned up.

CSS can handle this for us, too!

If we set a --color-*-chroma variable, we can combine it with the CSS calc() function to do math for us and adjust the chroma up or down.

I include a default value of 1

:root {

	--color-blue-base: #004cff;
	--color-blue-hue: 263.27;
	--color-blue-chroma: 1;

}

And multiply the default chroma value by it in the CSS.

:root {

	--color-blue-05: oklch(18.5% calc(.08 * var(--color-blue-chroma)) var(--color-blue-hue));
	--color-blue-10: oklch(24% calc(.1 * var(--color-blue-chroma)) var(--color-blue-hue));
	--color-blue-20: oklch(32.5% calc(.135 * var(--color-blue-chroma)) var(--color-blue-hue));
	--color-blue-30: oklch(40% calc(.16 * var(--color-blue-chroma)) var(--color-blue-hue));
	--color-blue-40: oklch(47% calc(.185 * var(--color-blue-chroma)) var(--color-blue-hue));
	--color-blue-50: oklch(57% calc(.2 * var(--color-blue-chroma)) var(--color-blue-hue));
	--color-blue-60: oklch(67% calc(.175 * var(--color-blue-chroma)) var(--color-blue-hue));
	--color-blue-70: oklch(75% calc(.13 * var(--color-blue-chroma)) var(--color-blue-hue));
	--color-blue-80: oklch(83.5% calc(.085 * var(--color-blue-chroma)) var(--color-blue-hue));
	--color-blue-90: oklch(92% calc(.04 * var(--color-blue-chroma)) var(--color-blue-hue));
	--color-blue-95: oklch(96% calc(.02 * var(--color-blue-chroma)) var(--color-blue-hue));

}

If you adjust --color-blue-chroma, you’ll get a different color palette, without changing the hue.

:root {

	/* more muted */
	--color-blue-chroma: 0.5;

	/* more vibrant */
	--color-blue-chroma: 1.25;

}

You can play around with this in the Kelp Theme Builder right now.