Do you ever wonder why there are so many ways to declare the colours?
Some (long) while ago, I was reading posts about new colours, you know, those HSL, OKLCH, HWB, LAB, and LCH. Also, there is the Color() function as well as Relative colours.
That made me think - why? Why do we need all those different ways to declare the colour? For the last 15 years, I
have happily used RGB, RGBA, hex, or even by names like purple, orange or #bada55
. I have never had
any issues. Why all the fuss?
Until one day when I finally realised that.
Just a quick recap before we dive in.
OKCLH is designed to map colours in a way that aligns with how humans perceive them. Also, the values are much easier to play with than remembering hex or RGB().
L - Lightness (0% - 100%)
C - Chroma (Saturation) (0 - 0.37)
H - Hue (0 - 360)
a - optional opacity (0 - 1 or 0 - 100%)
It is worth mentioning that if you set two colours by using OKLCH with good accessibility value, then by changing Hue values, you will keep the same good accessibility ratio. That one benefit is already a fantastic win!
You can play with those values down the post and see how that accessibility works.
Anyway, back to the problem. I had a simple component or widget, if you like, with a Title, Description and Link. Something like this:
Lovely description for the component
There is not much there, but those simple snippets are many and assigned to categories, which have defined colour schemas, exactly like those backgrounds on the buttons below.
1 | |
2 | |
3 | |
4 | |
5 | |
So, my next thought is: how about I apply the same colour schema for the links? That way, I would make it easy to distinguish between different snippets.
This is where I realised that I’m in trouble. Suddenly, I need three colours:
Oh, did I mention that I also need something for a light/dark theme? That means I need six colours from one pre-defined colour.
Here is an example of what I would need to create with one colour:
This component uses Tools category colours for link
This component uses Tools category colours for link
So, the Tools category uses --pastel-rose: #FFA3B6;
colour, and I would need to create six colours
from that colour. There are three colours for each theme and 10 categories. That's like 60 colours to define in
variables and reuse. It feels wrong.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
While I was tinkering with the problem (well, actually randomly browsing blueSky) I stumbled upon Ahmad Shadeed's
post on relative colours: CSS relative colors.
This, in turn, led me to the post from Evil Martians: OKLCH in CSS, and that's when I
realised I wanted to rewrite all the colours in my blog to use OKLCH
(someday).
Once I realised the power of OKLCH
and relative
colours
, the answer is simple.
I can take one colour and create multiple colours in turn. Actually, I can take any colour and reuse that colour to create corresponding colours in CSS. Simple.
In my case, each snippet loops through the config file and gets assigned a colour. Instead of assigning colour
directly like color: var(--pastel-orange)
, I assign a new variable to hold the current snippets
colour value, like this <a style="--link-color: var(--pastel-orange)">link here</a>
This is important. Instead of assigning a colour to the link, I assigned a variable with the current colour. Because of that, I can get this value and use it in the CSS later! Very nifty!
Now, the magical part in CSS:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
If you freak out when looking at this code, that's normal. But let's go step by step. Honestly, it is all very simple.
Let's look at line 3: background: oklch(from var(--link-color) l c h / 0.6);
I assign background colour and use relative colour oklch
I created that colour from var(--link-color)
which I assigned to the element. Remember this line:
<a style="--link-color: var(--pastel-orange)">link here</a>
so, I assign var(--pastel-orange
to --link-color
and use it in oklch
.
The oklch
has three values Lightness, Chroma, Hue, and the last value (0.6) is opacity. Basically, I
take --link-color
and pass it in relative color in the same way but with opacity 0.6. That's it.
For line 4
color: oklch(from var(--link-color) calc(l - 0.4) c h);
,
I change the lightness.
The value range for the lightness is from 0 to 0.37. When I create OKLCH, it simply assigns all values to the
respective channel. Then I use calc(l - 0.4)
to reduce lightness to my liking.
The beauty of this approach is that I do not need to know the exact colour; I can simply change one of the parameters, and it will adjust colour by lightness, hue, or opacity. You can't simply do that with RGB() or hex colours, well, apart from opacity.
I use exactly this approach in Bookmarks. Try to open the dev tools and inspect yourself.
{
background: oklch(90% 0.084 75);
}
Ok, you may be still not convinced, but let me give another example.
Imagine you have text and a background. You want the text to always be easy to read against the background and keep both colours similar to each other. How would you do it with RGB() or hex colours? You would need to declare every background and every prime colour for the text, right? I'm too lazy to do that, so here is how I would do it with oklch().
In the example below, I assign only one colour to the —-figure-main
and reuse it in both examples.
Always prominent text against a background
Here it is the same but with reverse colours.
Always prominent text against a background
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
Notice that the only thing I change is one parameter - hue
.
The rest is calculated in CSS
automatically while
keeping the colour ratio.
Here you have it! Finally, it clicked for me, and I can see fantastic opportunities to use OKLCH for design
systems and reuse one colour for dark/light themes with reversed lightning.
Also, since OKLCH works with how humans perceive colours, you can build better colour contrast designs and improve
accessibility with ease.
I bet I only scratched the surface of all the possibilities.
Let me know your thoughts on BlueSky or Mastodon.
P.S. This post was written by a human, and no AI was harmed in the process.