Tools

Hex, RGB, HSL, OKLCH: Which Color Format Should You Actually Use?

June 10, 2026·10 min read

Four Ways to Say "Blue"

If you open any modern CSS file, design token spec, or Figma export, you will see the same color expressed in at least three different notations within a few hundred lines. #3b82f6, rgb(59, 130, 246), hsl(217, 91%, 60%), and oklch(0.62 0.19 259) all describe the same blue. They are not interchangeable. Each was designed to solve a different problem, each has a failure mode, and the choice between them is one of the more consequential small decisions in a design system.

This is not a syntax tour. The MDN entries for each format are excellent and you should read them if you need the grammar. What follows is the part that does not fit in a reference page: where each format shines, where it quietly breaks, and how to decide which one belongs in your codebase in 2026 now that all four are real, well-supported options rather than a legacy-and-future split.

Hex: The Universal Common Tongue

Hexadecimal notation is the oldest format on this list and still the most widely understood. #3b82f6 is six hexadecimal digits encoding three 8-bit channels: red, green, and blue, each from 0 to 255. The three-character shorthand (#3bf) expands each digit, so #abc becomes #aabbcc. The eight-character form adds an alpha channel at the end: #3b82f680 is the same blue at 50 percent opacity.

Hex's superpower is that it is the lingua franca of every design tool that has ever existed. Photoshop, Figma, Sketch, Affinity, every brand guidelines PDF, every Slack message where a designer pastes a color — they all speak hex. When a stakeholder asks "what's our primary blue?" the answer that everyone in the room can parse is the hex code.

Its weakness is that it is human-unreadable in any useful sense. You cannot look at #3b82f6 and predict that it is a saturated medium blue. You cannot eyeball "slightly darker than this" without running it through a converter. The format encodes the machine representation, not the perceptual one, which makes it terrible for design work and fine for storage and exchange.

Hex also caps you at the sRGB gamut — the color space defined by standard displays since the late 1990s. That sounds fine until you remember that essentially every Apple display sold since 2016, plus most premium Android and Windows hardware, supports Display P3 with about a third more visible color volume. Hex cannot address those colors. If you write #ff0000, you get the brightest red sRGB can produce, not the brightest red the screen can produce.

Use hex for: brand guidelines, designer handoff, anywhere a color needs to be copied across tools that may or may not understand modern CSS. Do not use hex for: anything in your stylesheet that you want to programmatically lighten, darken, or shift.

RGB: Hex With Decimal Channels

The rgb(59, 130, 246) notation is the same data as hex, just in decimal. CSS Color Level 4 also accepts a space-separated form with an optional slash for alpha: rgb(59 130 246 / 0.5). The percentage form (rgb(23% 51% 96%)) has been around since CSS 2 but is rarely used outside of generated code.

The honest case for RGB over hex is narrow. It composes slightly better with CSS custom properties when you want to split out the alpha channel for tinting (--brand-rgb: 59 130 246; background: rgb(var(--brand-rgb) / 0.1); is a common pattern). It is marginally more readable than hex for people who think in 0-255 channel values, which is mostly engineers who came up through games or computer graphics. Otherwise, RGB inherits hex's weaknesses: not perceptually meaningful, sRGB-bound, and useless for relative manipulation.

The one place where RGB unambiguously wins over hex is when you genuinely need to do arithmetic on channels in CSS itself. With color-mix() shipping in every modern browser, that need has shrunk considerably, but it has not gone away.

HSL: The First Honest Attempt at Human-Readable Color

Hue, Saturation, Lightness. hsl(217, 91%, 60%) says: a color at 217 degrees around the color wheel (which is in the blue range), 91 percent saturated, and 60 percent lightness. CSS Color Level 4 accepts a space-separated form: hsl(217 91% 60%).

HSL was a genuine improvement when it landed in CSS3. You can read an HSL value and predict what color it produces. You can darken a color by reducing the lightness component. You can build hover states by nudging the saturation up by ten percent. For roughly a decade, HSL was the default recommendation in serious design systems work.

It has one large, well-known flaw: the lightness value is not perceptually uniform across hues. hsl(60, 100%, 50%) (a pure yellow) and hsl(240, 100%, 50%) (a pure blue) both claim 50 percent lightness, but the yellow looks dramatically brighter to a human eye. If you build a design system where every primary color is "the brand hue at 50 percent lightness," you will get a yellow that feels like a screaming highlighter sitting next to a blue that looks almost navy. Designers compensate by hand-tuning each hue's lightness, which defeats the entire point of using a parametric color system.

HSL also shares hex and RGB's sRGB ceiling. The math is just a transformation of the sRGB cube into a cylinder, so anything sRGB cannot express, HSL cannot express either.

