oklab()
Baseline 2023
Newly available
Since May 2023, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.
The oklab()
functional notation expresses a given color in the Oklab color space, which attempts to mimic how color is perceived by the human eye.
Oklab is a perceptual color space and is useful to:
- Transform an image to grayscale, without changing its lightness.
- Modify the saturation of colors, while keeping user perception of hue and lightness
- Create smooth and uniform gradients of colors (when interpolated manually, for example, in a
<canvas>
element).
oklab()
works with a Cartesian coordinate system on the Oklab color space — a- and b-axes. It can represent a wider range of colors than RGB, including wide-gamut and P3 colors. If you want a polar color system, chroma and hue, use oklch()
.
Syntax
/* Absolute values */
oklab(40.1% 0.1143 0.045);
oklab(59.69% 0.1007 0.1191);
oklab(59.69% 0.1007 0.1191 / 0.5);
/* Relative values */
oklab(from green l a b / 0.5)
oklab(from #0000FF calc(l + 0.1) a b / calc(alpha * 0.9))
oklab(from hsl(180 100% 50%) calc(l - 0.1) a b)
Values
Below are descriptions of the allowed values for both absolute and relative colors.
Absolute value syntax
oklab(L a b[ / A])
The parameters are as follows:
L
-
A
<number>
between0
and1
, a<percentage>
between0%
and100%
, or the keywordnone
(equivalent to0%
in this case). This value specifies the color's perceived lightness. The number0
corresponds to0%
(black) and the number1
corresponds to100%
(white). a
-
A
<number>
between-0.4
and0.4
, a<percentage>
between-100%
and100%
, or the keywordnone
(equivalent to0%
in this case). This value specifies the color's distance along thea
axis in the Oklab color space, which defines how green (moving towards-0.4
) or red (moving towards+0.4
) the color is. Note that these values are signed (allowing both positive and negative values) and theoretically unbounded, meaning that you can set values outside the±0.4
(±100%
) limits. In practice, values cannot exceed±0.5
. b
-
A
<number>
between-0.4
and0.4
, a<percentage>
between-100%
and100%
, or the keywordnone
(equivalent to0%
in this case). This value specifies the color's distance along theb
axis in the Oklab color space, which defines how blue (moving towards-0.4
) or yellow (moving towards+0.4
) the color is. Note that these values are signed (allowing both positive and negative values) and theoretically unbounded, meaning that you can set values outside the±0.4
(±100%
) limits. In practice, values cannot exceed±0.5
. A
Optional-
An
<alpha-value>
representing the alpha channel value of the color, where the number0
corresponds to0%
(fully transparent) and1
corresponds to100%
(fully opaque). Additionally, the keywordnone
can be used to explicitly specify no alpha channel. If theA
channel value is not explicitly specified, it defaults to 100%. If included, the value is preceded by a slash (/
).
Note:
See Missing color components for more information on the effect of none
.
Relative value syntax
oklab(from <color> L a b[ / A])
The parameters are as follows:
from <color>
-
The keyword
from
is always included when defining a relative color, followed by a<color>
value representing the origin color. This is the original color that the relative color is based on. The origin color can be any valid<color>
syntax, including another relative color. L
-
A
<number>
between0
and1
, a<percentage>
between0%
and100%
, or the keywordnone
(equivalent to0%
in this case). This value represents the lightness of the output color. The number0
corresponds to0%
(black) and the number1
corresponds to100%
(white). a
-
A
<number>
between-0.4
and0.4
, a<percentage>
between-100%
and100%
, or the keywordnone
(equivalent to0%
in this case). This value represents the output color's distance along thea
axis in the Oklab color space, which defines how green (moving towards-0.4
) or red (moving towards+0.4
) the color is. Note that these values are signed (allowing both positive and negative values) and theoretically unbounded, meaning that you can set values outside the±0.4
(±100%
) limits. In practice, values cannot exceed±0.5
. b
-
A
<number>
between-0.4
and0.4
, a<percentage>
between-100%
and100%
, or the keywordnone
(equivalent to0%
in this case). This value represents the output color's distance along theb
axis in the Oklab color space, which defines how blue (moving towards-0.4
) or yellow (moving towards+0.4
) the color is. Note that these values are signed (allowing both positive and negative values) and theoretically unbounded, meaning that you can set values outside the±0.4
(±100%
) limits. In practice, values cannot exceed±0.5
. A
Optional-
An
<alpha-value>
representing the alpha channel value of the output color, where the number0
corresponds to0%
(fully transparent) and1
corresponds to100%
(fully opaque). Additionally, the keywordnone
can be used to explicitly specify no alpha channel. If theA
channel value is not explicitly specified, it defaults to the alpha channel value of the origin color. If included, the value is preceded by a slash (/
).
Defining relative color output channel components
When using relative color syntax inside an oklab()
function, the browser converts the origin color into an equivalent Oklab color (if it is not already specified as such). The color defined as three distinct color channel values — l
(lightness), a
(green/red axis), and b
(blue/yellow axis) — plus an alpha channel value (alpha
). These channel values are made available inside the function to be used when defining the output color channel values:
- The
l
channel value is resolved to a<number>
between0
and1
, inclusive. - The
a
andb
channels are each resolved to a<number>
between-0.4
and0.4
, inclusive. - The
alpha
channel is resolved to a<number>
between0
and1
, inclusive.
When defining a relative color, the different channels of the output color can be expressed in several different ways. Below, we'll study some examples to illustrate these.
In the first two examples below, we are using relative color syntax. However, the first one outputs the same color as the origin color and the second one outputs a color not based on the origin color at all. They don't really create relative colors! You'd be unlikely to ever use these in a real codebase, and would probably just use an absolute color value instead. We included these examples as a starting point for learning about relative oklab()
syntax.
Let's start with an origin color of hsl(0 100% 50%)
(equivalent to red
). The following function outputs the same color as the origin color — it uses the origin color's l
, a
, and b
channel values (0.627966
, 0.22488
, and 0.125859
) as the output channel values:
oklab(from hsl(0 100% 50%) l a b)
This function's output color is oklab(0.627966 0.22488 0.125859)
.
The next function uses absolute values for the output color's channel values, outputting a completely different color not based on the origin color:
oklab(from hsl(0 100% 50%) 42.1% 0.165 -0.101)
In the above case, the output color is oklab(0.421 0.165 -0.101)
.
The following function creates a relative color based on the origin color:
oklab(from hsl(0 100% 50%) l -0.3 b)
This example:
- Converts the
hsl()
origin color to an equivalentoklab()
color —oklab(0.627966 0.22488 0.125859)
. - Sets the
L
andb
channel values for the output color to those of the originoklab()
equivalent'sL
andb
channel values — those values are0.627966
and0.125859
, respectively. - Sets the output color's
a
channel value to a new value not based on the origin color:-0.3
.
The final output color is oklab(0.627966 -0.3 0.125859)
.
Note: As mentioned above, if the output color is using a different color model to the origin color, the origin color is converted to the same model as the output color in the background so that it can be represented in a way that is compatible (i.e. using the same channels).
In the examples we've seen so far in this section, the alpha channels have not been explicitly specified for either the origin or output colors. When the output color alpha channel is not specified, it defaults to the same value as the origin color alpha channel. When the origin color alpha channel is not specified (and it is not a relative color), it defaults to 1
. Therefore, the origin and output alpha channel values are 1
for the above examples.
Let's look at some examples that specify origin and output alpha channel values. The first one specifies the output alpha channel value as being the same as the origin alpha channel value, whereas the second one specifies a different output alpha channel value, unrelated to the origin alpha channel value.
oklab(from hsl(0 100% 50% / 0.8) l a b / alpha)
/* Computed output color: oklab(0.627966 0.22488 0.125859 / 0.8) */
oklab(from hsl(0 100% 50% / 0.8) l a b / 0.5)
/* Computed output color: oklab(0.627966 0.22488 0.125859 / 0.5) */
In the following example, the hsl()
origin color is again converted to the oklab()
equivalent — oklab(0.627966 0.22488 0.125859)
. calc()
calculations are applied to the L
, a
, b
, and A
values, resulting in an output color of oklab(0.827966 0.14488 -0.0741406 / 0.9)
:
oklab(from hsl(0 100% 50%) calc(l + 0.2) calc(a - 0.08) calc(b - 0.2) / calc(alpha - 0.1))
Note:
Because the origin color channel values are resolved to <number>
values, you have to add numbers to them when using them in calculations, even in cases where a channel would normally accept <percentage>
, <angle>
, or other value types. Adding a <percentage>
to a <number>
, for example, doesn't work.
Formal syntax
Examples
Adjusting lightness
The following example shows the effect of varying the lightness, a-axis, and b-axis values of the oklab()
function.
HTML
<div data-color="red-dark"></div>
<div data-color="red"></div>
<div data-color="red-light"></div>
<div data-color="green-dark"></div>
<div data-color="green"></div>
<div data-color="green-light"></div>
<div data-color="blue-dark"></div>
<div data-color="blue"></div>
<div data-color="blue-light"></div>
CSS
[data-color="red-dark"] {
background-color: oklab(0.05 0.4 0.4);
}
[data-color="red"] {
background-color: oklab(0.5 0.4 0.4);
}
[data-color="red-light"] {
background-color: oklab(0.95 0.4 0.4);
}
[data-color="green-dark"] {
background-color: oklab(5% -100% 0.4);
}
[data-color="green"] {
background-color: oklab(50% -100% 0.4);
}
[data-color="green-light"] {
background-color: oklab(95% -100% 0.4);
}
[data-color="blue-dark"] {
background-color: oklab(0.05 -0.3 -0.4);
}
[data-color="blue"] {
background-color: oklab(0.5 -0.3 -0.4);
}
[data-color="blue-light"] {
background-color: oklab(0.95 -0.3 -0.4);
}
Result
Adjusting opacity
The following example shows the effect of varying the A
(alpha) value of the oklab()
function.
The red
and red-alpha
elements overlap the #background-div
element to demonstrate the effect of opacity.
Giving the red-alpha
element an opacity of 0.4
makes it appear more transparent than the red
element.
HTML
<div id="background-div">
<div data-color="red"></div>
<div data-color="red-alpha"></div>
</div>
CSS
[data-color="red"] {
background-color: oklab(0.628 0.225 0.126);
}
[data-color="red-alpha"] {
background-color: oklab(0.628 0.225 0.126 / 0.4);
}
Result
Adjusting color axes
This example demonstrates the effects of setting the a
and b
values of the oklab()
function to the ends and midpoints of the a-axis and b-axis, respectively. The a-axis goes from green (-0.4
) to red (0.4
) and the b-axis goes from yellow (-0.4
) to blue (0.4
).
HTML
<div data-color="red-yellow"></div>
<div data-color="red-zero"></div>
<div data-color="red-blue"></div>
<div data-color="zero-yellow"></div>
<div data-color="zero-zero"></div>
<div data-color="zero-blue"></div>
<div data-color="green-yellow"></div>
<div data-color="green-zero"></div>
<div data-color="green-blue"></div>
CSS
Using the CSS background-color
property, we vary the a
and b
values of the oklab()
color function along the a-axis and b-axis, showing the effects of maximum, midpoint, and minimum values in each case.
/* a-axis max, variable b-axis */
[data-color="red-yellow"] {
background-color: oklab(0.5 0.4 0.4);
}
[data-color="red-zero"] {
background-color: oklab(0.5 0.4 0);
}
[data-color="red-blue"] {
background-color: oklab(0.5 0.4 -0.4);
}
/* a-axis center, variable b-axis */
[data-color="zero-yellow"] {
background-color: oklab(0.5 0 0.4);
}
[data-color="zero-zero"] {
background-color: oklab(0.5 0 0);
}
[data-color="zero-blue"] {
background-color: oklab(0.5 0 -0.4);
}
/* a-axis min, variable b-axis */
[data-color="green-yellow"] {
background-color: oklab(0.5 -0.4 0.4);
}
[data-color="green-zero"] {
background-color: oklab(0.5 -0.4 0);
}
[data-color="green-blue"] {
background-color: oklab(0.5 -0.4 -0.4);
}
Result
The left column is at the yellow end (-0.4
) of the b-axis and the right column is at the blue end (0.4
). The top row displays colors at the red end of the a-axis (-0.4
) and the bottom row is at the green end (0.4
). The middle column and row are at the midpoints of each axis, with the middle cell being grey; it contains no red, green, yellow, or blue, with a 0
value for both axes.
Linear gradients along the a-axis and b-axis
This example includes linear gradients to demonstrate the progression of values of the oklab()
function along the a-axis (from red to green) and along the b-axis (from yellow to blue). In each gradient image, one axis remains static while the other axis progresses from low to high values.
CSS
/* a-axis gradients */
[data-color="red-to-green-yellow"] {
background-image: linear-gradient(to right, oklab(50% 0.4 0.4), oklab(50% -0.4 0.4));
}
[data-color="red-to-green-zero"] {
background-image: linear-gradient(to right, oklab(50% 0.4 0), oklab(50% -0.4 0));
}
[data-color="red-to-green-blue"] {
background-image: linear-gradient(to right, oklab(50% 0.4 -0.4), oklab(50% -0.4 -0.4));
}
/* b-axis gradients */
[data-color="yellow-to-blue-red"] {
background-image: linear-gradient(to right, oklab(50% 0.4 0.4), oklab(50% 0.4 -0.4));
}
[data-color="yellow-to-blue-zero"] {
background-image: linear-gradient(to right, oklab(50% 0 0.4), oklab(50% 0 -0.4));
}
[data-color="yellow-to-blue-green"] {
background-image: linear-gradient(to right, oklab(50% -0.4 0.4),oklab(50% -0.4 -0.4));
}
Result
Using relative colors with oklab()
This example styles three <div>
elements with different background colors. The middle one is given the unmodified --base-color
, while the left and right ones are given lightened and darkened variants of that --base-color
.
These variants are defined using relative colors — the --base-color
custom property is passed into an oklab()
function, and the output colors have their lightness channel modified to achieve the desired effect via a calc()
function. The lightened color has 0.15
(15%) added to the lightness channel, and the darkened color has 0.15
(15%) subtracted from the lightness channel.
CSS
:root {
--base-color: orange;
}
#one {
background-color: oklab(from var(--base-color) calc(l + 0.15) a b);
}
#two {
background-color: var(--base-color);
}
#three {
background-color: oklab(from var(--base-color) calc(l - 0.15) a b);
}
Result
The output is as follows:
Specifications
Specification |
---|
CSS Color Module Level 5 # relative-Oklab |
CSS Color Module Level 4 # ok-lab |
Browser compatibility
BCD tables only load in the browser
See also
- The
<color>
data type for a list of all color notations lab()
andoklch()
color functions- Using relative colors
- CSS colors module
- A perceptual color space for image processing on bottosson.github.io (2023)
- OKLAB color wheel on observablehq.com