Get affordable and hassle-free WordPress hosting plans with Cloudways — start your free trial today.
The oklab()
function represents colors in the OKLab color space. OKLab is an “OK” and even better version of the lab color space. It displays colors according to their lightness, red/green axis, blue/yellow axis, and an optional alpha transparency value. Unlike lab()
, we can change its position on any color axis without affecting its perceived lightness.
.element {
color: oklab(25.77% 25.77% 54.88% / 0.5);
}
The oklab()
color function is defined in the CSS Color Module Level 4 and Level 5 specifications. The OKLab color space was created by Björn Ottosson to solve the limitations of CIELAB and CIELCH color space.
Syntax
oklab()
can only be written as a space-separated list, so use spaces, not commas.
oklab( [<percentage> | <number> | none]
[ <percentage> | <number> | none]
[ <percentage> | <number> | none]
[ / [<alpha-value> | none] ]? )
<alpha-value> = <number> | <percentage>
Arguments
/* Integer and decimal values ranging from 0 - 1 for l, and -0.4 - 0.4 for a and b */
.element {
color: oklab(0.013 0.1456 -0.34);
}
/* Percentages ranging from 0% - 100% */
.element {
color: oklab(45% 15% 25%);
}
/* `none` can be specified for any channel */
.element {
color: oklab(20% none none);
}
/* Optional decimal value for transparency */
.element {
color: oklab(0 0 0 / 0.2);
}
/* Optional percentage value for transparency */
.element {
color: oklab(0 0 0 / 20%);
}
/* Using relative colors */
.element {
color: oklab(from green 0.5 a b / 0.2);
}
l
value: Represents the perceived lightness and ranges from0%
or0.0
to100%
or1.0
. Sincel
represents the lightness,0%
adds more black and100%
more white.a
value: It takes both positive and negative values from-0.4
to0.4
or-100%
to100%
. Thea
value represents the color’s red/green axis, setting the amount of green (-0.4
/-100%
) or red (0.4
/100%
) contained in the color.b
value: It takes both positive and negative values from-0.4
to0.4
or-100%
to100%
. Theb
value represents the color’s position in the blue/yellow axis, setting the amount of blue (-0.4
/-100%
) or yellow (0.4
/100%
) contained in the color.<alpha-value>
: Sets the transparency and can be any decimal value between0
to1.0
(e.g.0.8
) or any percentage from0%
and100%
.
oklab()
Understanding You can think of each channel in CSS oklab()
function as an axis between two colors, moving from one side to another to get more or less of that color. For example, we can imagine l
as an axis between white and black, where 0
adds more black and 100
adds more white. The a
channel does the same with an axis going from green (-0.4
) to red (0.4
), while b
goes from blue (-0.4
) to yellow (0.4
).
It’s odd at first how l
goes from 0.0
to 1.0
while the rest of the axes go to 0.4
and even have negative values. Remember, though, that l
also represents lightness, where 0
is the absence of light, and we can’t go below that. So, it ends up making sense.
The
l
value is generally considered to be achromatic (without any color, including black, white, or gray), whilea
andb
are considered to be chromatic (with color, so no hint of black, white, or gray).
So, if we have three axes, we can then imagine a 3D plane of color that we can navigate using oklab()
:

OKlab was created by Björn Ottosson to solve issues related to image processing in lab()
such as making an image grayscale. It also does a good job of predicting perceived lightness, chroma, and hue. The full details of the issues it solves and the calculations involved in how this works are fully explained in Björn’s post on his color space.
Another major issue this solves is the inconsistency in perceptual uniformity lab()
and lch()
have when making them in gradients. And to understand what I mean when I say “perceptual uniformity”, I think Theresa-Marie explains it well:
“A color space is perceptually uniform if a change of length in any direction X of the color space is perceived by a human as the same change. A non-uniform perceptual colormap can have stark contrasts when transitioning from one hue to another hue.”
A good example of a pictorial description of this is from Eric Portis’ blog on OKLab color representation:

