Generative colors with CSS

I just updated the CSS for my website to use a fork of Kelp UI, which includes a much more consistent and easy-to-maintain class system than I had before.
Quick aside: if you see any bugs in your travels, please let me know!
While it mostly looks the same as before, the biggest change was to the color palette.
I’m now taking advantage of relative colors with the oklch() CSS function to dynamically generate all of the colors used on this site from just six hex codes defined as CSS variables.


This content originally appeared on Go Make Things and was authored by Go Make Things

I just updated the CSS for my website to use a fork of Kelp UI, which includes a much more consistent and easy-to-maintain class system than I had before.

Quick aside: if you see any bugs in your travels, please let me know!

While it mostly looks the same as before, the biggest change was to the color palette.

I’m now taking advantage of relative colors with the oklch() CSS function to dynamically generate all of the colors used on this site from just six hex codes defined as CSS variables.

Let’s look at how it all works!

The oklch() CSS function

The oklch() CSS function lets you create a color by defining its…

  • Lightness - the perceived brightness.
  • Chroma - the vibrancy or saturation of the color.
  • Hue - a number representing the color.

For example, the blue I use for this website, #007ab8, is represented in OKLCH as oklch(55.48% 0.131 241.70).

What makes the oklch() function so cool is that once you have a colors L, C, and H values, you can tweak the lightness and chroma slightly to create a full palette from your hue.

For example, I could create a slightly darker shade of that blue by reducing the lightness slightly: oklch(48% 0.131 241.70).

Note: there are other color functions besides oklch(), including rgb(), oklab(), and more. I find oklch() the easiest to work with.

Relative colors

Creating a palette of colors from oklch() by hand is tedious work, and I don’t recommend it.

This is where relative colors come in!

By passing the from operator followed by a color (as a hex value or another color function), the oklch() function will convert the color into l, c, and h values (with percentages represented as decimals) for you.

