RGB to HSL Converter
rgb(59, 130, 246) converts to hsl(217, 91%, 60%). The hue 217° places this color on the blue part of the color wheel, the 91% saturation means it is nearly fully vivid, and 60% lightness puts it at a medium brightness. HSL separates color identity from intensity, which makes it far easier to work with programmatically than RGB.
What HSL Means
HSL stands for Hue, Saturation, Lightness. Each component describes a different quality of a color:
| Component | Range | Meaning |
|---|---|---|
| Hue | 0° to 360° | Position on the color wheel |
| Saturation | 0% to 100% | Color intensity (0% = gray) |
| Lightness | 0% to 100% | Brightness (0% = black, 100% = white) |
The color wheel positions for hue:
0° / 360° — Red
60° — Yellow
120° — Green
180° — Cyan
240° — Blue
300° — Magenta
hsl(217, 91%, 60%) sits at 217°, between cyan (180°) and blue (240°), closer to blue. At 91% saturation it is nearly fully vivid. At 60% lightness it is slightly above the pure color midpoint.
Why HSL Is Better for Programmatic Color
With RGB, there is no direct channel for brightness. To lighten rgb(59, 130, 246), you need to scale all three channels towards 255 while preserving their ratios. To darken it, scale towards 0. The math is error-prone and non-intuitive.
With HSL, you adjust one value:
/* Base color */
--color: hsl(217, 91%, 60%);
/* Lighter variant — just increase lightness */
--color-light: hsl(217, 91%, 75%);
/* Darker variant — just decrease lightness */
--color-dark: hsl(217, 91%, 40%);
/* Desaturated (muted) variant */
--color-muted: hsl(217, 30%, 60%);
/* Complementary color — rotate hue by 180° */
--color-complement: hsl(37, 91%, 60%);
This pattern is how design systems generate full color palettes from a single base hue. Libraries like Tailwind’s palette, Radix Colors, and Polished all operate in HSL or a similar cylindrical model.
Conversion Algorithm
The conversion from RGB to HSL involves normalizing channels to [0, 1], finding the min and max channel values, and deriving each HSL component:
function rgbToHsl(r, g, b) {
r /= 255;
g /= 255;
b /= 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
const delta = max - min;
let h = 0;
let s = 0;
const l = (max + min) / 2;
if (delta !== 0) {
s = delta / (1 - Math.abs(2 * l - 1));
if (max === r) h = ((g - b) / delta) % 6;
else if (max === g) h = (b - r) / delta + 2;
else h = (r - g) / delta + 4;
h = Math.round(h * 60);
if (h < 0) h += 360;
}
return {
h,
s: Math.round(s * 100),
l: Math.round(l * 100)
};
}
rgbToHsl(59, 130, 246); // { h: 217, s: 91, l: 60 }
# Python — note colorsys uses HLS order, not HSL
import colorsys
r, g, b = 59 / 255, 130 / 255, 246 / 255
h, l, s = colorsys.rgb_to_hls(r, g, b)
print(round(h * 360), round(s * 100), round(l * 100))
# 217 91 60
CSS hsl() Function
CSS accepts HSL colors natively:
/* Modern syntax (CSS Color Level 4) — no commas */
color: hsl(217 91% 60%);
/* With alpha */
color: hsl(217 91% 60% / 0.5);
/* Legacy syntax */
color: hsla(217, 91%, 60%, 0.5);
The modern syntax without commas is supported in all current browsers and is what CSS Color Level 4 standardizes. Both forms produce the same result.
HSL in Design Systems
HSL-based custom properties are a standard pattern for theming:
:root {
--brand-hue: 217;
--brand-saturation: 91%;
--color-50: hsl(var(--brand-hue) var(--brand-saturation) 95%);
--color-100: hsl(var(--brand-hue) var(--brand-saturation) 90%);
--color-200: hsl(var(--brand-hue) var(--brand-saturation) 80%);
--color-500: hsl(var(--brand-hue) var(--brand-saturation) 60%);
--color-700: hsl(var(--brand-hue) var(--brand-saturation) 40%);
--color-900: hsl(var(--brand-hue) var(--brand-saturation) 20%);
}
Change --brand-hue and the entire scale shifts. This is the foundation of single-token theming in design systems.
Limitations of HSL
HSL is intuitive but not perceptually uniform. Two colors with the same HSL lightness value will not look equally bright to human eyes. Yellow at hsl(60, 100%, 50%) looks noticeably lighter than blue at hsl(240, 100%, 50%).
For color systems that need to be visually consistent across hues (accessibility-focused palettes, data visualization), oklch is a better choice. It is a perceptually uniform model where equal changes in lightness produce equal-looking changes across all hues. CSS supports it natively: oklch(60% 0.15 250).