Color Format Guide: HEX vs RGB vs HSL vs oklch
Web development involves four primary color formats — HEX, RGB, HSL, and the newer oklch — and each has a distinct role in a professional workflow. Understanding what each format encodes, how they relate mathematically, and when to reach for each one eliminates the confusion that slows down design and development handoffs. This guide explains all four formats from first principles, with conversion examples you can verify in the WikiPlus Color Picker, and practical guidance on when each format is the right choice.
HEX: The Web Standard
HEX color notation represents colors as a six-character (or three-character shorthand) hexadecimal string preceded by a hash: #RRGGBB. Each pair of characters encodes one color channel — red, green, blue — as a value from 00 (0 decimal) to FF (255 decimal). Examples: #FF0000 — pure red (R=255, G=0, B=0) #00FF00 — pure green #0011FF — the WikiPlus brand blue #FFFFFF — white (all channels at maximum) #000000 — black (all channels at zero) The three-character shorthand #RGB is equivalent to #RRGGBB when each pair has identical digits: #FFF is the same as #FFFFFF, and #3AC is the same as #33AACC. CSS also supports an eight-character HEX with an alpha channel: #RRGGBBAA, where the last two characters set opacity. #FF000080 is a semi-transparent red (alpha 128/255 ≈ 50%). Why HEX is ubiquitous: — It is a single compact token — easy to copy, paste, and embed in any context — Universally accepted by all browsers, design tools, and code editors — Visually distinctive; experienced developers and designers can roughly estimate a color's family from the hex string — Not human-intuitive for adjustments — changing lightness or saturation requires manual math or a conversion tool HEX remains the lingua franca of web colors. Even when your source of truth is HSL or oklch, sharing colors with clients, generating design specification documents, or copy-pasting into legacy codebases almost always requires HEX.
RGB: Channels and Component Access
RGB notation expresses a color as three decimal integers, each from 0 to 255, one per channel: rgb(255, 99, 71). The CSS color function also accepts a modern syntax with spaces and an optional alpha: rgb(255 99 71 / 70%). RGBA adds an alpha (transparency) channel as a fourth value: rgba(255, 99, 71, 0.7). In modern CSS, the / separator syntax handles both opaque and transparent colors in the same function: rgb(255 99 71 / 0.7). RGB maps directly to the physics of light and digital displays. Every pixel on an LCD or OLED screen mixes three channels of light — red, green, and blue — to produce the full visible spectrum (additive color mixing). The R, G, and B values you specify in CSS correspond directly to the intensities of those sub-pixels. When to use RGB: — Canvas API and WebGL: the CanvasRenderingContext2D fillStyle and other canvas properties accept rgb() strings, and WebGL passes color data as float arrays derived from 0–1 normalized RGB values — Image processing in JavaScript or Node.js: pixel data from getImageData() is a Uint8ClampedArray of [R, G, B, A, R, G, B, A, ...] values, directly in RGB — Programmatic color manipulation when you need channel-level access — Backend/server environments (Node.js, Python) that process images RGB is not intuitive for color selection or theming. No human naturally thinks in terms of 'I need 20 more units of red.' For design decisions, convert to HSL or oklch first, make your adjustment, then convert back to RGB or HEX for the output.
HSL: Intuitive for Designers
HSL stands for Hue, Saturation, Lightness. It encodes color information in terms that map to human perceptual concepts: Hue (0–360): the base color, expressed as an angle on the color wheel. 0° and 360° are red, 120° is green, 240° is blue. Values between these give the secondary and tertiary hues: 60° is yellow, 180° is cyan, 300° is magenta. Saturation (0–100%): the intensity or purity of the color. 100% is the most vivid version of the hue; 0% is pure gray (the hue value is irrelevant at 0% saturation). Lightness (0–100%): how bright the color appears. 0% is always black regardless of hue and saturation; 100% is always white; 50% is the 'pure' mid-tone of the hue. CSS syntax: hsl(120 100% 50%) for fully saturated, mid-lightness green. With alpha: hsl(120 100% 50% / 0.5). Why HSL is powerful for theming: — To create a lighter tint: increase the lightness value — To create a darker shade: decrease the lightness value — To desaturate for muted UI elements: decrease saturation — To rotate through related hues: change the hue angle With CSS custom properties, HSL enables dynamic theming: :root { --hue: 240; --color-primary: hsl(var(--hue) 80% 55%); } Changing --hue updates the entire theme. This is impossible with HEX or RGB without JavaScript. HSL limitation: it is not perceptually uniform. A bright yellow at hsl(60 100% 50%) appears much lighter than a vivid blue at hsl(240 100% 50%) even though both have 50% lightness. This makes it unreliable for generating accessible color palettes automatically. oklch addresses this limitation.
oklch: Perceptually Uniform and Modern
oklch (Oklab Lightness Chroma Hue) is a relatively new color space in CSS, standardized as part of CSS Color Level 4. It was designed explicitly to be perceptually uniform — meaning equal numeric changes in any parameter produce equal perceived changes in appearance. The three parameters: L (Lightness, 0–1 or 0%–100%): perceived brightness, uniform across all hues C (Chroma, 0–0.4 approximately): colorfulness/saturation; 0 is gray, higher values are more vivid H (Hue, 0–360): the color angle, similar to HSL's hue CSS syntax: oklch(0.63 0.22 29) or oklch(63% 0.22 29) Why oklch is superior for design systems: — Generate a 5-step tonal palette (light to dark) by evenly stepping the L value — the steps look perceptually even across all hues, unlike HSL where yellows appear much lighter than blues at the same L value — Build accessible color pairs with predictable contrast by working in a space where luminance is linear — Produce dark mode variants by flipping the lightness: oklch(0.85 0.22 29) for a light variant, oklch(0.35 0.22 29) for a dark one Browser support: oklch is supported in Chrome 111+, Firefox 113+, Safari 15.4+, and Edge 111+. As of 2026, all actively maintained browsers support it. Internet Explorer does not, but IE is no longer in active support. For progressive enhancement: define a HEX fallback before the oklch value. Browsers that do not understand oklch ignore it and fall back to the preceding HEX value. The WikiPlus Color Picker displays oklch values for every color you pick, making it easy to incorporate this format into your design tokens immediately.
Frequently Asked Questions
- Which color format should I use in CSS in 2026?
- Use oklch for design tokens and dynamic color generation, and HEX or rgb() for static colors in component stylesheets. oklch's perceptual uniformity makes it the best choice for systematic color decisions — palettes, themes, dark mode — where you want equal adjustments to produce equal perceived results. HEX remains the most portable format for sharing colors across tools and for static values where no programmatic adjustment is needed. For properties that set transparency, rgb() with the slash alpha syntax (rgb(255 99 71 / 0.5)) is clean and universally supported.
- How do I convert a HEX color to HSL?
- The conversion involves two steps. First, convert HEX to normalized RGB (divide each 0–255 value by 255 to get values from 0 to 1). Then apply the HSL formula: find the max and min of R, G, B; lightness is (max+min)/2; saturation is (max-min)/(1-|2L-1|); hue depends on which channel is maximum. The WikiPlus Color Picker performs this conversion automatically — enter any HEX value in the input field and the HSL value appears instantly. For programmatic conversion in JavaScript, the CSS Color 4 specification provides the exact formulas, or use a library like chroma.js or culori.
- Does oklch cover the same colors as sRGB?
- oklch covers the entire sRGB gamut and extends well beyond it into the P3 and Rec. 2020 wide-gamut color spaces. For colors within sRGB (the traditional web color gamut), oklch values map to identical displayed colors in any browser. For wide-gamut colors — particularly vivid greens and reds that are outside sRGB — oklch can specify them, and devices with P3 displays (modern iPhones, MacBooks, and many monitors) will show the wider gamut. Browsers on non-wide-gamut displays will gamut-map the color to the nearest sRGB equivalent. This makes oklch forward-compatible with wide-gamut displays.