2026年11月13日

2026年11月13日

CSS oklch() and oklab() in WordPress: Syntax, Palettes and Fallbacks

This article is a localized edition of the Japanese original. Read the Japanese original

The CSS functions oklch() and oklab() specify colors in a color space called OKLab. Unlike HEX values such as #0f74c5 or rgb(), they let you set "lightness", "vividness" and "hue" directly, on a scale close to how the human eye perceives them. This article covers how to read the values, how to use them in a WordPress theme or Additional CSS, how to build color steps, and how to provide fallbacks for older browsers.

oklch() syntax

color: oklch(0.55 0.15 250);         /* lightness chroma hue */
color: oklch(55% 0.15 250deg);       /* lightness can also be a percentage */
color: oklch(0.55 0.15 250 / 0.5);   /* the value after the slash is opacity */
Value Meaning Allowed range
L (lightness) Brightness. 0 is black, 1 is white 0 to 1 (a percentage also works)
C (chroma) Vividness. 0 is gray 0 or more. As a percentage it is relative to 0.4 (50% is 0.2)
H (hue) The hue angle A number or an angle (deg, etc.)
A (alpha) Written after a slash. Opaque if omitted 0 to 1 (a percentage also works)

Chroma has no theoretical upper limit, but the range of colors a screen can display is limited. If you push chroma too high, as in oklch(0.9 1 25), the browser converts it to a color within the displayable range, so you will not get the exact color you specified. For use within sRGB, aim for a chroma of roughly 0.1 to 0.2 and adjust while checking the result on screen.

Hue angles do not match those of hsl(). For example, at lightness 0.55 and chroma 0.15, hue 30 is a reddish brown, 140 is a green, and 250 is a blue.

How oklab() differs

oklab() describes the same color space with lightness L and two axes, a and b. The a axis runs from green to red, and b runs from blue to yellow.

color: oklab(0.55 -0.05 -0.14);

oklch() expresses those a and b values as "chroma" (distance from the center) and "hue" (angle). Adjustments such as changing only the lightness while keeping the hue, or rotating only the hue, are more intuitive with oklch(). For interpolating between two colors, oklab, which does not travel around the hue circle, can be the better fit (see the gradients section below).

Why use oklch()

In hsl(), the same lightness (L) value can look very different in brightness depending on the color. If you place yellow and blue side by side in hsl() with the same saturation and lightness, the yellow looks much brighter.

Lightness in oklch() is designed to be close to perceived brightness. As a result:

  • Changing only the hue tends to keep the impression of brightness consistent
  • Changing lightness in steps of 0.1 changes brightness by a similar amount for any color
  • It is easy to derive steps such as light background tints and dark text colors from a brand color numerically

These are what make it easy to work with.

However, writing colors with oklch() does not automatically give you enough contrast between text and background. This is explained in "Things to watch out for" below.

Browser support

oklch() and oklab() have worked in current versions of Chrome, Edge, Firefox and Safari since May 2023 (Baseline "Widely available" on MDN, as of October 2026). If visitors might arrive on older devices or browsers, add the fallbacks described in the next section.

Adding it to a WordPress theme

Where to write it

Method Where Good for
Additional CSS (classic themes) Appearance > Customize > Additional CSS Changing a few colors
Additional CSS (block themes) "Additional CSS" in the menu of "Styles" in Appearance > Editor (the Site Editor) Changing a few colors
Theme (child theme) CSS style.css or a CSS file you load Managing the whole color scheme in one place

If you edit a third-party theme directly, theme updates will overwrite your changes. When writing in theme files, use a child theme or your own theme.

Collecting colors in CSS variables

Define the color steps as CSS variables (custom properties) on :root, and use those variables on each element. This example uses hue 250 (blue) and builds steps with different lightness.

/* assets/css/colors.css */

/* 1. HEX values for browsers without support (the oklch values converted to sRGB) */
:root {
  --brand-50:  #ebf3fc;
  --brand-200: #acd2fb;
  --brand-400: #61a3e6;
  --brand-500: #0f74c5;
  --brand-700: #0e4f86;
  --brand-900: #0d2339;
}

/* 2. Override them in browsers that support oklch() */
@supports (color: oklch(0 0 0)) {
  :root {
    --brand-50:  oklch(0.96 0.015 250);
    --brand-200: oklch(0.85 0.07 250);
    --brand-400: oklch(0.70 0.12 250);
    --brand-500: oklch(0.55 0.15 250);
    --brand-700: oklch(0.42 0.11 250);
    --brand-900: oklch(0.25 0.05 250);
  }
}

/* 3. Elements only reference the variables */
a {
  color: var(--brand-700);
}

