HEX vs RGB vs HSL vs OKLCH: Which Should You Use?
They all describe the same colors — #E63946, rgb(230, 57, 70), and hsl(355, 78%, 56%) are one pixel wearing three outfits. The formats differ in what they make easy. Pick the wrong one and you'll fight your tools; pick the right one and half your color math disappears.
A format is notation, not a promise about how a color will be used. Converting one exact sRGB color from HEX to RGB does not brighten, mute, or improve it; only the written coordinates change. A color space becomes important when you start adjusting those coordinates, generating related colors, blending, or moving beyond the sRGB gamut. Keep that distinction in mind and the alphabet soup becomes a set of practical choices rather than competing camps.
#E63946rgb(230 57 70)hsl(355 78% 56%)oklch(61.7% 0.198 22.8)HEX — the universal ID card
#RRGGBB, two hexadecimal digits per channel. HEX is compact, unambiguous, and understood by literally everything built since 1996. It's the format you paste into Slack, store in a config, and read out of a brand guide.
Use it for: storing and sharing exact colors.
Terrible at: being edited by humans. Quick — make #7B4FA2 10% lighter. Exactly.
Three-digit HEX such as #E34 is shorthand for doubled digits, #EE3344. Eight-digit HEX adds an alpha channel as the final pair, but support in modern CSS does not make it the clearest choice for every team. When transparency matters, an explicit functional notation such as rgb(230 57 70 / 60%) is often easier to review because the opacity is visible as a percentage.
RGB — how screens actually think
rgb(230, 57, 70) is the hardware truth: how much red, green, and blue light to emit, 0–255. It matters when you're compositing, working with canvas pixel data, or adding transparency (rgba, though modern CSS lets every format take alpha).
Use it for: programmatic pixel work, transparency, anything talking to a graphics API.
Terrible at: intuition. Nobody looks at three numbers and feels "dusty rose."
Most web RGB values refer to the sRGB color space. That shared reference is why a HEX value and its RGB equivalent normally round-trip cleanly. The same three channel numbers interpreted in another RGB space can describe a different color, so production assets also need correct color-profile handling. For ordinary CSS tokens, sRGB remains the compatibility baseline; for image and print workflows, profiles are part of the specification rather than optional metadata.
HSL — the first one made for humans
hsl(355, 78%, 56%) reads as hue, saturation, lightness — a color wheel position plus two sliders. Want it lighter? Raise L. Want it muted? Lower S. This is why design systems built their 50–900 scales on HSL for a decade, and why our Shades & Tints Generator and Harmony Generator think in hue-and-lightness terms.
Use it for: quick manual adjustments and hue rotations.
The catch: HSL lies about lightness. hsl(60, 100%, 50%) (yellow) and hsl(240, 100%, 50%) (blue) claim the same 50% lightness — but the yellow is blindingly bright and the blue is nearly black to your eye. Build a scale across hues with HSL and the steps come out visually uneven.
hsl(60 100% 50%)hsl(240 100% 50%)OKLCH — HSL that tells the truth
oklch(63.1% 0.211 22.2) is the modern answer: lightness, chroma, hue in the OKLab perceptual space, supported in every major browser since 2023. Its superpower is that L means what your eye sees. Two colors with the same OKLCH lightness genuinely look equally bright — across any hue. That makes it the right space for design tokens, theme ramps, and "shift the hue but keep the perceived weight" operations that HSL botches.
Use it for: new design systems, dark-mode ramps, palette scales that must feel even.
The catch: chroma limits vary by hue and lightness (that's physics, not a bug), and legacy tooling may not parse it yet.
OKLCH is especially useful when a system needs related states. Holding hue and chroma roughly steady while changing lightness produces steps that are more visually predictable than equivalent HSL edits. Holding lightness steady while rotating hue makes categorical colors feel closer in visual weight. It is still not automatic accessibility: perceptual evenness does not guarantee a text/background pair meets a WCAG ratio, and two equal-lightness colors may be intentionally poor foreground and background partners.
Some OKLCH coordinates sit outside a display's available gamut. A browser must map an unrenderable color to something it can show, and that mapping can reduce chroma or otherwise alter the requested result. Check saturated colors on the devices and gamut you actually target. For a shared token library, document whether a value is intended for sRGB-only output or may use a wider gamut.
CMYK — for ink, not screens
cmyk(0%, 75%, 70%, 10%) describes ink coverage for print. Screens can only approximate it, and the same CMYK values print differently on different stock. Treat on-screen CMYK as a starting estimate for your print vendor, never as a promise.
A mathematical RGB-to-CMYK conversion cannot account for a printer's press condition, ink set, paper, total ink limit, or ICC profile. Use the converted values to start a conversation, then rely on the printer's profile and a physical proof for brand-critical work. Keep the original screen color alongside the approved print specification; neither should silently replace the other.
Stop converting by hand: the Color Code Converter gives you all five formats for any color with one-click copy — including OKLCH, computed with the real OKLab math.
Rules of thumb
- Store colors as HEX — maximum compatibility, zero ambiguity.
- Manipulate colors in OKLCH if your stack allows it, HSL if it doesn't.
- Composite in RGB — it's what the canvas and the GPU speak anyway.
- Hand off to print in CMYK, and ask the printer for a proof.
- Building a 50–900 scale? Generate it in a lightness-aware way (our Shades generator re-steps lightness at fixed hue) rather than multiplying HEX values and hoping.
Separate source values from derived values
Teams create avoidable confusion when a converted value and an adjusted value receive the same name. Suppose an eyedropper returns #E63946. Its RGB, HSL, and OKLCH coordinates are equivalent descriptions of the sampled pixel. If you then raise OKLCH lightness so the color works on a dark background, the result is a new implementation color. Preserve the source measurement, name the derived token for its role, and record why it changed.
The same rule applies to opacity. A translucent foreground has its own channels and alpha, but the color a person sees is the composite over a particular background. Store the unblended token when the layer must remain reusable; test the composited result when evaluating contrast. A screenshot contains the final composite, so an exact pixel pick from that screenshot cannot uniquely recover the original foreground and opacity.
A practical CSS strategy
Use semantic custom properties for roles, not format names: --surface, --text, --action, and --action-hover communicate intent better than --blue-1 through --blue-4 alone. The stored value may be HEX for a fixed legacy token or OKLCH for a generated scale. Components should consume the role, leaving the palette layer responsible for the notation and fallbacks.
When older clients are in scope, put the broadly supported declaration first and the newer one second. Browsers that understand the later value use it; others retain the first. Keep both values visually close and test the fallback rather than treating it as an emergency approximation. If the product targets modern browsers only, one OKLCH declaration may be the simpler, maintainable choice—compatibility requirements, not fashion, should decide.
For state generation, choose one color space and use it consistently. Mixing an HSL hover adjustment, an RGB opacity pressed state, and a hand-picked HEX disabled state makes the scale difficult to explain. Generate candidates in OKLCH or another chosen working space, convert only at the delivery boundary if required, then measure the actual rendered pairs with the Contrast Checker.
One workflow, all formats
Pull a palette from a photo with the Palette Extractor (or sample exact pixels yourself — see how to pick colors from any image), copy the HEX for your tokens, convert to OKLCH in the Converter when you need to tune lightness honestly, and verify the result still reads with the Contrast Checker. Formats aren't a religion — they're screwdriver heads. Match the head to the screw.
Try it yourself
Everything above is hands-on in the free tools — no signup, nothing uploaded: Color Code Converter · Image Color Picker. More reads in the guides section.