OKLCH vs HSL vs HEX: The 2026 Designer's Guide to Choosing a Color Format

Updated May 16, 2026 · 9 min read · By the TinyTools team

If you opened a fresh design system repo in 2026 and saw oklch(0.62 0.22 295) instead of #a855f7, you are not alone in wondering what changed. OKLCH quietly became the default color format in Tailwind v4, the new shadcn/ui theming layer, and most of the design systems shipping at YC-stage startups this year. It is doing a job that HEX and HSL could not do well, and it is doing it in every modern browser without a polyfill.

That does not mean HEX is dead, and it does not mean you should rewrite every variable in your codebase tonight. This guide explains the three formats in plain terms, shows where each one wins, and gives you a decision framework you can apply to your next project in about thirty seconds.

Need a palette in any format?

Generate a complete brand palette and copy it as HEX, HSL, or OKLCH with one click — no signup, no watermark, dark-mode tokens included.

Try the Color Palette Generator free →

The three formats at a glance

Before we get into theory, here is the same color expressed three ways so the rest of the article has a shared reference point:

FormatExampleWhat it describes
HEX#a855f7Three bytes of sRGB (red, green, blue) packed into base 16
HSLhsl(271 91% 65%)Hue angle, saturation, lightness — still sRGB underneath
OKLCHoklch(0.62 0.22 295)Perceptual lightness, chroma, hue — in a wider color space
#a855f7
hsl()
oklch()

To your eye they look identical. To the browser they are stored, interpolated, and clamped to display gamut in different ways — and that is where the practical differences start.

HEX: the universal default that hides everything

HEX is just a compressed way to write an sRGB triplet. #a855f7 means red = 168, green = 85, blue = 247 on a 0–255 scale. Every device, every email client, every legacy CMS knows what to do with it.

The trouble is that HEX is opaque to humans. If a stakeholder asks "can you make it slightly darker?" you have no idea which byte to nudge. You end up bouncing into a color picker, eyeballing it, copying a new hex back out. That is fine for a single brand color, painful for a 12-step ramp, and disastrous for generating themes programmatically.

HEX also has no notion of brightness the way humans see it. #ffff00 (yellow) and #0000ff (blue) both have one channel maxed out, but yellow looks roughly seven times brighter to the human eye. That mismatch is why naive "lighten by 10%" functions in HEX produce dirty, washed-out results.

Use HEX when: the color leaves the browser. Email templates, social card metadata, brand guidelines as PDFs, design files shared with non-technical stakeholders. HEX is the universal lingua franca and that is its real superpower.

HSL: the 2010s upgrade that almost worked

HSL (hue, saturation, lightness) was added to CSS in 2011 and felt like a revelation. Suddenly you could write hsl(271 91% 65%) and a teammate could read it: "purple-ish, very saturated, medium-light." Changing the lightness from 65% to 45% gives you a darker shade of the same hue. Most design systems built between 2014 and 2022 are quietly HSL underneath.

The problem is that HSL lies about lightness. The "L" channel is mathematically simple but perceptually wrong. Compare these three colors, all at lightness 50%:

hsl(60 100% 50%)
hsl(120 100% 50%)
hsl(240 100% 50%)

To HSL, they are equally light. To your eye, the yellow is blinding, the green is bright, and the blue is dark. That difference is why a 10-step HSL ramp from L: 95% down to L: 5% produces a smooth gray ramp but a wildly uneven color ramp — the yellows clump at the light end, the blues clump at the dark end, and nothing in the middle feels evenly spaced.

The other thing HSL gets wrong is gamut. It is locked to sRGB, which covers maybe 70% of what a modern P3 display can actually show. The reds in your iPhone photos are more saturated than anything HSL can describe.

Use HSL when: you have an existing codebase full of HSL variables. It is not broken, it is just less precise than what you can have today. Migration is rarely worth the effort on its own.

OKLCH: perceptual color that finally shipped

OKLCH stands for Oklab Lightness, Chroma, Hue. Oklab is a color space designed by Börn Ottosson in 2020 specifically to fix the "L means something" problem — if two OKLCH colors have the same L, they actually look equally bright to a typical observer.

The three channels mean:

Because L is perceptually uniform, you can build a 10-step ramp by walking from L: 0.95 down to L: 0.15 in equal increments and get a ramp that looks evenly spaced — in any hue, on any display. That is the property that makes OKLCH ideal for design systems.

