Every front-end developer has copy-pasted a hex code from Figma, only to realize the CSS property they need requires rgb() - or the animation library expects HSL. Color format confusion wastes time and introduces bugs. This guide walks through every format you'll encounter, when to use each, and exactly how to convert between them.
1. Why Color Formats Matter
The web supports many color formats - and they're not interchangeable in every context. Some CSS properties accept only specific formats. Some JavaScript APIs require numeric values. Print workflows use CMYK. Modern CSS Level 4 introduces perceptually uniform spaces like OKLCH.
Choosing the right format affects:
- Opacity control - only RGBA/HSLA/OKLCH support the alpha channel inline
- Programmatic manipulation - HSL is far easier to lighten/darken in JS
- Color interpolation - gradients look different in sRGB vs OKLCH
- Print accuracy - screens use RGB; printers use CMYK
- Perceptual consistency - OKLCH ensures equal-step lightness feels equal visually
2. HEX - What Each Character Means
A hex color like #2a56f0 encodes three 8-bit channels - Red, Green, Blue - as pairs of base-16 digits. Each pair ranges from 00 (0) to ff (255).
# 2a 56 f0 ↑ ↑ ↑ R G B (42) (86) (240) Calculation: R = 0x2a = 2×16 + 10 = 42 G = 0x56 = 5×16 + 6 = 86 B = 0xf0 = 15×16 + 0 = 240
3-digit shorthand: When both digits of each pair are identical, you can use the 3-digit form:
#aabbcc → #abc ✓ (valid shorthand) #2a56f0 → no shorthand possible (digits differ)
8-digit hex with alpha: CSS also supports #rrggbbaa where the last two digits control opacity:#2a56f0ff = fully opaque, #2a56f080 = 50% transparent.
3. RGB and RGBA - When Opacity Matters
rgb() expresses the same three channels as HEX but in decimal notation, making it easier to read and manipulate programmatically. rgba() adds the alpha channel as a 0–1 decimal.
/* Equivalent colors */ color: #2a56f0; color: rgb(42, 86, 240); /* With opacity */ background: rgba(42, 86, 240, 0.15); /* 15% tinted overlay */ background: rgba(42, 86, 240, 0.5); /* 50% semi-transparent */ /* Modern CSS syntax (space-separated, / for alpha) */ background: rgb(42 86 240 / 0.15);
RGB shines in JavaScript Canvas and WebGL contexts where you're passing numeric values to APIs. It's also the format used by getComputedStyle() - so when you read a color from the DOM, you'll always get back an rgb() string regardless of how you specified it.
4. HSL and HSLA - The Designer's Format
HSL stands for Hue, Saturation, and Lightness. It maps to how humans actually think about color - "a medium-bright blue" is far more intuitive than "42, 86, 240".
hsl(221, 85%, 55%)
↑ ↑ ↑
Hue Sat Light
221° 85% 55%
/* Hue: 0–360° on the color wheel
0/360 = red, 120 = green, 240 = blue
Saturation: 0% = grayscale, 100% = vivid
Lightness: 0% = black, 50% = pure hue, 100% = white */
/* Darkening is trivial with HSL */
.button { background: hsl(221, 85%, 55%); }
.button:hover { background: hsl(221, 85%, 45%); } /* -10% L */
.button:active { background: hsl(221, 85%, 35%); } /* -20% L */This is why HSL is a designer's best friend in CSS. You can tweak lightness and saturation independently without touching the hue - creating hover, active, and disabled states with a single number change.
Caveat: HSL is mathematically simple but not perceptually uniform. Two colors with the same HSL lightness value may look very different in actual brightness to the human eye (yellow at L 50% appears much brighter than blue at L 50%). For perceptual uniformity, use OKLCH.
5. CMYK - Print vs. Screen
CMYK (Cyan, Magenta, Yellow, Key/Black) is the color model used by physical printers. Unlike RGB which adds light, CMYK subtracts light by absorbing specific wavelengths via ink.
Important: CSS does not natively support CMYK
The web works in RGB color space. If you receive CMYK values from a print designer, you must convert to RGB before using them in CSS. The conversion is lossy - some CMYK colors (especially vivid cyans and magentas) cannot be exactly reproduced on screen.
/* CMYK to RGB conversion formula */ C = 0.46, M = 0.64, Y = 0, K = 0.06 R = 255 × (1 - C) × (1 - K) = 255 × 0.54 × 0.94 = 129 G = 255 × (1 - M) × (1 - K) = 255 × 0.36 × 0.94 = 86 B = 255 × (1 - Y) × (1 - K) = 255 × 1.00 × 0.94 = 240 Result: rgb(129, 86, 240) → #8156f0
6. OKLCH - The Modern CSS Color Level 4 Format
OKLCH is the newest and most powerful color format for CSS, part of the CSS Color Level 4 specification. It stands for OK-LCH: Lightness, Chroma, Hue in the Oklab perceptual color space.
The key difference from HSL: OKLCH is perceptually uniform. When you change the L value by 10%, the perceived lightness actually changes by the same amount regardless of hue. This solves HSL's biggest problem.
/* OKLCH syntax */
oklch(L C H)
oklch(L C H / alpha)
/* L: 0 (black) to 1 (white) - or 0% to 100% */
/* C: chroma 0 (gray) to ~0.4 (vivid) */
/* H: hue angle 0–360° */
/* Example: vivid indigo */
color: oklch(0.55 0.22 264);
/* Generating a perceptually uniform scale is trivial: */
.brand-100 { color: oklch(0.95 0.10 264); }
.brand-300 { color: oklch(0.80 0.15 264); }
.brand-500 { color: oklch(0.55 0.22 264); }
.brand-700 { color: oklch(0.38 0.18 264); }
.brand-900 { color: oklch(0.22 0.12 264); }
/* Wide-gamut colors (P3, Rec2020 displays) */
color: oklch(0.65 0.35 264); /* beyond sRGB - vivid on modern screens */OKLCH has excellent browser support (Chrome 111+, Firefox 113+, Safari 15.4+) and is the recommended format for new CSS projects in 2026 and beyond.
7. Quick Conversion Formulas
Here are the key conversion formulas you'll need most often:
/* ── HEX → RGB ─────────────────────────────── */
hex = "#2a56f0"
R = parseInt(hex.slice(1,3), 16) // 42
G = parseInt(hex.slice(3,5), 16) // 86
B = parseInt(hex.slice(5,7), 16) // 240
/* ── RGB → HEX ─────────────────────────────── */
hex = '#' + [R, G, B]
.map(v => v.toString(16).padStart(2, '0'))
.join('') // "#2a56f0"
/* ── RGB → HSL ─────────────────────────────── */
r = R/255, g = G/255, b = B/255
max = Math.max(r,g,b), min = Math.min(r,g,b)
L = (max + min) / 2
if (max === min) { H = S = 0 }
else {
d = max - min
S = L > 0.5 ? d/(2-max-min) : d/(max+min)
switch(max) {
case r: H = ((g-b)/d + (g<b?6:0)) / 6; break
case g: H = ((b-r)/d + 2) / 6; break
case b: H = ((r-g)/d + 4) / 6; break
}
}
// H×360, S×100%, L×100% → hsl(221, 85%, 55%)
/* ── HSL → RGB ─────────────────────────────── */
// Use CSS color-mix() or a library like chroma-js
// for production; manual formula is error-prone8. Which Format to Use Where
| Context | Recommended | Why |
|---|---|---|
| CSS variables / design tokens | OKLCH or HSL | Easy to manipulate programmatically |
| Static CSS colors | HEX | Shortest, most widely understood |
| CSS with opacity | rgb() / oklch() + alpha | Inline alpha channel support |
| CSS animations / transitions | HSL or OKLCH | Smooth interpolation |
| Canvas / WebGL | RGB (0–255) | APIs expect numeric channels |
| SVG fill / stroke | HEX or rgb() | Best SVG compatibility |
| Print / PDF export | CMYK | Printer color model |
| Design tokens (Figma/Style Dict) | HEX or OKLCH | Universal toolchain support |
| Wide-gamut P3 displays | OKLCH | Only format that accesses P3 gamut in CSS |
Share this article
Convert Any Color Format Instantly
Paste any HEX, RGB, HSL, CMYK, or OKLCH value into ColorPeek's converter and get all formats at once - with one-click copy for each.