OKLCH Color Picker: เหตุใดนักออกแบบจึงเปลี่ยนมาใช้
Embed This Widget
Add the script tag and a data attribute to embed this widget.
Embed via iframe for maximum compatibility.
<iframe src="https://colorfyi.com/iframe/entity//" width="420" height="400" frameborder="0" style="border:0;border-radius:10px;max-width:100%" loading="lazy"></iframe>
Paste this URL in WordPress, Medium, or any oEmbed-compatible platform.
https://colorfyi.com/entity//
Add a dynamic SVG badge to your README or docs.
[](https://colorfyi.com/entity//)
Use the native HTML custom element.
Open any design tool — Figma, Sketch, Adobe XD — and the default color picker presents HSL sliders or a hue wheel with a lightness/saturation square. This interface has been the industry standard for decades. It feels familiar and intuitive, yet it consistently produces one of the most frustrating problems in design systems: color scales where the steps look uneven, where a yellow at 50% lightness appears blindingly bright next to a blue at the same value.
OKLCH color pickers solve this problem at the level of the color model itself. They are gaining adoption across developer tooling and beginning to appear in design tools. This guide explains why, how they work, and how to build better palettes using them.
Problems with HSL Color Pickers
HSL stands for Hue, Saturation, Lightness. The model was a significant improvement over raw RGB when it was introduced to CSS — it gave designers a way to think about color in more intuitive terms. Rotating the hue by 30 degrees, increasing saturation to 80%, bringing lightness up to 70%: these operations map to design intent far better than manipulating red, green, and blue channel values directly.
But HSL has a fundamental flaw that no amount of UI polish can fix: its lightness axis is not perceptually uniform.
The Lightness Illusion
Consider two colors at identical HSL lightness values:
hsl(60, 100%, 50%)— pure yellowhsl(240, 100%, 50%)— pure blue
In HSL's model, both have 50% lightness. To the human eye, the yellow appears dramatically brighter than the blue. This is not a display calibration issue — it is a fundamental property of human vision. Our retinal cone cells have different sensitivity to different wavelengths of light. The M-cones (medium wavelength, sensitive to yellow-green light) and L-cones (long wavelength, sensitive to red) are far more numerous and sensitive than S-cones (short wavelength, sensitive to blue). As a result, we perceive yellow-green as inherently much brighter than blue at the same physical energy level.
HSL was designed around the mathematics of the RGB color model, not around human perception. Its lightness axis is a compromise that approximates perceived brightness for the average of all hues — but fails significantly for specific hues at the extremes of human sensitivity.
The Shade Scale Problem
This perceptual non-uniformity creates a concrete, practical problem when building shade scales. Imagine you are creating a 9-step scale from light to dark for your brand color. In HSL, you increment the lightness value by a fixed amount at each step:
| Step | HSL | Perceived brightness |
|---|---|---|
| 50 | hsl(210, 80%, 95%) |
Very light |
| 100 | hsl(210, 80%, 87%) |
Light |
| 200 | hsl(210, 80%, 79%) |
Moderately light |
| 300 | hsl(210, 80%, 71%) |
Medium-light |
| 400 | hsl(210, 80%, 63%) |
Medium |
| 500 | hsl(210, 80%, 55%) |
Medium-dark |
| 600 | hsl(210, 80%, 47%) |
Dark |
| 700 | hsl(210, 80%, 39%) |
Darker |
| 800 | hsl(210, 80%, 31%) |
Very dark |
For a blue hue (210°), this produces a reasonably even-looking scale. But run the same algorithm with a yellow hue (55°) and the middle steps look washed out. Run it with a green-yellow (85°) and the high-lightness steps look nearly identical because yellow-green has so much inherent perceived brightness.
HSL shade generators require manual correction for each hue — they are not truly systematic.
The Gradient Muddy-Middle Problem
HSL's non-uniformity also affects gradients. A CSS gradient from a vivid orange to a vivid blue, interpolated in HSL, often passes through a dull, grayish green in the middle because the hue rotation passes through a region where HSL's model produces desaturated-looking colors. This is why gradients between complementary colors in HSL often look muddy rather than vivid.
How OKLCH Fixes Perceptual Uniformity
OKLCH is a color model built from the ground up around human visual perception. It is derived from the Oklab color space, which was designed by Björn Ottosson in 2020 specifically to improve on the perceptual uniformity of CIE Lab — particularly for blue and purple hues, where CIE Lab has known weaknesses.
The name OKLCH breaks down as:
- OK — the Oklab color space prefix
- L — Lightness, from 0 (absolute black) to 1 (absolute white)
- C — Chroma, the colorfulness or vividness (similar to saturation)
- H — Hue, a degree from 0 to 360
Perceptually Uniform Lightness
The key claim of OKLCH is that its L axis is perceptually uniform: equal numerical changes in L produce equal-looking changes in perceived brightness, regardless of the hue.
To illustrate, consider the same two colors from the HSL example, but expressed in OKLCH:
| Color | HSL Lightness | OKLCH Lightness | Perceived brightness |
|---|---|---|---|
| Pure yellow | hsl(60, 100%, 50%) L=50% |
oklch(0.96 0.21 90) L=0.96 |
Very high |
| Pure blue | hsl(240, 100%, 50%) L=50% |
oklch(0.45 0.31 270) L=0.45 |
Moderate |
In HSL, both have L=50%. In OKLCH, the yellow has L=0.96 and the blue has L=0.45 — the OKLCH lightness correctly captures the dramatic perceptual brightness difference that HSL ignores.
This means that when you build a shade scale in OKLCH by fixing the L values and choosing specific increments, the resulting steps look visually even across all hues. A 5-step blue scale and a 5-step yellow scale built with the same L values will appear to have matched brightness at each step.
Chroma Instead of Saturation
OKLCH uses chroma (C) rather than saturation (S). This distinction matters. Saturation in HSL is relative — 100% saturation of a dark gray and 100% saturation of a vivid red are very different amounts of actual colorfulness. Chroma in OKLCH is an absolute measure of colorfulness that can be compared across hues and lightness levels.
The chroma range varies by hue and lightness — not all hue/lightness combinations can support high chroma values within the sRGB gamut. For example, a highly vivid yellow (hue ~90°) at high lightness can achieve a chroma of around 0.35, while a blue (hue ~270°) at the same lightness can only reach about 0.15 before going out of sRGB gamut.
OKLCH color pickers typically show the achievable chroma range for the current hue and lightness, preventing you from accidentally selecting an out-of-gamut color (or explicitly letting you do so for wide-gamut displays).
Perceptual Lightness in Practice
The practical benefit of perceptual lightness becomes most visible when building multi-hue color palettes.
Multi-Hue Palettes
Suppose you want to create a design system with five semantic colors — blue (primary), green (success), amber (warning), red (danger), and purple (brand) — where the 500-weight shade of each color looks visually equivalent in weight on a white background.
In HSL, achieving this requires manually adjusting the lightness for each hue. A yellow-amber at L=50% looks far brighter than a blue at L=50%. You end up with different lightness values for each color just to make them look balanced.
In OKLCH, you set all five 500-weight shades to the same L value — say, L=0.62 — and they look equally weighted:
:root {
--blue-500: oklch(0.62 0.19 250); /* Primary */
--green-500: oklch(0.62 0.20 145); /* Success */
--amber-500: oklch(0.62 0.18 70); /* Warning */
--red-500: oklch(0.62 0.24 25); /* Danger */
--purple-500: oklch(0.62 0.17 300); /* Brand */
}
All five share L=0.62. In a UI, they will appear as equally strong colors on a white background — none will dominate or fade unexpectedly.
Even Shade Steps
Building a complete shade scale in OKLCH produces visually even steps:
:root {
/* Blue scale — OKLCH with even L increments */
--blue-50: oklch(0.97 0.02 250);
--blue-100: oklch(0.93 0.04 250);
--blue-200: oklch(0.87 0.07 250);
--blue-300: oklch(0.79 0.11 250);
--blue-400: oklch(0.70 0.15 250);
--blue-500: oklch(0.62 0.19 250);
--blue-600: oklch(0.52 0.19 250);
--blue-700: oklch(0.42 0.18 250);
--blue-800: oklch(0.33 0.14 250);
--blue-900: oklch(0.24 0.09 250);
--blue-950: oklch(0.17 0.06 250);
}
Each L step is approximately 0.07–0.08 apart. Because OKLCH lightness is perceptually uniform, these steps look visually even — the jump from 50 to 100 looks similar to the jump from 400 to 500. Achieving this in HSL requires different step sizes for different hues.
Note also that chroma (C) decreases toward the extremes. Very light shades (50–200) have low chroma because high-lightness colors cannot support high chroma. Very dark shades (800–950) similarly have lower chroma. Only the middle range (400–700) has full chroma. This taper is characteristic of well-built OKLCH scales and is why the Shade Generator at colorfyi.com uses OKLCH internally for its computations.
Building Harmonious Palettes in OKLCH
OKLCH makes certain palette construction strategies more reliable than they are in HSL.
Monochromatic Scales
A monochromatic scale keeps H and C fixed while varying L. Because OKLCH L is perceptually uniform, the steps look even:
/* Monochromatic teal scale */
:root {
--teal-100: oklch(0.93 0.05 185);
--teal-300: oklch(0.76 0.10 185);
--teal-500: oklch(0.60 0.16 185);
--teal-700: oklch(0.43 0.14 185);
--teal-900: oklch(0.27 0.08 185);
}
Analogous Palettes
Analogous palettes use adjacent hues — typically within ±30° of the primary hue. Because OKLCH chroma is absolute, you can keep chroma constant across hues and get colors of similar vividness:
/* Analogous warm palette around hue 30° (orange) */
:root {
--hue-a: oklch(0.65 0.18 10); /* Red-orange */
--hue-b: oklch(0.65 0.18 30); /* Orange */
--hue-c: oklch(0.65 0.18 50); /* Amber */
--hue-d: oklch(0.65 0.18 70); /* Yellow-orange */
}
All four colors at the same L and C values. In HSL, the yellow-orange would look noticeably brighter than the red-orange.
Complementary Pairs
Complementary colors sit 180° apart on the hue wheel. In OKLCH, you can create a complementary pair at matched perceptual weight by keeping L and C the same while rotating H by 180°:
:root {
--primary: oklch(0.60 0.20 250); /* Blue */
--complement: oklch(0.60 0.20 70); /* Amber (250 - 180 = 70) */
}
Both colors will feel equally "strong" on a white background because L and C are matched — a balance that HSL cannot achieve by simply rotating the hue.
Wide Gamut Colors
OKLCH can express colors that lie outside the sRGB gamut — available on modern displays (iPhone 15, MacBook Pro, most high-end laptops) that support Display P3 or wider. These out-of-gamut colors appear more vivid than anything achievable in HEX or HSL:
/* This vivid green is beyond sRGB — fully rendered only on P3 displays */
color: oklch(0.80 0.35 145);
/* A vivid cyan that saturates P3 capability */
color: oklch(0.78 0.28 195);
Browsers gracefully map out-of-gamut OKLCH colors to the nearest sRGB equivalent on standard displays, so it is safe to author with these values even for mixed audiences.
OKLCH Tool Recommendations and Workflows
Converting Existing Colors
Before you can work in OKLCH, you need to know the OKLCH values for your existing hex brand colors. The Color Converter converts any hex, RGB, or HSL color to OKLCH (and back). Paste in your brand color and read off the L, C, and H values.
For example, #2563EB (a common Tailwind-derived blue) converts to approximately oklch(0.55 0.24 264). This tells you it has moderate lightness (0.55), high chroma (0.24), and a hue of 264° (blue-violet range).
Building Palettes
The Palette Generator generates harmonious color palettes. For OKLCH-based workflows, use the generated hex colors as starting points, convert them via the Color Converter, and then build your OKLCH variable set.
A practical workflow:
- Start with your brand hex color (e.g., #3B82F6)
- Convert to OKLCH:
oklch(0.62 0.19 250) - Note the L, C, H values
- Build your semantic palette by varying L while keeping H and C stable
- For semantic accent colors (success, warning, danger), rotate H while keeping the same L as your primary 500-weight shade
- Verify contrast of text/background pairs with the contrast checker
In CSS
Once you have OKLCH values, use them directly in CSS custom properties:
:root {
--brand-h: 250; /* Brand hue — reuse across the scale */
--brand-c: 0.19; /* Brand chroma at mid-weight */
--brand-500: oklch(0.62 var(--brand-c) var(--brand-h));
--brand-400: oklch(0.70 var(--brand-c) var(--brand-h));
--brand-600: oklch(0.52 var(--brand-c) var(--brand-h));
}
Storing H and C as sub-variables makes it easy to adjust chroma or hue globally for the entire scale.
OKLCH in Figma
Figma's color picker added OKLCH support in late 2024 via the color space dropdown in the fill panel. Switch the color picker to OKLCH mode and you can input L, C, H values directly. This lets you work natively in OKLCH within the design tool, building palettes that will produce consistent OKLCH CSS output.
Third-party Figma plugins like Chromatic, Color Compass, and the OKLCH Color Picker plugin extend this capability further, allowing you to generate complete shade scales, preview wide-gamut colors, and export OKLCH token files.
Key Takeaways
- HSL color pickers are not perceptually uniform: the same lightness value looks dramatically different in brightness across different hues, making it impossible to build visually even shade scales or matched multi-hue palettes algorithmically.
- OKLCH fixes this through a mathematically perceptually-calibrated lightness axis, where equal L increments produce equal perceived brightness changes regardless of hue.
- Chroma in OKLCH is an absolute measure of colorfulness (unlike HSL saturation, which is relative). This allows direct comparison of color vividness across different hues.
- Multi-hue palettes built with the same L value at each weight level look visually balanced — a systematic property that HSL cannot provide.
- OKLCH can express wide-gamut colors beyond sRGB, producing more vivid results on modern displays (Display P3 and wider). Browsers gracefully map these to sRGB on standard displays.
- A practical OKLCH workflow: convert your brand hex to OKLCH using the Color Converter, build your shade scale by varying L with fixed H and C, generate semantic accent hues by rotating H while keeping L constant, and verify contrast with the contrast checker.
- Tools supporting OKLCH include: the Palette Generator, the Shade Generator, and the Color Converter on colorfyi.com, as well as native OKLCH pickers now available in Figma.