.wp-block-button__link {
  background-color: var(--brand-500);
  color: #fff;
}

.wp-block-button__link:hover {
  background-color: var(--brand-700);
}

.notice-box {
  background-color: var(--brand-50);
  border-left: 4px solid var(--brand-400);
  color: var(--brand-900);
}

The reason for @supports here is that browsers do not validate the contents of a CSS variable when it is declared. If you write --brand-500: oklch(…), even an unsupported browser defines the variable, and it only becomes invalid in the property that uses it. The result is not a fallback to the HEX value written earlier but a property with no color applied. If you write the color directly on a property instead of using a variable, simply declaring it twice is enough:

.site-header {
  background-color: #0e4f86;                /* browsers without support use this */
  background-color: oklch(0.42 0.11 250);   /* supporting browsers override with this */
}

To change the hue, change the last number (250) on each line. For example, 30 gives a reddish-brown scheme and 140 a green scheme, each with evenly matched lightness steps. Recalculate the HEX fallback for each color.

Loading the CSS file from your theme

In a child theme or your own theme, load the CSS file from functions.php. To show the same colors in the Block editor, also load it with add_editor_style().

<?php
// functions.php of the child theme
add_action( 'wp_enqueue_scripts', function () {
	wp_enqueue_style(
		'mytheme-colors',
		get_stylesheet_directory_uri() . '/assets/css/colors.css',
		array(),
		wp_get_theme()->get( 'Version' )
	);
} );

add_action( 'after_setup_theme', function () {
	add_theme_support( 'editor-styles' );
	add_editor_style( 'assets/css/colors.css' );
} );

get_stylesheet_directory_uri() returns the URL of the active theme (the child theme, if you use one). The path passed to add_editor_style() is relative to the theme folder.

Gradients and color mixing

oklch and oklab can also be specified as the interpolation method for gradients and color-mix().

/* interpolate in oklab (midpoints are less muddy) */
.hero {
  background-image: linear-gradient(#0f74c5, #b94739);
  background-image: linear-gradient(in oklab, #0f74c5, #b94739);
}

/* interpolate in oklch, going around the longer hue arc */
.rainbow {
  background-image: linear-gradient(in oklch longer hue to right, #0f74c5, #b94739);
}

/* mix 20% white into the brand color */
.soft {
  background-color: color-mix(in oklch, var(--brand-500), white 20%);
}

Browsers that do not understand an interpolation method such as in oklab ignore the whole declaration. As in the gradient example, writing a declaration without it first keeps something on screen. If you use color-mix() inside a CSS variable, switch with @supports.

Deriving colors by calculating lightness or chroma from an original color (syntax such as oklch(from var(--brand-500) calc(l - 0.1) c h)) is covered in How to use CSS relative color syntax in WordPress.

Things to watch out for

Check contrast separately

The contrast ratio between text and background (the WCAG measure) is calculated from relative luminance. That is a different calculation from oklch() lightness L, so colors with the same lightness can have different contrast ratios depending on hue.

Color Contrast ratio against a white background
oklch(0.55 0.15 30) (reddish brown) About 5.2:1
oklch(0.55 0.15 250) (blue) About 4.9:1
oklch(0.55 0.15 140) (green) About 4.6:1

The WCAG 2 success criteria (Level AA) require a contrast ratio of at least 4.5:1 for normal-size text. Lowering lightness only slightly can drop some combinations below that, so once you settle on a palette, check text and background combinations with a contrast checker.

Colors beyond the displayable range

Screens that support a wide gamut (such as Display P3) can show colors more vivid than sRGB, and oklch() can specify those colors. On sRGB screens, however, they are converted into the displayable range, so they look different from device to device. For colors that should look the same everywhere, such as a brand color, values inside the sRGB range (all the example values above are) give stable results.

Typos in variable names

If you mistype the variable name in var(--brand-500), the declaration becomes invalid and no color is applied. Select the element in your browser's developer tools and check that the expected color appears in the computed styles (Computed) to find the cause quickly.

Summary

  • oklch(L C H) specifies a color by lightness (0 to 1), chroma and hue. Too much chroma goes beyond the displayable range
  • Because lightness is close to perceived brightness, it is easy to keep color steps and hue variations consistent
  • As of October 2026, current versions of the major browsers support it. For older browsers, provide HEX fallbacks by declaring the property twice or with @supports
  • In WordPress, write it in Additional CSS, or load a child theme CSS file with wp_enqueue_style() and add_editor_style()
  • Even with matching lightness, the WCAG contrast ratio varies by hue. Check text color combinations with a checker

Related articles

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