Color plays a vital role in today’s web and also our daily life. And as technology progresses, new colors are born in modern displays, monitors, and we need a way to represent them in web too.
When it comes to creating or picking colors , developers often rely on design tools to reproduce these tokens. However, most of the time by choosing from classic RGB or even HSL can’t be sufficient sometimes.
CSS now can access colors outside of the sRGB gamut, so we’re going beyond to see alternative and potentially better colorspaces to represent those colors. While in this small journey you’ll see how to mix colors by using the new color-mix()
CSS function.
Jump to headingNew Colorspaces
Before we introduce some of the new colorspaces, you may be wonder why do need more ways to create colors?
Having more or less colors comes down to human color perception and is subjective to how we see things on the screen. A low or wide range of colors it is going to be determined by the gamut of a display and coordinated via the chromaticity space diagram of a colorspace.
Color space is a specific organization of colors. In combination with color profiling supported by various physical devices, it supports reproducible representations of color - Wikipedia
Color spaces arrange colors of a gamut in certain shapes, being some in 3D shapes like cubes (rgb) and others as cylinders (hsl).
We often apply colors in CSS in the so-called sRGB, used for the legacy rgb
, hex
, hsl
, and hwb
color functions. But there are way more possible colors that are capable of human eye seeing visible outside of these spectrums.
lch
- Device-independent representation that stands for CIE Lightness, Chroma and Hue. It allows for more precise control over the appearance of colors, especially when it comes to adjusting the lightness and saturation. More precise as per human perception.
lab
- Stands for Lightness, A (green-red axis) and B (blue-yellow axis) channels. The A and B axis represent unique axes of human color vision in values between ±160.
Both lch
and lab
formats are expressed under the CIELAB color space. A rectangular colorspace built on axis around lightness that can range from 0% to 100%.
oklch
- Practically an improvement around lch
with better chroma uniformity and linear lightness. You can essentialy use oklch
where lch
is being used. Checkout this awesome color picker by Evil Martians team: https://oklch.com/
oklab
- Corrective to LAB. It also improves linear lightness and hue uniformity compared to CIE LAB.
Any CIE space colors (lch, oklch, lab, oklab) are capable of representing the entire human visible color spectrum, but we can also explicit create colors from a specific color gamut.
The color()
function is normalized way to access colors within any RGB color spaces. This new function can be used for any color space that specifies colors with R, G and B channels.
High-definition displays can have much more amount of colors than standard sRGB in display-p3
and Rec2020
colorspaces.
They can also be used to create perceptually consistent gradients:
Jump to headingMixing two colors
Now that we have good grasp of these new color formats, let’s explore how we can mix them with color-mix()
.
color-mix()
is a CSS function that can take two colors and dynamically create adjusted color based on a mix of them in a given method (colorspace)
color-mix(in <colorspace> | <interpolation>, <color1> <n%>, <color2> <n%>)
Where the values can be:
- Colorspaces:
srgb
,srgb-linear
,lab
,oklab
,hsl
,hwb
,lch
,oklch
. - Interpolation method:
shorter
,longer
,increasing
,decreasing
. <n%>
: Percentage amount from 0% to 100%. Default to 50%.
.mix {
--color: color-mix(in srgb, yellow, red);
}
Jump to headingColor stops
The following example mixes 60% of blue and 40% yellow in lch
.
.mix {
--color: color-mix(in lch, lch(50 61 267) 60%, lch(81 95 80) 40%);
}
Jump to headingMixing colorspaces
You can mix color from different methods. Color interpolation can be from any of the colorspaces metioned like hsl to lch, lab to oklab, and the color-algorithm will do the calculation to interpolate them to a proximum value.
.mix {
--color: color-mix(in hsl, hsl(0 50% 50%), #7acedd);
}
Notice the suttle different tones of purple when switching between colorspaces. Behind the scenes both colors are converted to the given colorspace. Some methods may have a wide range of colors than others, thus represeting a distinct mixed color.
Jump to headingAlpha
There is a significant change when using alpha colors where colors have their components (chroma, lightness, hue) converted to rgb channels and premultiplied with three alpha values, one for each channel (red, green and blue).
Follow the example below where mixes 50% opaque red with 90% opaque green. Since the amount of both colors are ommited, the are both at 50%.
.mix {
--color: color-mix(in lab, lab(49 72.05 57.68 / 0.5), lab(84 -74.11 75.76 / 0.9));
}
Where the final computed color will be: color(srgb 0.936942 0.916944 0.0808208 / 0.7)
You can dive in the details of the calculation on the spec here.
Jump to headingHue inporlation
Finally, we can also tweak colors to short of wider angles of the color wheel.
/* Mixing with blue and white in short angle */
.mix {
--color: color-mix(in hsl shorter hue, hsl(240 100% 50%), hsl(0 100% 100%));
}
Previously, every example were mixing by connecting two hue values in a straight line. This is interesting because by opting for a longer route we’re able to get more vibrant hues in the result.
/* Mixing with blue and white in a longer angle */
.mix {
--color: color-mix(in hsl longer hue, hsl(240 100% 50%), hsl(0 100% 100%));
}
This is especially useful to create gradients without having “dead zones” in the middle.
Shorter:
Longer:
Whether if there is any “best” or go-to colorspace to use it all depends what you’re trying to achieve, accuracy and how much support you’re expecting from user’s devices. Test each one and see what you like the most!