HSL Color: Hue, Saturation and Lightness in CSS
hsl() sets a colour by hue (an angle 0 to 360 on the colour wheel), saturation (0% grey to 100% vivid) and lightness (0% black to 100% white): hsl(199 89% 60%). An optional slash alpha adds opacity.
Why it matters
HSL is the format you tweak by hand. Want a darker shade of the same colour? Drop the lightness. A muted version? Cut the saturation. That is far more intuitive than juggling three RGB channels, where nudging one channel shifts hue, saturation and lightness all at once.
Designers reach for HSL because the three axes map to what you see. The honest limitation: HSL lightness is not perceptual, so two colours at 50% lightness can look wildly different in brightness. Pure yellow at 50% lightness reads far brighter than pure blue at the same setting. For palettes that need to stay visually even, oklch() is the upgrade.
How it works
The hue is an angle 0 to 360 on the colour wheel:
0and360are red.120is green.240is blue.
Saturation ranges from 0% (grey, no colour) to 100% (vivid, fully saturated). Lightness ranges from 0% (black) to 100% (white); 50% is the "pure" colour.
So hsl(199 89% 60%) is a hue of 199 (a cyan-blue), nearly fully saturated, and shifted up in lightness to a bright tone.
Modern CSS writes it space-separated: hsl(199 89% 60%). The legacy comma form still works: hsl(199, 89%, 60%). The hsla() function is now just an alias; add alpha with the slash syntax: hsl(199 89% 60% / 0.5).
What does not matter
HSL percentages do not map linearly to perceptual brightness. hsl(60 100% 50%) (pure yellow) reads far brighter than hsl(240 100% 50%) (pure blue), even though both are at the same 50% lightness. This is not a bug; it reflects how the human eye weights different hues. If you need perceptually even lightness, switch to oklch().
The choice between legacy comma syntax and modern space-separated syntax is purely about readability and browser support. Space-separated is slightly cleaner, but both work in all modern browsers.
Code example
/* Build a palette by fixing hue, varying lightness for tints and shades */
:root {
--hue-blue: 199;
--brand-light: hsl(var(--hue-blue) 89% 75%); /* Tint: lighter */
--brand-main: hsl(var(--hue-blue) 89% 50%); /* The pure colour */
--brand-dark: hsl(var(--hue-blue) 89% 25%); /* Shade: darker */
}
/* With alpha for semi-transparent overlays */
.overlay {
background: hsl(199 89% 50% / 0.6);
}
/* Wrong: trying to be too clever with the wheel */
.text-primary {
color: hsl(0 100% 50%); /* Pure red. Bright, but not readable on every background. */
}
How Scalpel Color shows it
Open the Picker tab. The HSL row shows the current colour's hue, saturation and lightness. You can adjust the hue with a slider (0 to 360), then dial saturation and lightness up and down. The header's format select lets you switch to hex, rgb(), or another format if you prefer.