:root {
	--color-blue: oklch(from #007ab8 l c h);
}

Here, I’ve passed the generated variables along as-is without any changes.

But—this is where things get really powerful—you can manually override their values, and even use the calc() math function to adjust the values.

Let’s create a darker shade of blue by adjust the lightness (l) down 5% programmatically. I don’t care or need to know what the actual starting value is.

:root {
	--color-blue-darker: oklch(from #007ab8 calc(l - 0.05) c h);
}

A quick note about lightness and chroma

Very light and very dark lightness levels have a tendency to look oversaturated.

As a result, a lot of color palettes look more cohesive when you reduce the chroma slightly as you move away from the middle-range of lightness towards the edges.

Generating a whole palette

Let’s look at how we can use oklch() and a little bit of math to generate an 11-color palette from a single hex code.

First, we’ll define our color as a CSS variable.

:root {
  --color: #007ab7;
}

Next, we’ll create a range of named color variables, from --color-05 to --color-95.

For each one, we’ll generate the color from our --color variable. We’ll adjust the lightness (l), but keep the chroma (c) unchanged for now.

:root {
	--color: #007ab7;
	--color-05: oklch(from var(--color) 18.5% c h);
	--color-10: oklch(from var(--color) 24% c h);
	--color-20: oklch(from var(--color) 32.5% c h);
	--color-30: oklch(from var(--color) 40% c h);
	--color-40: oklch(from var(--color) 45% c h);
	--color-50: oklch(from var(--color) 57% c h);
	--color-60: oklch(from var(--color) 67% c h);
	--color-70: oklch(from var(--color) 75% c h);
	--color-80: oklch(from var(--color) 83.5% c h);
	--color-90: oklch(from var(--color) 92% c h);
	--color-95: oklch(from var(--color) 96% c h);
}

Here’s a demo of what the palette looks like.

Adjusting the chroma

You may notice that the lightest shades are still pretty vibrant. If you were using this as muted background colors, they might be a bit too intense.

To fix that, we’ll use the calc() function and a little math to adjust the chroma down a bit near the edges of our palette.

After some trial-and-error, I found a range of percentages I like to adjust the chroma by at each step in the palette. To make the math work, I divide the chroma (c) by 0.2, then multiply it by the percentage.

Why divide by 0.2? In OKLCH, 0.4 represents 100% saturation. It’s rare for a color to have that level of saturation. Using 50% saturation gives you a could baseline for the rest of the math.

:root {
	--color: #007ab7;
	--color-05: oklch(from var(--color) 18.5% calc(0.08 * (c / .2)) h);
	--color-10: oklch(from var(--color) 24% calc(0.1 * (c / .2)) h);
	--color-20: oklch(from var(--color) 32.5% calc(0.135 * (c / .2)) h);
	--color-30: oklch(from var(--color) 40% calc(0.16 * (c / .2)) h);
	--color-40: oklch(from var(--color) 45% calc(0.185 * (c / .2)) h);
	--color-50: oklch(from var(--color) 57% calc(0.2 * (c / .2)) h);
	--color-60: oklch(from var(--color) 67% calc(0.175 * (c / .2)) h);
	--color-70: oklch(from var(--color) 75% calc(0.13 * (c / .2)) h);
	--color-80: oklch(from var(--color) 83.5% calc(0.085 * (c / .2)) h);
	--color-90: oklch(from var(--color) 92% calc(0.04 * (c / .2)) h);
	--color-95: oklch(from var(--color) 96% calc(0.02 * (c / .2)) h);
}

Here’s what the palette looks like with the chroma adjusted.

Notice how the palette is more subdued, especially at the lightest and darkest shades.

Manual chroma override

Sometimes, the chroma of a color you’ve picked is just too muted or too vibrant and doesn’t work well. I wanted a way to manually adjust it up or down without having to find a better hex value.

To support that, I updated the calc() function for the chroma to use a --chroma variable as its starting point.

CSS variables let you pass in a fallback value. I use c / .2 as the default, and --chroma if one is defined.

The color blue I used, #007ab7, has a c / .2 value of about 0.65. Here, I’ve set --chroma to 0.95, making it substantially brighter or more vibrant.

:root {
	--color: #007ab7;
	--chroma: 0.95;
	--color-05: oklch(from var(--color) 18.5% calc(0.08 * var(--chroma, c / .2)) h);
	--color-10: oklch(from var(--color) 24% calc(0.1 * var(--chroma, c / .2)) h);
	--color-20: oklch(from var(--color) 32.5% calc(0.135 * var(--chroma, c / .2)) h);
	--color-30: oklch(from var(--color) 40% calc(0.16 * var(--chroma, c / .2)) h);
	--color-40: oklch(from var(--color) 45% calc(0.185 * var(--chroma, c / .2)) h);
	--color-50: oklch(from var(--color) 57% calc(0.2 * var(--chroma, c / .2)) h);
	--color-60: oklch(from var(--color) 67% calc(0.175 * var(--chroma, c / .2)) h);
	--color-70: oklch(from var(--color) 75% calc(0.13 * var(--chroma, c / .2)) h);
	--color-80: oklch(from var(--color) 83.5% calc(0.085 * var(--chroma, c / .2)) h);
	--color-90: oklch(from var(--color) 92% calc(0.04 * var(--chroma, c / .2)) h);
	--color-95: oklch(from var(--color) 96% calc(0.02 * var(--chroma, c / .2)) h);
}

Here’s what the palette looks like with the manual --chroma override.

Feel free to play around with the --chroma value, or even remove it altogether, and see how the color palette changes in response.

CSS is programming language

I hope this article makes it pretty clear that CSS is in fact a programming language, and can lots of really cool stuff that used to require JS or hand-coding.

This one update has made working with colors so much easier, and I’m eager to bring it to Kelp soon.

Like this? A Lean Web Club membership is the best way to support my work and help me create more free content.


This content originally appeared on Go Make Things and was authored by Go Make Things


Print Share Comment Cite Upload Translate Updates
APA

Go Make Things | Sciencx (2026-04-29T14:30:00+00:00) Generative colors with CSS. Retrieved from https://www.scien.cx/2026/04/29/generative-colors-with-css/

MLA
" » Generative colors with CSS." Go Make Things | Sciencx - Wednesday April 29, 2026, https://www.scien.cx/2026/04/29/generative-colors-with-css/
HARVARD
Go Make Things | Sciencx Wednesday April 29, 2026 » Generative colors with CSS., viewed ,<https://www.scien.cx/2026/04/29/generative-colors-with-css/>
VANCOUVER
Go Make Things | Sciencx - » Generative colors with CSS. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2026/04/29/generative-colors-with-css/
CHICAGO
" » Generative colors with CSS." Go Make Things | Sciencx - Accessed . https://www.scien.cx/2026/04/29/generative-colors-with-css/
IEEE
" » Generative colors with CSS." Go Make Things | Sciencx [Online]. Available: https://www.scien.cx/2026/04/29/generative-colors-with-css/. [Accessed: ]
rf:citation
» Generative colors with CSS | Go Make Things | Sciencx | https://www.scien.cx/2026/04/29/generative-colors-with-css/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.