Why this comparison still matters
Every CSS color value you write is one of three formats: HEX (#10b981), RGB (rgb(16, 185, 129)), or HSL (hsl(160, 84%, 39%)). They all describe the same sRGB colors, so the browser renders them identically. The differences are in compactness, readability, programmatic manipulation, and transparency support — and those differences matter more than people realize. CSS Color Module Level 4 (shipped in all major browsers by 2023) also added new syntax that shifts the trade-offs. This article compares the three formats and recommends when to reach for each.
HEX: compact, universal, terse
HEX notation represents a color as a hash followed by hexadecimal byte values for red, green, and blue: #RRGGBB. #ff5733 means red=255, green=87, blue=51. The shorthand #RGB expands to #RRGGBB, so #f53 becomes #ff5533. HEX has been part of CSS since CSS 1 (1996) and is supported everywhere — every browser, every design tool, every image format that embeds color metadata.
The advantages are compactness and convention. A HEX color is 7 characters (#RRGGBB); the same color in rgb() is 14+ characters. Designers and developers have memorized common HEX values — #fff is white, #000 is black, #f00 is red — and HEX is what Figma, Sketch, and the macOS color picker copy to your clipboard by default. HEX is also the only format that survives copy-paste through plain text without quotes or commas getting mangled.
The disadvantages are readability and manipulation. Is #d4881f more red or more green? You have to mentally decode each byte. Want to darken it by 20%? You have to convert to HSL or RGB, do math, and convert back — there's no native way to manipulate a HEX color in CSS. Alpha transparency was historically awkward: #RRGGBBAA (8-digit HEX) was added in CSS Color 4 and is now widely supported, but it's less readable than rgba().
HEX is the right choice for color values stored in configuration, design tokens, and anywhere you need a compact, universally understood representation. It's also the right choice when you want a designer's Figma value to round-trip through code unchanged.
RGB: explicit, channel-oriented
RGB notation lists the red, green, and blue channel values explicitly: rgb(255, 87, 51) or the modern space-separated form rgb(255 87 51) added in CSS Color 4. The rgba() function adds an alpha channel — historically rgba(255, 87, 51, 0.5), now rgb(255 87 51 / 50%) in the new syntax. CSS Color 4 also allows percentages alongside numbers and the none keyword for missing components.
RGB's strength is explicitness. Each channel is a separate number you can reason about and manipulate programmatically. Want to halve the red channel? rgb(127 87 51) is obvious. Mixing two colors is channel-wise interpolation — easy to write and reason about. The alpha channel is a first-class citizen via rgba() or the new slash syntax, which made RGB the default for translucent colors before 8-digit HEX existed.
RGB's weakness is human perception. Saying a color is 'rgb(217, 136, 31)' tells you the channel values but nothing about the color's hue, saturation, or lightness. Generating a color palette (a base color plus lighter and darker variants) is awkward in RGB because changing lightness requires shifting all three channels in coordinated ways that depend on the hue. Designers don't think in RGB; they think in hue, saturation, and lightness.
RGB is the right choice when you're doing channel-wise math (color mixing, blending modes, image processing), when you need explicit per-channel alpha, or when you're working with values from graphics APIs that natively use RGB (Canvas, WebGL, image libraries).
HSL: perceptual, palette-friendly
HSL notation represents a color as hue (0–360 degrees on the color wheel), saturation (0–100%), and lightness (0–100%): hsl(34, 76%, 49%) for the same orange as above. The hsla() function or the new hsl(34 76% 49% / 50%) form adds alpha.
HSL's strength is perceptual alignment. Hue, saturation, and lightness map roughly to how humans describe colors — 'a saturated orange at medium lightness' is hsl(30, 100%, 50%). Generating a palette is trivial: hold hue and saturation constant, vary lightness from 10% to 90% in 10% steps, and you get a clean ramp from dark to light. Darken a color? Lower lightness. Saturate it? Raise saturation. Compute complementary, analogous, or triadic colors? Add 180, ±30, or ±120 to the hue. This is why design systems (Tailwind, Material, Radix) define color scales in HSL.
HSL's weakness is that it's not perfectly perceptually uniform. A lightness of 50% in yellow looks much lighter than 50% in blue, because human eyes are more sensitive to yellow-green light. Two colors with the same HSL lightness can have very different perceived brightness, which can cause contrast problems in accessible design. The newer LCH and OKLCH color spaces (CSS Color 4) address this with perceptually uniform lightness, and are worth adopting for new design systems. But HSL remains far better than RGB or HEX for human manipulation.
HSL is the right choice for design systems, theming (CSS custom properties that adjust lightness), generating palettes programmatically, and anywhere humans will read or edit the color value. It's also the format to use when computing accessible color combinations, since contrast ratios depend on relative luminance which is easier to reason about in HSL.
The CSS Color 4+ landscape
CSS Color Module Level 4 (Candidate Recommendation 2022, shipped in all major browsers by 2023) substantially expanded the color toolkit. The headline additions are lab(), lch(), oklab(), and oklch() — perceptually uniform color spaces that solve HSL's biggest weakness. In OKLCH, equal lightness steps look equally spaced to the human eye, which makes palette generation dramatically more predictable. Design systems like Radix Colors and Tailwind 4 have moved to OKLCH for this reason. The color() function gives access to wider gamuts (display-p3, rec2020, a98-rgb) for HDR-capable displays, letting you specify colors that simply cannot exist in sRGB.
Practical guidance for 2025: use HEX or rgb() for hand-written values where you want broad compatibility and designer round-tripping. Use HSL for design-system tokens where perceptual uniformity is not critical. Use OKLCH for new design systems where palette consistency matters. Avoid lab() unless you have a specific reason — OKLCH is the human-friendly form (the 'O' is a perceptual remapping that makes hue, chroma, and lightness behave the way you would expect). The relative color syntax (color-mix(), color-contrast()) added in CSS Color 5 lets you compute shades and tints directly in CSS without preprocessors, reducing the need to generate palettes in JavaScript.
Alpha channel history matters for compatibility. The rgba() and hsla() functions date to CSS 3 (2003) and are universally supported. The 8-digit HEX (#RRGGBBAA) and 4-digit shorthand (#RGBA) were added in CSS Color 4 and have been supported in all major browsers since 2018–2019. The modern space-separated syntax with slash alpha (rgb(255 87 51 / 50%)) is also CSS Color 4 and is the preferred form going forward — the legacy comma-separated form is still supported but flagged as legacy in the spec.
Side-by-side comparison
When to choose which
Choose HEX for color values stored in configuration, design tokens, or anywhere compactness and convention matter. If a designer hands you #10b981 from Figma, use #10b981 in your CSS — converting to HSL just to feel modern adds friction without benefit. HEX is also the right choice for email templates (where parser quirks rule out newer syntax) and for any context where the value must survive plain-text round-trips.
Choose RGB when you're doing channel-wise computation: mixing colors, applying blend modes, processing images, or working with WebGL and Canvas APIs that natively use RGB tuples. RGB is also a reasonable choice when you need explicit per-channel values for debugging ('why is this color too red?'). The CSS Color 4 space-separated syntax (rgb(255 87 51)) and slash-separated alpha (rgb(255 87 51 / 50%)) make RGB more readable than the legacy comma form.
Choose HSL when you're designing a color system, generating palettes, or building themeable components where lightness varies. Tailwind, Radix Colors, and Material Design all define their color scales in HSL for exactly this reason. HSL is also the right choice for CSS custom properties that compute tints and shades via hsl(var(--hue) var(--sat) calc(var(--light) + 10%)).
For new design systems in 2025, seriously consider OKLCH (the perceptually uniform successor to HSL, part of CSS Color 4). It solves HSL's uneven lightness and lets you generate palettes where each step actually looks evenly spaced. Browser support is universal as of 2023. The oklch.com color picker by Evgeny Kozlov is the easiest way to explore the format.
Conclusion
HEX, RGB, and HSL all describe the same sRGB colors, so the browser doesn't care which you use. What differs is how humans and code interact with the values. HEX wins on compactness and convention — use it for stored values and Figma round-trips. RGB wins on channel-wise math — use it for blending and graphics. HSL wins on human manipulation and palette generation — use it for design systems and theming. For greenfield work, consider OKLCH, which combines HSL's intuition with perceptual uniformity. The format you pick is a tool, not a religion — pick the one that makes your task easier.