HSL

A way to describe color with three values — hue, saturation and lightness — instead of RGB. It matches how people actually think about adjusting a color.

Also known as: Hue Saturation Lightness색상 채도 명도
···
html
<div class="panel">
  <div class="swatch" id="sw"></div>
  <div class="row"><span class="lbl">H</span><div class="bar" id="barH"><i id="dotH"></i></div><b id="vh">210°</b></div>
  <div class="row"><span class="lbl">S</span><div class="bar" id="barS"><i id="dotS"></i></div><b id="vs">78%</b></div>
  <div class="row"><span class="lbl">L</span><div class="bar" id="barL"><i id="dotL"></i></div><b id="vl">55%</b></div>
</div>
css
.panel{width:min(520px,92%);display:grid;gap:clamp(8px,2.4vmin,14px)}
.swatch{height:clamp(48px,16vmin,72px);border-radius:14px;border:1px solid var(--line)}
.row{display:grid;grid-template-columns:18px 1fr 58px;align-items:center;gap:10px}
.lbl{color:var(--muted);font:700 clamp(10px,2.6vmin,13px)/1 ui-monospace,monospace}
.bar{position:relative;height:clamp(12px,3.4vmin,16px);border-radius:8px;border:1px solid var(--line);cursor:pointer;touch-action:none}
.bar i{position:absolute;top:50%;width:16px;height:16px;margin-left:-8px;margin-top:-8px;border-radius:50%;background:#fff;border:2px solid var(--fg);box-shadow:0 1px 3px rgba(0,0,0,.35);pointer-events:none}
#barH{background:linear-gradient(90deg,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)}
b{font:700 clamp(10px,2.6vmin,13px)/1 ui-monospace,monospace;color:var(--fg);text-align:right}
js
let hue = 210, sat = 78, light = 55, autoRotate = true;
const sw = document.getElementById('sw');
const barH = document.getElementById('barH'), barS = document.getElementById('barS'), barL = document.getElementById('barL');
const dotH = document.getElementById('dotH'), dotS = document.getElementById('dotS'), dotL = document.getElementById('dotL');
const vh = document.getElementById('vh'), vs = document.getElementById('vs'), vl = document.getElementById('vl');

function hsl(h, s, l) { return 'hsl(' + h + ', ' + s + '%, ' + l + '%)'; }

function render() {
  sw.style.background = hsl(hue, sat, light);
  dotH.style.left = (hue / 360 * 100) + '%';
  barS.style.background = 'linear-gradient(90deg,' + hsl(hue, 0, light) + ',' + hsl(hue, 100, light) + ')';
  dotS.style.left = sat + '%';
  barL.style.background = 'linear-gradient(90deg,' + hsl(hue, sat, 0) + ',' + hsl(hue, sat, 50) + ',' + hsl(hue, sat, 100) + ')';
  dotL.style.left = light + '%';
  vh.textContent = Math.round(hue) + '°';
  vs.textContent = Math.round(sat) + '%';
  vl.textContent = Math.round(light) + '%';
}

function bindDrag(bar, onMove) {
  function fromEvent(e) {
    const r = bar.getBoundingClientRect();
    const p = Math.min(1, Math.max(0, (e.clientX - r.left) / r.width));
    onMove(p);
    render();
  }
  bar.addEventListener('pointerdown', e => { autoRotate = false; bar.setPointerCapture(e.pointerId); fromEvent(e); });
  bar.addEventListener('pointermove', e => { if (e.buttons) fromEvent(e); });
}
bindDrag(barH, p => hue = p * 360);
bindDrag(barS, p => sat = p * 100);
bindDrag(barL, p => light = p * 100);

(function tick() {
  if (autoRotate) hue = (hue + 0.5) % 360;
  render();
  requestAnimationFrame(tick);
})();

RGB describes how much of three light primaries to mix, which makes "a bit brighter" or "a bit more muted" hard to reason about. HSL solves this with a cylinder model — hue (0–360°, the angle on the color wheel), saturation (0–100%, how pure the color is) and lightness (0–100%, how close to black or white it is).

CSS accepts it directly as hsl(210 80% 55%), which makes generating lighter/darker variants of the same hue (just change lightness), or muting a color (just lower saturation), very convenient.

HSL's lightness doesn't quite match perceived brightness, though: at the same L value, yellow looks brighter than blue. OKLCH exists to fix that.

When to use

Use it when you fix one hue and vary lightness/saturation to build a palette, or compute color values dynamically in code.