Relative Color Syntax

상대 색상 문법

`color(from ...)` reads an existing color and lets you tweak just one channel, whatever format the original was in.

Also known as: color(from ...)hsl(from ...)
···
html
<div class="wrap">
  <div class="badge" id="badge"><svg viewBox="0 0 10 10"><path id="bpath" d="M1.5 5.2l2.6 2.6L8.5 2.4" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/></svg><span id="btext">확인 중</span></div>
  <div class="row" id="row"><div class="sw base"></div><div class="sw light"></div><div class="sw dark"></div><div class="sw alpha"></div></div>
</div>
css
.wrap{position:relative;width:min(260px,92%)}
.row{display:flex;gap:8px}
.sw{flex:1;height:52px;border-radius:8px}
.base{background:var(--accent)}
.light{background:hsl(from var(--accent) h s calc(l + 22))}
.dark{background:hsl(from var(--accent) h s calc(l - 18))}
.alpha{background:color(from var(--accent) srgb r g b / 0.35)}
.row.fallback .light{background:#8f8ffa}.row.fallback .dark{background:#3d3dc4}.row.fallback .alpha{background:rgba(91,91,247,.35)}
.badge{position:absolute;top:-30px;right:0;display:flex;align-items:center;gap:5px;padding:4px 9px;border-radius:999px;font-size:10px;font-weight:700;background:var(--bg);border:1px solid var(--line);color:var(--accent-3)}
.badge.no{color:var(--accent-2)}
.badge svg{width:9px;height:9px}
js
const ok = CSS.supports('color', 'hsl(from red h s calc(l + 10))');
const b=document.getElementById('badge'),p=document.getElementById('bpath'),t=document.getElementById('btext');
b.classList.toggle('no', !ok);
p.setAttribute('d', ok ? 'M1.5 5.2l2.6 2.6L8.5 2.4' : 'M2 2l6 6M8 2l-6 6');
t.textContent = ok ? '상대 색상 문법 지원됨' : '미지원 · 정적 색 폴백';
if (!ok) document.getElementById('row').classList.add('fallback');

Making "this color, but 20% brighter" used to require knowing whether the source was hex, hsl, or rgb — awkward in a component library that doesn't control what format a design token arrives in. Parsing, transforming, and reassembling with a JS color library was the usual detour.

Relative color syntax pulls in an existing color with `from` and exposes its channels as variables — `hsl(from var(--accent) h s calc(l + 20))` reads hue, saturation, and lightness directly. `color(from var(--accent) srgb r g b / 0.4)` can change just the alpha channel. Either way, a derived color comes straight out of CSS regardless of the source format.

Check caniuse/MDN baseline for support. Without it, parsing the source color in JS, adjusting a channel, and reassembling the string is the fallback.

When to use

Deriving a lighter, more saturated, or more transparent variant of a token color without knowing its format.