Xerobit
Dev Productivity

Hex, RGB, HSL, OKLCH: Which to Pick in 2026

Four CSS color formats, four different audiences. This is what each is good at, why OKLCH is the 2026 upgrade, and a practical guide for which to use where.

MA Mian Ali Khalid 9 min read
Free tool
Color Picker
Pick colors, convert hex/RGB/HSL/OKLCH, and check WCAG contrast.
Open tool →
On this page ⌄
  1. The four formats at a glance
  2. Hex: the universal default
  3. RGB: per-channel reasoning
  4. HSL: the human-friendly default that isn't
  5. OKLCH: the 2026 upgrade
  6. Quick conversion reference
  7. Which format to use, when
  8. Three palette gotchas
  9. What's next
  10. Further reading

Every color in CSS is, ultimately, three or four numbers. The format you write them in, #10B981, rgb(16, 185, 129), hsl(161 84% 39%), oklch(69.4% 0.147 162.5): produces the same color on screen. But each format models color differently, which means each is suited to different work.

This post is the working developer's guide: what each format is, what it's optimized for, and which to reach for in 2026.

The four formats at a glance

FormatExampleModelsBest for
Hex#10B981Compact RGBDesigner handoff, brand colors, copy/paste
RGBrgb(16 185 129)Per-channel intensityChannel-level animation, image processing
HSLhsl(161 84% 39%)Hue + saturation + lightnessManual color tweaks, traditional palettes
OKLCHoklch(69% 0.147 162)Perceptually uniform L+C+HModern palettes, accessibility, 2026 default

All four describe the same color. The difference is which axes are easy to think about.

Hex: the universal default