/* A perceptually even purple ramp in OKLCH */
--purple-50:  oklch(0.97 0.02 295);
--purple-100: oklch(0.93 0.05 295);
--purple-200: oklch(0.86 0.10 295);
--purple-300: oklch(0.77 0.16 295);
--purple-400: oklch(0.69 0.20 295);
--purple-500: oklch(0.62 0.22 295);
--purple-600: oklch(0.54 0.22 295);
--purple-700: oklch(0.46 0.20 295);
--purple-800: oklch(0.38 0.16 295);
--purple-900: oklch(0.28 0.10 295);

Notice that only the L and C numbers move. Hue stays locked at 295. To make a teal ramp with identical perceptual spacing, you change one number: 295195. Try doing that in HEX.

The wide-gamut bonus

OKLCH is not tied to sRGB. When the browser renders oklch(0.62 0.30 25) on a P3-capable screen, it uses the wider gamut and you get a richer, more saturated red than any HEX value can express. On an older sRGB screen, the browser clamps it down gracefully. You write one color and get the best version your hardware can render — no media queries needed.

Browser support in May 2026

FormatChrome / EdgeSafariFirefoxOld browsers
HEXForeverForeverForeverForever
HSLSince 2011Since 2011Since 2011IE9+
OKLCH111+ (Mar 2023)15.4+ (Mar 2022)113+ (May 2023)No fallback in IE

Global support for OKLCH crossed 93% in late 2024 and is at roughly 96% as of Q2 2026 (caniuse). The remaining gap is mostly Android WebView versions older than 113 and Samsung Internet under 22. If your analytics show fewer than 1% of users on those, you can ship OKLCH without a fallback. Otherwise, modern build tools (Tailwind v4, PostCSS Preset Env, Lightning CSS) will compile oklch() down to the nearest #hex for you at build time.

Generating palettes: where OKLCH wins by a mile

This is the practical reason to care. A palette generator using HSL has to add hue-specific magic numbers to fake perceptual uniformity. A palette generator using OKLCH just walks the L axis.

Here is the entire algorithm for a balanced 9-step accent ramp in OKLCH:

const hue = 295; // purple
const chroma = 0.22; // saturation
const steps = [0.95, 0.85, 0.75, 0.65, 0.55,
               0.45, 0.35, 0.25, 0.15];

steps.map((L, i) => `--accent-${(i+1)*100}: oklch(${L} ${chroma * Math.min(1, L * 1.6)} ${hue});`);

Twelve lines of code, applied to any hue, produces a Tailwind-quality ramp. The same algorithm in HSL needs a lookup table of hue corrections to stop the yellows from blowing out.

Skip the math entirely

Pick a brand color, hit generate, and copy a full perceptually-balanced palette in OKLCH, HSL, or HEX. Includes dark-mode tokens and WCAG contrast checks.

Generate a palette →

When HEX still wins in 2026

OKLCH is the right default for new design tokens, but HEX is not going anywhere. Here are the places where HEX is still the correct choice:

Migration strategy if you already have HSL

If your codebase is already on HSL CSS variables, you do not need a rewrite. A staged migration costs nothing and lets you A/B the result:

  1. Keep your existing semantic tokens. --accent, --bg-card, --text all stay where they are.
  2. Rewrite the source-of-truth values in OKLCH inside a :root block. Use a converter to get exact equivalents the first pass.
  3. Generate ramps by walking the L axis, replacing the eyeballed numbers from your old HSL ramp.
  4. Add a P3 layer for accent colors only — bump the chroma where the display can handle it.

Most teams report the swap takes an afternoon and produces visibly nicer dark-mode surfaces immediately, because the gray steps actually look evenly spaced for the first time.

The 30-second decision framework

If you are…Use
Authoring a new design system or themeOKLCH
Generating a programmatic color rampOKLCH
Maintaining an existing HSL systemHSL (don’t migrate for its own sake)
Writing email HTMLHEX
Sharing a value with a designer or brand guideHEX
Targeting users on browsers older than 2023HEX with a build-time fallback
Doing anything that touches a wide-gamut displayOKLCH

Further reading

If you want to go deeper, Börn Ottosson's original Oklab post is short and surprisingly readable. Evil Martians' OKLCH writeup has interactive visualizations that make the perceptual-uniformity claim obvious in about ten seconds. And the CSS Color Level 4 spec is where this all became official — useful when you need to argue with a senior engineer about whether OKLCH is "standard."

Build a palette in any format

Generate a complete brand palette — tints, shades, dark-mode surfaces, WCAG-checked text colors — and copy the values as HEX, HSL, or OKLCH. Free, no signup.

Open the Color Palette Generator →