As of last month, Firefox 128’s support of the relative color syntax means we’ve now got support across the board. I’m excited about that as it’s an extremely powerful way to manipulate colors in CSS. Plus it was part of Interop this year so that is further proof that is trucking along nicely.
The syntax with generic names looks like this:
color-function(from origin-color channel1 channel2 channel3 / alpha)
Code language: CSS (css)
Here’s how it works in my head:
Add Opacity to a Color you Already Have
It’s common to have CSS custom properties set up for colors on a project.
html {
--color-yellow: oklch(80% 0.15 94);
--color-green: oklch(70% 0.25 140);
...
}
Code language: CSS (css)
Now you want to use that yellow, but at about 50% opacity. How do you do that? There are actually a couple of ways to add transparency to an existing color, but in my opinion the relative color syntax is the nicest.
In the past, I’ve split out the color values like this:
html {
--color-yellow-lch: 80% 0.15 94;
--color-yellow: oklch(var(--color-yellow-lch);
...
}
Code language: JavaScript (javascript)
That way I could either use the color all together, or use the split out values to apply opacity:
.box {
background: var(--color-yellow);
border-color: oklch(var(--color-yellow-lch) / 50%);
}
Code language: CSS (css)
But that can get out of hand! You could also split each color into L, C, and H, the combine those, giving you five variables for every color. Too much.
With the relative color syntax, breaking down colors isn’t necessary. You apply alpha (and other transformations) on demand, leaving the original single color as the only variable (token) you need.
.box {
background: var(--color-yellow);
border-color: oklch(from var(--color-yellow) l c h / 50%);
}
Code language: CSS (css)
I much prefer the idea of keeping the main colors tokenized as custom properties, then tweaking them as needed on demand.
Darken a Color you Already Have
In the above example, we had --color-yellow
and I ended by saying I prefer doing one-off tweaks on demand rather than making a whole new variable. If you have a ton of usage of a slightly-darker version of a color, then sure, make a new variable and stay consistent. But if it’s more of a one-off, relative color syntax is awesome:
.box {
background: var(--gray-5);
h2 {
color: var(--color-yellow);
/* Darkened version of yellow */
border-bottom: 2px solid oklch(from var(--color-yellow) calc(l - 0.4) c h);
}
}
Code language: JavaScript (javascript)
Lighten a Color you Already Have
Same deal here. I’m using OKLCH because I like it, particularly the “uniform brightness” characteristic. Meaning when doing this darkening and lightening across different colors, it feels like it lightens/darkens the same amount. Which feels weird to write, but it’s true. Other color spaces do not lighten and darken consistently.
.box {
background: var(--gray-5);
h2 {
color: var(--color-orange);
/* Darkened version of orange */
border-bottom: 2px solid oklch(from var(--color-orange) calc(l + 0.4) c h);
}
}
Code language: JavaScript (javascript)
Easy Variations
Avoiding making too many variables is a nice consequence of the relative color syntax, but you can still use the relative color syntax to make variables if it’s useful to have them.
I like the idea of starting with a base color, perhaps a slightly tinted gray, and then making the official variations with the relative color syntax.
html {
--base-gray: oklch(12.94% 0.02 159);
--gray-1: var(--base-gray);
--gray-2: oklch(from var(--base-gray) calc(l + 0.1) c h);
--gray-3: oklch(from var(--base-gray) calc(l + 0.2) c h);
--gray-4: oklch(from var(--base-gray) calc(l + 0.3) c h);
--gray-5: oklch(from var(--base-gray) calc(l + 0.4) c h);
--gray-6: oklch(from var(--base-gray) calc(l + 0.5) c h);
--gray-7: oklch(from var(--base-gray) calc(l + 0.6) c h);
--gray-8: oklch(from var(--base-gray) calc(l + 0.7) c h);
}
Code language: CSS (css)
The fact that you can start with any color, use any color function, and manipulate any part of the color is incredibly powerful. The above use cases are pretty basic. I’m sure more talented designers or developers who deeply know color will be able to do much more interesting things!
The most interesting part in my opinion, because it would theoretically allow creating complete color palettes depending on the users preferences utilizing the system colors like AccentColor or Highlight. Like Material You for the web – especially if the website doesn’t have an own strong brand color.
A pity, but it seems like no browser does currently support the relative color syntax in combination with system colors (yet).
Unfortunate that the MDN docs botch this syntax, such as in this evidently non-working example:
background-color:
color(from var(–base-color) hsl h s l);
Glad I found this page so I can modify my code correctly!