Hex (#RRGGBB) is RGB written in base 16. Two characters per channel, six characters total. It's the default for designer→developer handoff because:

  • Compact. 6 characters. Fits in tweets, JSON, branding briefs.
  • Tool-universal. Photoshop, Figma, Sketch, every dev tool, every design tool: all speak hex.
  • No format ambiguity. #10B981 means exactly one thing across every implementation.

What hex is bad at:

  • No mental model. You can't tell from #10B981 whether it's bluish-green or yellowish-green without rendering it.
  • No incremental adjustment. "Slightly darker" requires knowing which channels to bump. Compare HSL where you'd just decrease lightness.
  • No transparency without 8-digit hex. #10B981FF is 8-digit hex (RGB+alpha): supported in modern browsers but less common in design tools.

Use hex for: brand colors, design system tokens that don't need adjustment, anything you're copying from a design tool.

RGB: per-channel reasoning

rgb(16 185 129) is the same color as #10B981. RGB is decimal hex; the bytes are identical. CSS supports both space- and comma-separated forms, plus an optional alpha:

rgb(16 185 129)              /* modern syntax */
rgb(16, 185, 129)            /* legacy syntax (still works) */
rgb(16 185 129 / 0.5)        /* with alpha */
rgba(16, 185, 129, 0.5)      /* legacy with alpha */

What RGB is good at:

  • Per-channel manipulation. "Boost the red channel by 30" is straightforward in RGB; awkward in HSL.
  • Image processing. Pixel data is RGB. Tools like canvas's getImageData give you RGB arrays.
  • Hardware-aligned. Display panels are physical R, G, B subpixels. RGB matches the metal.

What RGB is bad at:

  • Same as hex: no perceptual axis.
  • Verbose. Three numbers in 0-255 vs six hex chars.

Use RGB for: programmatic color manipulation, image work, animations that change one channel.

HSL: the human-friendly default that isn't

hsl(hue saturation lightness). Hue is 0-360° (red=0, green=120, blue=240). Saturation and lightness are 0-100%.

What HSL got right:

  • Hue is a wheel. "Move toward yellow" is +30° on the hue. Intuitive.
  • Saturation is "muted vs vivid". 0% saturation is grayscale; 100% is fully saturated.
  • Lightness is "darker vs lighter." In theory.

What HSL got wrong: lightness is mathematical, not perceptual.

Pick yellow at HSL 60°, 100%, 50%. Pick blue at HSL 240°, 100%, 50%. Both have lightness 50%. Look at them side by side. The yellow looks dramatically brighter than the blue.

That's because HSL's "lightness" is the midpoint of the RGB cube, a mathematical construction, not a model of how eyes work. Yellow has high green-channel intensity (which dominates perceived brightness, see WCAG luminance), so HSL lightness 50% yellow is far brighter than HSL lightness 50% blue.

Real-world consequence: a palette built in HSL with even lightness steps does not feel like even lightness steps. Designers learned to compensate by tuning each hue manually. Twenty years of palette tools papered over this with ad-hoc adjustments.

HSL is still useful for one-off tweaks where you're eyeballing the result. But for systematic palette generation, you want OKLCH.

OKLCH: the 2026 upgrade

oklch(lightness chroma hue):

  • Lightness (0-100%): perceptually uniform. 60% yellow looks the same brightness as 60% blue.
  • Chroma (0-~0.4): how saturated. 0 is gray; higher is more vivid.
  • Hue (0-360°): same as HSL hue, just in a different color space.

Background: OKLCH is built on the Oklab color space by Björn Ottosson, designed specifically to be perceptually uniform. Equal numerical steps produce equal visual steps. This is what HSL was supposed to do but didn't.

What OKLCH unlocks:

  • Even palette ramps. Set lightness 95%, 85%, 75%, ... 15%, 5% for a 10-step shade scale that feels evenly stepped across all hues.
  • Accessible defaults. Pick a base color, derive light/dark variants by adjusting L predictably. Contrast ratios become predictable.
  • Hue rotation that doesn't drift. Rotating hue while keeping L and C constant produces colors that feel like the same "weight" across hues. HSL drifts in lightness.

CSS support: every browser shipped after late 2023 supports oklch() natively. As of 2026, that's safe to use without fallbacks. Tailwind 4 ships with OKLCH by default. Radix Colors uses OKLCH internally. Open Props OKLCH variant is standard.

:root {
  --primary: oklch(69% 0.15 162);
  --primary-light: oklch(85% 0.10 162);  /* same hue, lighter */
  --primary-dark: oklch(45% 0.18 162);   /* same hue, darker, slightly more saturated */
}

The lightness changes feel even because they are even.

Quick conversion reference

The Color Picker does this live, but if you need to know the math: every browser and CSS engine ships with conversion code. The pipeline:

Hex ↔ RGB (trivial, 2 hex chars per channel)
RGB → linear RGB (gamma decode)
linear RGB → OKLCH (matrix multiply + cube root + atan2)
RGB → HSL (algorithm in CSS spec, doesn't go through linear RGB)

OKLCH conversion is non-trivial, it goes through linearization and matrix transforms. For full implementation see the CSS Color Module 4 spec.

Which format to use, when

A practical decision tree:

SituationFormatWhy
Receiving a color from designWhatever they sent (usually hex)Don't round-trip-convert; preserve what they specified
Storing brand colors in a token fileHexCompact, universal
Building a design system shade scaleOKLCHPerceptual uniformity wins on every axis
Animating a single channelRGBDirect channel access
Manual quick tweak ("a bit darker")HSL or OKLCHAdjust lightness directly
Calculating contrastDoesn't matter: convert to luminance internallyAll formats produce the same luminance
CSS custom properties for themingOKLCHEasy variants, predictable behavior
Anywhere a designer works in FigmaHex (until Figma fully supports OKLCH)Round-trip what they hand you

Three palette gotchas

1. Don't mix formats in a palette

Don't define some colors in hex and others in OKLCH within the same token file. Pick one format for the canonical definition, derive everything else. Mixing makes the file unreadable and creates silent rounding drift.

2. Don't try to math hex

// Don't do this
const darker = `#${(parseInt(hex.slice(1), 16) - 0x101010).toString(16)}`;

That subtracts 16 from each channel, but you can't tell from looking at hex whether it'll go negative, overflow, or shift the hue. Always convert to RGB or OKLCH for arithmetic, then convert back.

3. Don't trust HSL "evenness"

If you're building a 10-step shade ramp and want it to feel even, use OKLCH. HSL ramps look uneven; you'll spend hours hand-tuning to fix what's a mathematical mismatch.

What's next

Hex isn't going away. RGB isn't going away. HSL probably is going away as the default for palette tooling, modern systems standardize on OKLCH. The transition is similar to em → rem in CSS: an existing format that mostly worked, replaced by a slightly better one as browser support caught up.

For 2026 work: default to OKLCH for systematic palettes, hex for handoff, RGB for channel manipulation, HSL for legacy compatibility. That's the entire decision.

Further reading

Keep reading

WCAG Contrast Explained (AA vs AAA, When It Matters)

Color contrast determines who can read your interface. This is the WCAG math, the four thresholds, the difference from APCA, and how to actually fix violations.

Color Accessibility: WCAG Contrast Ratios and Tools

WCAG 2.1 requires a 4.5:1 contrast ratio for normal text and 3:1 for large text. Learn how to calculate contrast ratios, test color combinations, use browser DevTools, and...

Color Picker Tools: Browser DevTools, VS Code, and Online Pickers

Color picker tools help designers and developers find and manage colors. Learn how to use Chrome DevTools color picker, VS Code color preview, online tools, and eyedropper APIs...

Color Theory for Web Design: Hue, Saturation, and Color Harmonies

Color theory explains how colors relate to each other and why some combinations work visually. Here's how hue, saturation, and lightness work, common color harmonies, and how...

Hex Color Codes Explained: RGB, HSL, and How Colors Work in CSS

Hex color codes are 6-digit hexadecimal numbers that represent RGB values. Here's exactly how #FF5733 translates to a color, and how to convert between hex, RGB, and HSL.

HSL Color: Hue, Saturation, and Lightness Explained

HSL represents colors as hue (0-360°), saturation (0-100%), and lightness (0-100%). It's more intuitive than RGB for programmatic color manipulation, here's how it works and...

OKLCH Color Space: Perceptually Uniform Colors for CSS

OKLCH is a perceptually uniform color space that makes predictable color palettes, consistent lightness, and accessible contrast easy. Learn the oklch() CSS function, how to...

Related tools

Written by Mian Ali Khalid. More guides in Dev Productivity.