Use HSL for: hand-rolled color palettes where you only care about a few hues, quick visual reasoning while reading a stylesheet, and any case where you do not need cross-hue consistency. Do not use HSL for: programmatic palette generation, accessible contrast scales, or any system where a "50 percent" anywhere means a perceptually equal step.

OKLCH: The Perceptually Honest One

OKLCH is the format that matters in 2026. It is part of CSS Color Module Level 4, it shipped in Chrome 111 (March 2023), Safari 15.4, and Firefox 113, and by mid-2024 it had universal modern-browser support. The oklch(0.62 0.19 259) notation means: 62 percent perceptual lightness, 0.19 chroma (saturation), 259 degrees hue.

The "OK" stands for the Oklab color space, published by Björn Ottosson in late 2020. Oklab is a perceptual color space designed to fix exactly the problem HSL has: a step of equal lightness should look like an equal step regardless of hue. oklch(0.6 0.2 60) (a yellowish orange) and oklch(0.6 0.2 240) (a blue) actually feel like the same brightness when you put them next to each other. This is the property that makes programmatic palettes work.

OKLCH also natively supports wide-gamut colors. oklch(0.7 0.3 30) describes a red that exists in Display P3 but is outside sRGB. On modern hardware it renders as a more saturated red than any hex code can produce; on older sRGB-only displays the browser gracefully maps it back into gamut. You write the color you mean, and the platform handles the fallback.

The trade-off is that OKLCH is harder to eyeball. The lightness range is 0 to 1, not 0 to 100. Chroma is unbounded in theory but practically caps around 0.37 for the most saturated visible colors. Hue degrees do not map to the same wheel positions as HSL — OKLCH blue sits around 260 degrees, where HSL blue sits around 240. None of this is hard to learn, but it does mean OKLCH is not as immediately readable to someone seeing it for the first time as HSL was.

If you are converting back and forth between formats while you work — pulling a hex code from a Figma file, then needing the OKLCH version for a CSS custom property — the friction shows up fast. A simple color picker that gives you all four formats at once takes the conversion step out of the loop, which is roughly what you want sitting next to your editor.

Use OKLCH for: design systems where colors are generated parametrically, accessible contrast scales, palette interpolation, wide-gamut work on modern hardware, and any stylesheet written in 2026 that does not have legacy constraints. Do not use OKLCH for: handoff to a designer who is going to paste the value into Photoshop — they cannot consume it directly yet.

The Decision Heuristic

The four formats are not in competition. They sit at different layers of a working color pipeline, and a serious codebase will use most of them in the right places.

Brand colors live in hex because that is the universal exchange format. A brand guideline that says "primary blue is #3b82f6" works for every designer, every print vendor, every Figma file, every external partner. The hex code is the canonical reference.

Design tokens — the variables your stylesheet actually consumes — should be OKLCH in any new codebase. The reason is that tokens are where parametric manipulation happens. You want a "primary-300" through "primary-900" scale where each step is a perceptually equal lightness change. You want hover and active states that feel consistent across hues. OKLCH delivers both; HSL does not.

Inline color values in component code (the actual color and background-color properties) can stay in whatever format you find readable, because they will typically reference tokens rather than naming colors directly. If you are still hand-writing color values in components, that is the bigger problem to solve first.

Conversion between formats is mostly a developer-experience question. Modern build tools handle it transparently; PostCSS plugins, Tailwind's color resolver, and most CSS-in-JS libraries will accept any format and emit whichever the project standardizes on. The cost of switching is lower than it looks.

What Probably Does Not Matter Yet

A few things in the color-format conversation get more weight than they deserve.

HDR color in browsers is a real specification (color() with custom color spaces, the display-p3 and rec2020 identifiers) and worth knowing about, but it is not yet a posture most design systems take. Stick with OKLCH for now; it covers wide-gamut without requiring you to think about gamut mapping explicitly.

Color names (red, cornflowerblue, the full CSS named-color list) are fine for prototypes and the occasional debugging override. They are not a real format for production work.

LCH and Lab — the predecessors of OKLCH and Oklab — are valid CSS Level 4 formats, but Oklab fixed real perceptual issues with the original Lab color space and is the right default. Use the OK variants unless you have a specific reason not to.

The one thing that does deserve more weight than it gets: every codebase should standardize on one format for design tokens and stick with it. The cost of mixed formats inside a single token system is not the bytes; it is that every developer who reads the code has to context-switch between mental models of color. Pick one, write it down, and move on.

Stay Informed

Get ecosystem updates

New tools, posts, and ecosystem news — no spam, unsubscribe anytime.