That’s the basic gist of it, as well as other problems like increasing the saturation of colors in lab(), while maintaining their perceived hue and lightness. In short, if you’re looking for a better color space with perceptual uniformity, use oklab()
.
Basic usage
To recap, oklab()
has three main arguments in a space-separated list. First, l
sets the lightness ranging from 0.0
to 1.0
, then a
sets the value in the greenness-to-redness axis from -0.4
to 0.4
, and lastly b
does the same with the blueness-to-yellowness axes from -0.4
to 0.4
. And if you need to change the color’s transparency, we can write a slash (/
) followed by the transparency value formatted as a decimal between 0
to 1
, or as a percentage between 0%
and 100%
.
It can be used in the same places you use your rgb()
or hsl()
functions, meaning any CSS property that accepts a color value:
.element {
color: oklab(0.05 0.1 0.2 / 0.4);
}
This color function is ideal if you’re looking to represent or select colors that are not available in rgb()
or hsl()
and for accessing a color space with better color perceptual uniformity. In other words, if you are attempting to use a color that falls outside the range of what is offered in the sRGB color space and has better perceptual uniformity than what is offered in the CIELAB color space, then try using oklab()
for access to a wider range of colors and consistency in color value change when using gradients.
Even though the color space is supposed to solve the known issues in LAB in regards to its color space properties, it also shares a similar problem with LAB, and that is readability and understanding what the values would mean since the values are in super small decimals. I advise sticking with percentages as I think they are easier to read than the raw decimals, starting with zero if you plan on using the CSS oklab()
color function.
In essence:
/* Easier to read */
.element {
color: oklab(60.55% 40.55% 10.55%);
}
/* Too many decimal points */
.element {
color: oklab(0.6055 0.1622 0.0422); /* Same value */
}
Relative colors
The CSS oklab()
function supports the relative color syntax, which means it can be used to convert a color from one color space into another color in another color space.
.element {
color: oklab(from hsl(25% 55% 20%) l a -0.2);
}
You need to include the from
keyword followed by any color (it can be another color function or a named color), then replace any of its values with its corresponding channel letter (in this case, l
for lightness, a
for the red/green axis, b
for the blue/yellow axis, and the optional alpha
for the alpha value), and they will take on the value from the original color.
A quick demo below shows the colors produced by rgb()
inside lab()
:
.element {
background-color: oklab(from rgb(170, 70, 120) l a b);
}
It also works the other way around. We can translate lab()
, which operates in the OKLab color space, to the sRGB color space to be used by sRGB-based functions rgb()
, hsl()
or hwb()
oklab()
Color gradient with Colors created with oklab()
usually look more beautiful and vibrant, exploding with color and representing corners of the OKLab color space that hsl()
and rgb()
could ever dream of. One specific case further proves this: gradients.
Without getting too detailed, let’s make two two-color gradients from colors in the sRGB color space using rgb()
and hsl()
and compare it to a two-color gradient using colors from the OKLab color space using the oklab()
function:
See the difference? oklab()
is brighter and more vibrant than hsl()
and rgb()
. Some may even say they look “washed”, especially when passing through sRGB’s dead gray zone, which is caused by the lack of access to more color.
oklab()
Math functions can be used in You can use math functions in oklab()
to manipulate a color stored in a custom property:
.element {
background-color: oklab(
calc(var(--my-l-value) + 0.1) calc(var(--my-a-value) - 0.1) var(--my-b-value) / calc(var(--my-alpha-value) + 0.1)
);
}
It can even be used to change each channel after using the relative color syntax:
.element {
background-color: oklab(from hsl(30deg 50 10%) calc(l + 0.2) calc(a + 0.05) b);
}
In the example above, I’m using the calc()
function to add 0.2
more points to the l
channel and 0.05
more to the a
channel. The reason I’m adding such small values is that the upper and lower limits of the l
, a
, and b
channels are all in small decimals. Here’s what this looks like in the demo below:
Demos
Balloon pop with a twist!
I created a balloon pop game with OKLab and here’s how it works.
- Pop (or click) the balloons that correspond with the OKLab color code at the top
- Avoid clicking other balloons with a different OKLab color code
- If you lose, you get a chance to input the color for bonus points! If you get the OKLab color code format right, you get awarded 50 points, but if you get the OKLab color code format and the exact color code you last popped, you get awarded 150 points!
My highest was just a meager 260. Use this to know if you understand OKLab well enough while playing a game. 😀
If you are someone with a slight colorblindness, or simply using a screen that can’t represent that many colors, experiment with the demo below!
Conic gradient background change
Here’s a demo showing how the OKLab color function works with a conic gradient. Change the values to update the color scheme and see how each value influences the overall color:
Specification
The oklab()
function is defined in the CSS Color Module Level 4 specification, while the relative syntax using channel letters is defined in the CSS Color Module Level 5 specification. Both are currently in Editor’s Draft status at the time of writing. This means changes can still be made to this function in the future.
More information
- Okay, Color Spaces (Eric Portis)
- W3C Workshop on Wide Color Gamut and High Dynamic Range for the Web (Chris Lilley (W3C))
- A perceptual color space for image processing (Björn Ottosson)
- Color in a Perceptual Uniform Way (Theresa-Marie Rhyne)