How to Convert HEX to RGB and HSL in Seconds
You have a HEX color code — maybe it came from a brand guidelines document, a design file, or a style guide — and you need it in RGB for a canvas API call, or in HSL for a CSS theming system, or in oklch for a modern design token. Converting between these formats manually is time-consuming and error-prone. The WikiPlus Color Picker converts any color between all four formats instantly, but understanding the underlying conversion process is valuable — it helps you reason about color relationships and catch errors when values do not look right. This article explains the math and gives you practical shortcuts.
Converting HEX to RGB: The Simple Step
HEX and RGB are two notations for exactly the same information: the intensity of the red, green, and blue channels on a scale from 0 to 255. Converting between them is a direct translation. HEX to RGB: Split the six-character HEX into three pairs: #FF6347 → FF, 63, 47 Convert each pair from hexadecimal to decimal: FF (hex) = 255 (decimal) 63 (hex) = 99 (decimal) 47 (hex) = 71 (decimal) Result: rgb(255, 99, 71) — Tomato red RGB to HEX: Convert each decimal value to a two-character hexadecimal: 255 → FF 99 → 63 71 → 47 Concatenate with #: #FF6347 In JavaScript: HEX to RGB: const [r, g, b] = hex.slice(1).match(/../g).map(x => parseInt(x, 16)) RGB to HEX: '#' + [r, g, b].map(x => x.toString(16).padStart(2, '0')).join('') For the three-character shorthand #RGB, each digit is doubled before conversion: #F64 → #FF6644 → rgb(255, 102, 68). The WikiPlus Color Picker performs this conversion automatically. Paste any HEX value into the HEX input field and the RGB value appears immediately. You can also paste an RGB value and get the HEX back. No need to do the arithmetic manually for routine conversions — but knowing the process helps you spot errors when a conversion seems off.
Converting HEX to HSL: Understanding the Math
Converting from HEX to HSL requires two steps: first convert HEX to normalized RGB (0–1 range), then apply the RGB-to-HSL formula. Step 1: Normalize RGB to 0–1 R' = R / 255, G' = G / 255, B' = B / 255 For #FF6347 (rgb 255, 99, 71): R' = 1.000, G' = 0.388, B' = 0.278 Step 2: Find Cmax, Cmin, and delta Cmax = max(R', G', B') = 1.000 (R is max) Cmin = min(R', G', B') = 0.278 Delta = Cmax - Cmin = 0.722 Step 3: Calculate Lightness L = (Cmax + Cmin) / 2 = (1.000 + 0.278) / 2 = 0.639 → 63.9% Step 4: Calculate Saturation If delta = 0, saturation = 0 (achromatic/gray). Otherwise: S = delta / (1 - |2L - 1|) = 0.722 / (1 - |2*0.639 - 1|) = 0.722 / 0.722 = 1.000 → 100% Step 5: Calculate Hue When Cmax is R: H = 60° * ((G' - B') / delta mod 6) H = 60° * ((0.388 - 0.278) / 0.722 mod 6) = 60° * (0.152 mod 6) = 60° * 0.152 ≈ 9.1° Result: hsl(9, 100%, 64%) — which is correct for Tomato red. For most day-to-day work, you do not need to do this by hand. The Color Picker performs the calculation instantly. But understanding the steps helps you debug situations where a converted value seems wrong and tells you why lightness in HSL does not map linearly to perceived brightness.
Converting to oklch: Perceptual Color Space
Converting to oklch involves a more complex transformation through multiple intermediate color spaces. The full pipeline is: sRGB → Linear RGB → XYZ D65 → Oklab → oklch. Each step involves a matrix multiplication and some non-linear transformations. The complete formula is not practical to apply by hand, which is why the Color Picker is particularly valuable for oklch conversion — it handles the multi-step calculation transparently. However, understanding the relationship between RGB/HSL values and oklch values helps you work more effectively with the format: L (Lightness) correlates with, but is not equal to, HSL lightness. oklch L is perceptually linear while HSL L is not. A yellow at HSL 50% lightness will have a much higher oklch L value than a dark blue at HSL 50% lightness. C (Chroma) correlates with HSL saturation. For sRGB colors, C ranges from 0 (gray) to approximately 0.4 (the most saturated colors in the sRGB gamut). Colors outside sRGB can have higher C values. H (Hue) is similar to HSL hue but measured in a slightly different space. The hue angles do not map exactly 1:1, but the general color families (red ~30°, yellow ~100°, green ~135°, blue ~265°, purple ~310°) are recognizable. A practical tip: for colors in the middle of the sRGB gamut (moderate saturation and lightness), the oklch H value will be close to the HSL H value. The biggest differences appear at very high saturation levels and at the extremes of lightness. The WikiPlus Color Picker shows all four format values simultaneously, so you can learn the oklch equivalents of colors you already know in HEX or HSL by experimenting in the tool.
Programmatic Color Conversion in JavaScript
For projects that need to convert colors programmatically (generating palettes, computing contrast ratios at runtime, building theming systems), having reliable conversion functions in JavaScript is essential. HEX to RGB: function hexToRgb(hex) { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; } RGB to HSL: function rgbToHsl(r, g, b) { r /= 255; g /= 255; b /= 255; const max = Math.max(r, g, b), min = Math.min(r, g, b); let h, s, l = (max + min) / 2; if (max === min) { h = s = 0; } else { const 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; } } return { h: h * 360, s: s * 100, l: l * 100 }; } For oklch conversion, use the culori library (npm install culori): import { parse, formatCss, oklch } from 'culori'; const color = oklch(parse('#FF6347')); formatCss(color); — this handles the full multi-step conversion correctly. For WCAG contrast ratio calculation: function getRelativeLuminance(r, g, b) { const linearize = c => c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4; const [R, G, B] = [r/255, g/255, b/255].map(linearize); return 0.2126 * R + 0.7152 * G + 0.0722 * B; } function contrastRatio(l1, l2) { const [lighter, darker] = l1 > l2 ? [l1, l2] : [l2, l1]; return (lighter + 0.05) / (darker + 0.05); }
Frequently Asked Questions
- Is there a quick way to convert a HEX color to RGB without a calculator?
- The fastest manual method is to split the HEX into pairs and recall that the hex digit values are: 0-9 map to 0-9, and A=10, B=11, C=12, D=13, E=14, F=15. For a two-digit hex like 'B4', compute (11 × 16) + 4 = 180. With practice, common values become memorized: FF=255, 80=128, 40=64. For routine work, the Color Picker is faster than mental arithmetic — paste the HEX and copy the RGB in under two seconds. Manual conversion is mainly useful for understanding what a value means at a glance.
- Why does my HSL lightness value not match the perceived brightness?
- HSL lightness is not perceptually linear. It is a mathematical average of the maximum and minimum RGB channel values, not a measure of how bright the color actually appears to human vision. A yellow (hsl(60 100% 50%)) appears much brighter than a blue (hsl(240 100% 50%)) even though both have 50% lightness, because the human eye is much more sensitive to green (present in yellow) than to blue. oklch L is perceptually calibrated, meaning equal L values look equally bright regardless of hue. Use oklch when you need predictable perceptual lightness — it is the right tool for generating accessible tonal scales.
- Can I convert colors between sRGB and wide-gamut color spaces?
- Yes, the Color Picker works in sRGB, which is the standard web gamut. oklch can represent colors beyond sRGB (P3 and Rec. 2020 gamuts), and modern browsers on P3-capable displays will show these wider-gamut colors. However, for colors you specify in HEX, RGB, or HSL — all of which are sRGB formats — the oklch equivalent will always be within the sRGB gamut. If you want to work with P3 colors, specify them directly in oklch with chroma values above approximately 0.26–0.28 (the sRGB boundary varies by hue). Wide-gamut colors are automatically gamut-mapped to sRGB on displays that do not support P3.