The problem with HSL colors

Just a guy who loves to write code and watch anime.
Search for a command to run...

Just a guy who loves to write code and watch anime.
No comments yet. Be the first to comment.
Qualities that make outstanding builders.

Bipedal vs quadrupedal: how many legs This is about the number of legs the creature walks on. Bipedal. Two legs. Humans, ostriches, T-rex, kangaroos, most fantasy humanoids. Quadrupedal. Four legs. Do

Intro You hear "lerp" and "smoothstep" everywhere in game dev. They sound like math jargon. They're not. Both are small tools that do the same job: smoothly move from one value to another. The problem

What is Kinematics Kinematics is the math field. It's the study of how things move without worrying about forces (which would be dynamics). FK and IK are the two branches: forward kinematics and inver

Intro Textures are usually the biggest cost in a 3D scene. Memory, bandwidth, and load time all get eaten by them. Resizing them is the obvious lever. There's more. This post is about the less obvious

HSL has been standard for some time. OKLCH is a newer color space that's becoming popular.
I want to explore the issues with HSL and explain why OKLCH is better.
/* These HSL colors have equal lightness steps */
.color1 {
color: hsl(250, 100%, 20%);
}
.color2 {
color: hsl(250, 100%, 40%);
}
.color3 {
color: hsl(250, 100%, 60%);
}
But to your eye, the jump from 20% to 40% might look much bigger than 40% to 60%. HSL says they're equal steps, but your brain eyes disagrees.
/* These have the same lightness in HSL */
.yellow {
color: hsl(60, 100%, 50%);
} /* Yellow */
.blue {
color: hsl(240, 100%, 50%);
} /* Blue */
The yellow appears much brighter than the blue, even though HSL says they have the same lightness. This is because our eyes are more sensitive to yellow.
When you animate between colors in HSL:
.button {
background: hsl(0, 100%, 50%); /* Red */
transition: background 1s;
}
.button:hover {
background: hsl(240, 100%, 50%); /* Blue */
}
The transition might show unexpected dull colors because HSL changes colors in equal mathematical steps, not in steps that look equal to our eyes.
These problems exist because HSL was designed for computers to process colors easily, not for how humans actually see color.
OKLCH solves these issues by aligning with how our eyes see color differences, making transitions smoother and color relationships feel more natural.
Basic Structure: oklch(65% 0.3 250)
First number (65%): Lightness
Second number (0.3): Chroma (colorfulness)
Third number (250): Hue (color angle)
Range: 0-100%
0% = Black
100% = White
Perceptually uniform (50% looks like true middle gray to human eyes)
How colorful/saturated
Range: 0 to about 0.4
0 = Gray
Higher = More vivid
Maximum depends on the color and display capabilities
Color angle like HSL
0-360 degrees
Examples:
0 = Red
90 = Yellow
180 = Green
270 = Blue
Based on OKLAB color space
"OK" = Optimized Kánczos (named after researchers)
Designed around human perception studies
Mathematically optimized for how we see color
.button {
/* A vivid blue */
color: oklch(65% 0.3 250);
/* A pastel red */
color: oklch(80% 0.1 25);
/* A deep purple */
color: oklch(40% 0.2 300);
}
The key is that each change in these numbers matches how we actually see color changes with our eyes, not just how computers handle them.
You can also customize the opacity:
/* Two equivalent ways to write it: */
color: oklch(65% 0.3 250 / 0.5); /* With slash */
color: oklch(65% 0.3 250 / 50%); /* Can also use percentage */
/* You can also use the longer form: */
color: oklcha(65% 0.3 250 0.5); /* 'a' suffix like hsla */