Glossary

HSL

HSL is a color model that describes a color by hue angle, saturation percentage and lightness percentage, which makes it easier to tweak by hand than raw RGB numbers. HSL stands for Hue, Saturation, Lightness. CSS supports it through the hsl() function in CSS Color Module Level 4. The hue is an angle on a circle, and 0 degrees, 120 degrees and 240 degrees are red, green and blue.

How it works

HSL is a re-arrangement of RGB, not a different set of colors. It reads the red, green and blue channels, finds the largest and smallest, and derives three numbers from them.

  • Hue: the angle around the color wheel. CSS spreads hues from sRGB red at 0deg, so green is 120deg and blue is 240deg. Angles wrap, so 360deg and 720deg are red again. The hue accepts a plain number (degrees) or an angle unit.
  • Saturation: 0% is a gray, 100% is a fully saturated color.
  • Lightness: 50% is the normal color, 0% is black and 100% is white, whatever the hue and saturation are.

Lightness is the average of the largest and smallest channel. Saturation is the spread between them divided by how much room the lightness leaves.

CSS has two syntaxes. The modern one is hsl(217 91% 60% / 0.5). The legacy one is hsl(217, 91%, 60%), which requires percent signs on saturation and lightness. If saturation is negative, CSS clamps it to 0% when parsing.

function rgbToHsl(r, g, b) {
  [r, g, b] = [r, g, b].map(v => v / 255);
  const max = Math.max(r, g, b), min = Math.min(r, g, b), c = max - min;
  let h = 0;
  if (c) h = max === r ? ((g - b) / c + 6) % 6 : max === g ? (b - r) / c + 2 : (r - g) / c + 4;
  const l = (max + min) / 2;
  const s = c === 0 ? 0 : c / (1 - Math.abs(2 * l - 1));
  return `hsl(${(h * 60).toFixed(1)} ${(s * 100).toFixed(1)}% ${(l * 100).toFixed(1)}%)`;
}
console.log(rgbToHsl(59, 130, 246));
console.log(rgbToHsl(255, 0, 0));
console.log(rgbToHsl(255, 255, 0));
console.log(rgbToHsl(0, 0, 255));
console.log(rgbToHsl(128, 128, 128));
console.log(rgbToHsl(255, 255, 255));
hsl(217.2 91.2% 59.8%)
hsl(0.0 100.0% 50.0%)
hsl(60.0 100.0% 50.0%)
hsl(240.0 100.0% 50.0%)
hsl(0.0 0.0% 50.2%)
hsl(0.0 0.0% 100.0%)

Gray and white print a hue of 0 only because the formula needs a number. When saturation is 0 the hue has no effect.

What does the L in HSL mean?

The L in HSL is lightness, a value from 0% (black) to 100% (white) with the pure color at 50%. It is a calculation on RGB channels, not a measurement of how bright a color looks.

Common pitfalls

  • Expecting equal lightness to look equally light: pure blue and pure yellow are both hsl(... 100% 50%), yet CIE Lab lightness is about 29.6 for blue and 97.6 for yellow. For contrast work, use a perceptual space such as Lab color, or check contrast directly.
  • Legacy syntax without percent signs: hsl(217, 91, 60) is invalid in the comma form. Add % to both numbers or switch to the space-separated syntax.
  • Assuming steps in hue are even: HSL hues are bunched together in some regions and widely spaced in others, so the same 30 degree step looks small between hsl(220 100% 50%) and hsl(250 100% 50%) but large between hsl(50 100% 50%) and hsl(80 100% 50%), as the CSS spec notes.
  • Mixing up HSL and HSV: both share the same hue, but 100% lightness is always white in HSL, while 100% value in HSV is the brightest version of the color. See HSV.
  • Relying on hue at 0% saturation or at 0% or 100% lightness: the color is gray, black or white and the hue is meaningless. Do not store or animate it as if it mattered.

Related terms

  • RGB — the channel model that HSL is computed from
  • HSV — a sibling model with the same hue but a different brightness axis
  • Hex color — the compact notation that HSL values are often converted to
  • sRGB — the color space HSL colors resolve in
  • Lab color — a perceptual space where equal lightness really looks equal

See also