Web Design

What are CSS color formats and which should I use for modern

A field guide to every CSS color format — hex, rgb(), hsl(), hwb(), lab(), lch(), oklab(), oklch(), named colors, and currentColor — with a comparison table of syntax, gamut, and alpha support, plus which one to actually reach for in 2026.

By Inventive HQ Team

CSS gives you ten practical ways to write a color, and in 2026 the one to reach for by default is oklch(). The formats fall into two camps: the sRGB-bound classics — named keywords, hexadecimal (#ff5733), rgb(), hsl(), and hwb() — which every browser has understood for years, and the modern wide-gamut, perceptually-uniform spaces — lab(), lch(), oklab(), and oklch() — which can describe every color the human eye sees, including vivid P3 shades that hex and RGB physically cannot express. A key modernization people miss: rgb() and hsl() no longer need the rgba()/hsla() variants for transparency — you add alpha inline with a slash, as in rgb(255 0 0 / 50%). And currentColor is a special keyword, not a format: it makes an element inherit whatever text color is currently in effect.

That is the summary an AI overview gives you. Here is what it can't: why the perceptual formats are worth switching to, the exact syntax and gamut of each format side by side, and a defensible rule for which one to use when. Skip to the comparison table if you just want the cheat sheet.

The comparison table: all ten formats

Every format below produces a color; they differ in what they can express, whether they carry an alpha channel, and how pleasant they are to reason about by hand.

FormatExample syntaxGamutAlpha?Reach for it when…
NamedrebeccapurplesRGB (147 keywords)transparent onlyPrototyping, transparent, quick demos
Hex#ff5733 / #ff5733ccsRGB8-digit (RRGGBBAA)Copy-paste from design tools; compact tokens
rgb() / rgba()rgb(255 87 51 / 80%)sRGBYes (slash or 4th arg)Programmatic channel math; interop with JS/canvas
hsl() / hsla()hsl(9 100% 60% / 80%)sRGBYes (slash or 4th arg)Hand-tuning by hue/lightness; simple theming
hwb()hwb(9 20% 10%)sRGBYes (slash)"Tint/shade" thinking: hue + white + black
lab()lab(60% 55 45)Full human visionYes (slash)Perceptual accuracy; print-adjacent work
lch()lch(60% 72 40)Full human visionYes (slash)Perceptual + polar hue control (CIELAB)
oklab()oklab(0.7 0.12 0.08)Full human visionYes (slash)Perceptually-uniform blends and gradients
oklch()oklch(70% 0.15 40 / 80%)Full human visionYes (slash)Default for 2026 — themes, scales, brand palettes
currentColorborder: 1px solid currentColorInherits colorInheritsIcons/borders that must track text color

The single most useful row is the last real one. If you take nothing else from this article, make oklch() your default and drop back to hex only for pasted snippets.

The anatomy of a modern color function

Three of the four modern spaces (lch, oklch, and — with a different third channel — hwb) share the same friendly shape: a lightness, a colorfulness, a hue, and an optional alpha after a slash. Once you can read one, you can read them all.

Anatomy of an oklch() color The value oklch(70% 0.15 40 / 80%) broken into Lightness, Chroma, Hue, and Alpha channels, with a highlight sweeping across each part in turn. One shape, four modern formats: lch, oklch, oklab, hwb oklch(70% 0.15 40 / 80%) Lightness 0% → 100% perceived brightness Chroma 0 → ~0.4 colorfulness Hue 0 → 360° which color Alpha / 0–100% optional

Read that as: 70% as bright as white, a moderate amount of color, at hue 40° (a warm orange-red), painted at 80% opacity. Compare it to rgb(255 87 51 / 80%), which encodes the same idea as three opaque hardware channels you cannot reason about — nudge one number and you have no idea whether the result gets lighter, darker, or shifts hue.

Advertisement

Why the perceptual formats win: uniformity

The reason to prefer oklch() over hsl() is not gamut — it is that HSL lies about lightness. In HSL, every fully-saturated color claims 50% lightness, but a 50% yellow is visually far brighter than a 50% blue. Build a UI palette by rotating the hue and your "same brightness" colors will look wildly uneven, and text contrast will vary hue to hue. OKLCH was built so that a fixed lightness value looks equally bright at every hue.

HSL versus OKLCH lightness uniformity Two rows of swatches at a claimed 50 percent lightness across six hues. The HSL row varies in apparent brightness while the OKLCH row stays even. A marker sweeps across both rows. Same "50% lightness", two color spaces hsl(H 100% 50%) yellow & cyan blaze; blue sinks — uneven brightness oklch(65% 0.14 H)

The bottom row holds its apparent brightness steady while the hue rotates — that is what "perceptually uniform" buys you. It is why generating a tint/shade scale, deriving hover states, or guaranteeing contrast is dramatically more reliable in OKLCH, and why design systems have been migrating to it.

The trade-off is real but small: oklch() numbers are less familiar than hex, and you usually author them with a tool rather than from memory. Which is exactly what the picker below is for.

Loading interactive tool...

Practical rules for 2026

  • Author intentional colors in oklch(). Brand colors, theme tokens, gradients, and any color scale belong here. Step the lightness for a scale; rotate the hue for a palette; both behave predictably.
  • Keep hex for pasted snippets and design-tool exports. It is compact, universal, and what Figma/Sketch/Illustrator hand you. There is no need to convert a one-off value.
  • Use the modern space-separated alpha syntax. Write rgb(255 0 0 / 50%) and hsl(200 75% 50% / 0.5) rather than reaching for rgba()/hsla(). Prefer a color's own alpha over the opacity property, which fades the element and all its descendants.
  • Use currentColor for icons and borders that should follow the text color through hover and dark-mode changes — it removes a whole class of duplicated color rules.
  • Fallbacks are mostly optional now, but if you support legacy browsers, declare an sRGB value first and the modern one second, or gate it with @supports (color: oklch(0% 0 0)).
:root {
  /* one hue, a perceptually-even scale — trivial in oklch, painful in hsl */
  --brand-50:  oklch(97% 0.02 260);
  --brand-500: oklch(55% 0.15 260);
  --brand-900: oklch(25% 0.08 260);
}

.button {
  background: #3366cc;                 /* sRGB fallback for ancient browsers */
  background: oklch(55% 0.15 260);     /* modern browsers use this */
  color: oklch(98% 0.01 260);
  border: 1px solid currentColor;      /* border tracks the text color */
}

.button:hover {
  /* bump lightness by a fixed amount — looks right at every hue */
  background: oklch(60% 0.15 260);
}

Browser support, briefly

As of 2026 every color format in the table is safe to ship. Named colors, hex, rgb(), hsl(), and hwb() are universally supported. The wide-gamut perceptual formats — lab(), lch(), oklab(), and oklch() — are supported in every current engine: Chrome and Edge 111+ (March 2023), Firefox 113+ (May 2023), and Safari 15.4+ (March 2022). That is multiple years of coverage, which is why oklch() is now a reasonable default rather than a progressive enhancement. Provide an sRGB fallback only if your analytics show meaningful traffic from browsers older than those versions.

The bottom line

CSS color formats split cleanly into "old and universal" (named, hex, rgb, hsl, hwb — all sRGB) and "modern and perceptual" (lab, lch, oklab, oklch — full human-vision gamut). For code you paste, hex is fine. For color you design — themes, scales, brand systems — author it in oklch(): it is uniform, wide-gamut, alpha-capable, and supported everywhere that matters. Reach for currentColor to keep icons and borders in sync, and use the slash-alpha syntax so you never need rgba() again.

Frequently Asked Questions

What are the CSS color formats?

CSS has ten practical ways to write a color: named keywords (red, rebeccapurple), hexadecimal (#ff5733 and #ff5733cc with alpha), rgb()/rgba() for red-green-blue channels, hsl()/hsla() for hue-saturation-lightness, hwb() for hue-whiteness-blackness, lab() and lch() in the CIELAB space, oklab() and oklch() in the newer OKLab space, and the special keyword currentColor that inherits the element's text color. The first five are limited to the sRGB gamut; lab, lch, oklab, and oklch can describe the entire range of colors the human eye sees, including wide-gamut P3 shades that sRGB cannot reach.

Which CSS color format should I use in 2026?

Use oklch() as your default for anything you design deliberately — themes, brand colors, gradients, and color scales. It is perceptually uniform, so changing the lightness number changes the apparent brightness by the same amount for every hue, which makes generating consistent light/dark variants and accessible contrast far easier than with HSL. Keep hex or rgb() for third-party snippets and quick prototyping, and use currentColor for icons that should match surrounding text. oklch() is supported in every current browser (Chrome and Edge 111+, Safari 15.4+, Firefox 113+), so a fallback is only needed for very old browsers.

Is hex or rgb better in CSS?

They are identical in capability — both describe an sRGB color by its red, green, and blue channels, and both now support alpha (an 8-digit hex like #ff5733cc, or rgb(255 87 51 / 80%)). Hex is more compact and is what most design tools export, so it dominates copy-paste workflows. rgb() is easier to read and to manipulate programmatically because the channels are plain decimal numbers. Neither is "better"; pick whichever your toolchain produces, and reach for hsl() or oklch() when you actually need to reason about or adjust a color by hand.

Does rgb() support transparency without rgba()?

Yes. In CSS Color Module Level 4, rgb() and rgba() are the same function, and so are hsl() and hsla(). You can put an alpha value on plain rgb() using the modern space-separated syntax with a slash: rgb(255 0 0 / 50%) or hsl(200 75% 50% / 0.5). The old comma form with a separate rgba() name still works everywhere for backward compatibility, but it is no longer required — the "a" variants are kept only as aliases.

What is oklch and why is it better than hsl?

oklch() specifies a color by Lightness, Chroma (colorfulness), and Hue in the OKLab color space, which was designed to match human perception. Its advantage over HSL is uniformity: in HSL, hsl(60 100% 50%) (yellow) looks much brighter than hsl(240 100% 50%) (blue) even though both claim 50% lightness, so building a color scale in HSL produces uneven, muddy results. In oklch() a fixed lightness looks equally bright across every hue, so you can rotate the hue for a palette or step the lightness for a scale and get predictable, harmonious results. oklch() can also reach wide-gamut P3 colors that HSL cannot express.

What is the difference between lab, lch, oklab, and oklch?

All four describe colors across the full range of human vision rather than just sRGB. lab() and lch() use the older CIELAB color space; lab() uses Cartesian a/b axes while lch() uses polar Chroma and Hue coordinates. oklab() and oklch() use the newer OKLab space, which fixes CIELAB's known weakness around blue hues and is more perceptually uniform. The relationship inside each pair is the same: the "ch" version is just the "ab" version expressed as Lightness plus Chroma and Hue, which is far easier for humans to reason about. In practice, prefer oklch() — it is the most uniform and the most convenient to author.

Do I still need color fallbacks for older browsers?

Rarely, in 2026. oklch(), oklab(), lab(), lch(), and hwb() are all supported across current Chrome, Edge, Safari, and Firefox and have been for two to four years, so the vast majority of visitors render them natively. If you must support very old browsers, declare an sRGB fallback first and the modern color second — background: #3366cc; background: oklch(55% 0.15 260); — because a browser applies the last declaration it understands and ignores syntax it cannot parse. For fine-grained control, wrap the modern value in @supports (color: oklch(0% 0 0)).

What is currentColor in CSS?

currentColor is a keyword that resolves to the computed value of the element's own color property (its text color). Using it for borders, SVG icon fills, box-shadows, or outlines makes those elements automatically track the text color — so a button that changes color on hover or in dark mode brings its icon and border along with no extra rules. It is not a color format you pick channels for; it is a live reference to whatever color is currently in effect.

Should I use HSL for a design system?

HSL is a big step up from hex for a design system because you can build variants by adjusting a single number, but it has a real flaw: its lightness is not perceptually uniform, so equal lightness steps look uneven across hues and equal-lightness colors do not have equal contrast. oklch() solves exactly this and is the better foundation for a modern token system or theme in 2026. If your tooling or team is not ready for oklch(), HSL remains a reasonable and widely understood choice — just expect to hand-tune brightness when you rotate hues.

CSScolor formatsweb developmentmodern CSSoklch