Why CSS variables instead of preprocessor variables
SCSS and Less variables are baked at compile time - the moment you change a brand color, every dependent helper (lighten, darken, mix) keeps the old values until you rebuild. CSS custom properties update at runtime: change --brand and every color-mix(in oklch, var(--brand), ...) reflows instantly. That single property powers theme switching, multi-brand white labels, A/B color tests and live preview without re-shipping CSS.
The recipe
- Open /css-vars.
- Paste your brand HEX (e.g.
#7c5cff). - The tool emits an OKLCH ramp + semantic token mapping.
- Click Export → CSS.
- Paste into your stylesheet root.
Output shape
:root {
/* Reference layer (raw ramp) */
--brand-50: oklch(0.97 0.02 290);
--brand-500: oklch(0.65 0.21 290);
--brand-950: oklch(0.16 0.06 290);
/* Semantic layer (what components consume) */
--surface: var(--brand-50);
--surface-raised: #ffffff;
--text-primary: var(--brand-950);
--text-muted: oklch(0.55 0 0);
--border: oklch(0.92 0.01 290);
--action-primary: var(--brand-500);
--action-hover: color-mix(in oklch, var(--action-primary), black 12%);
}
[data-theme="dark"] {
--surface: oklch(0.16 0.02 290);
--surface-raised: oklch(0.20 0.02 290);
--text-primary: oklch(0.95 0.01 290);
--text-muted: oklch(0.65 0 0);
--border: oklch(0.28 0.02 290);
--action-primary: oklch(0.72 0.18 290); /* slightly desaturated for dark */
--action-hover: color-mix(in oklch, var(--action-primary), white 12%);
}How to consume in components
.button {
background: var(--action-primary);
color: var(--surface);
}
.button:hover { background: var(--action-hover); }
.card { background: var(--surface-raised); border: 1px solid var(--border); }FAQ
Why OKLCH instead of HEX or HSL?
OKLCH is perceptually uniform and natively supported in CSS. Equal lightness steps look equal across hues, gradients stay clean, and dark-mode mirroring becomes a one-line operation.
Will OKLCH variables work in older browsers?
Yes - we emit a sRGB HEX fallback alongside every OKLCH declaration. Browsers that do not understand OKLCH use the fallback automatically.
Do I have to use semantic tokens?
No, but it is strongly recommended. Components read --text-primary, not --brand-700, so a rebrand is one variable swap instead of a global find-and-replace.
How do I switch between light and dark mode?
Toggle a class or data attribute on <html>. The generated [data-theme="dark"] block overrides the same semantic tokens with their dark-mode mirror.