Tonal palette (50–950 ramp)

토널 팔레트 (50~950 램프)

One hue split into numbered lightness steps from 50 to 950 — the standard shape of a design-token color scale, as seen in Tailwind and Material.

Also known as: Color rampDesign token scale토큰 스케일
···
html
<div class="wrap">
  <div class="ramp" id="ramp"></div>
  <div class="readout" id="readout">oklch(60% 0.16 250)</div>
</div>
css
.wrap{width:min(560px,94%);display:grid;gap:10px}
.ramp{display:grid;grid-template-columns:repeat(11,1fr);gap:3px}
.ramp div{display:grid;gap:2px;justify-items:center}
.ramp i{display:block;width:100%;aspect-ratio:1;border-radius:5px;border:1px solid var(--line)}
.ramp b{font:700 clamp(6px,1.5vmin,8px)/1 ui-monospace,monospace;color:var(--muted)}
.readout{text-align:center;font:700 clamp(9px,2.4vmin,11px)/1 ui-monospace,monospace;color:var(--fg)}
js
var STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
var LIGHT = [97, 94, 87, 79, 70, 60, 50, 42, 34, 24, 15];
var CMAX = 0.16;
function chromaFor(i) {
  var t = i / (STEPS.length - 1);
  var taper = Math.sin(t * Math.PI);
  return +(CMAX * (0.3 + 0.7 * taper)).toFixed(3);
}
var ramp = document.getElementById('ramp'), readout = document.getElementById('readout');
ramp.innerHTML = STEPS.map(function (s, i) { return '<div><i id="c' + i + '"></i><b>' + s + '</b></div>'; }).join('');
var cells = STEPS.map(function (_, i) { return document.getElementById('c' + i); });
var hue = 250;
function render() {
  STEPS.forEach(function (s, i) {
    var c = chromaFor(i);
    var str = 'oklch(' + LIGHT[i] + '% ' + c + ' ' + Math.round(hue) + ')';
    cells[i].style.background = str;
    if (s === 500) readout.textContent = str;
  });
}
render();
setInterval(function () { hue = (hue + 40) % 360; render(); }, 2600);

A tonal palette keeps hue (H) and chroma (C) nearly fixed and splits only lightness (L) into 11 numbered steps — 50, 100, 200, … 900, 950. Lower numbers are lighter (50 is nearly white), higher numbers are darker (950 is nearly black) — that direction follows Tailwind CSS's convention.

Keeping the vividness from wobbling across steps is why this uses OKLCH's chroma (C) axis instead of HSL saturation. Try the same thing in HSL and the darkest steps (900s) usually look muddy; OKLCH keeps lightness and chroma independent, so that problem mostly goes away.

The demo below actually computes oklch(L% C H) fresh for every step. Chroma needs to taper down slightly at the extremes (50 and 950) to stay realistic — a color that is nearly white or nearly black simply cannot carry much chroma without the browser clamping it back into gamut.

When to use

Use it whenever a design-token system needs one brand hue expressed across many lightness steps, brand-50 through brand-950.