Skip to main content

jul 21, 2024

🔗 Using new Oklch colors to remove dependencies

Whenever a new web-development feature is released and gradually makes its way into the most used browsers, it can bring excitement to developers. Not only because of the new possibilities it brings to our craft but also because it can help offload some of the work that had previously required dependencies, to the browser itself.

When I first built this blog, I used two libraries, hsluv/hsluv and gka/chroma.js to generate and interpolate colors. Their functioning was described in a previous blog post: A technique for generating beautiful color gradients. They did their job, but they were also dependencies that I had to carry along in the project, which it was in open contrast with the idea of a simple and lightweight blog.

In the last year, support for Oklch color notation has been added to the most used browsers, and it's a great opportunity to remove those dependencies.

# What is Oklch?

Oklch is a color notation that represents colors the same colors of the Oklab color space in a cylindrical color space. Its strength is that it is designed to be more perceptually uniform than other color spaces like RGB or HSL.

The Oklch color space is defined by three components:

  • Okl: is the perceived lightness (0%-100%). “Perceived” means that it has consistent lightness for our eyes, unlike in hsl()
  • Chroma: the colorfulness of the color, ranging from gray to the most saturated color.
  • Hue: the hue of the color, ranging from 0 to 360.

# What is changing

The structure and the logic of the code is remaining the same. I'm not going to need any library to generate colors anymore, I can pick a color from the Oklch space and interpolate it to generate a gradient.

Here it creates an array of hues to use as a base for the gradient colors, by remaining inside a given range on the hues spectrum:

const huesToPickFrom = new Array(Math.round(360 / minHueDiffAngle))
.fill("")
.map((_, i) => (baseHue + i * minHueDiffAngle) % 360);

and it then generates the final gradient colors by adding the chroma and lightness values:

return huesToPickFrom.map((hue, i) => ({
lightness:
minLightness + Math.random() * 0.1 + (lightnessRange / (colors - 1)) * i,
chroma: minChroma + Math.random() * (maxChroma - minChroma),
hue,
}));

If I want to further interpolate the colors with more step values I can use another recently added feature, the color-mix() function in CSS, which allows me to interpolate colors in a more controlled way.

scaleSpreadArray(
cssColorStops,
colorsFinal,
(percent, lastValue, nextValue) =>
`color-mix(in ${minIn}, ${nextValue} ${(percent * 100).toFixed(
2
)}
%, ${lastValue})`

);

# Resources