Skip to content
PantoneTools
CSS tokens

CSS Variable Generator

Generate CSS custom properties from any color — HEX, RGB channels, HSL channels — ready to paste into a :root block for modern design tokens, theming, and color-mix() workflows.

  • Three output shapes: raw HEX, RGB channels, HSL channels
  • HSL channel form unlocks `color-mix()`, opacity, and dark-mode swaps
  • Copies as a paste-ready :root block
  • Works for a single brand color or any palette swatch

Direct answer

A CSS custom property holds one value referenced anywhere in your stylesheet via var(--name). For colors, the trick is to store channel components (e.g. --brand: 220 80% 50%) rather than full color strings, so opacity and mixing work without re-parsing.

CSS Variable Generator

#6366F1

50
100
200
300
400
500
600
700
800
900
950

CSS Variables

:root {
  --brand: #6366F1;
  --brand-rgb: 99 102 241;
  --brand-hsl: 239 84% 67%;
}

When this saves you time

Real workflows where css variable generator replaces tedious manual work or an in-app subscription tool.

Theming

One brand color, every shade

Store the HSL channels in a single variable, then derive lighter/darker shades with `hsl(var(--brand) / 90%)` or `color-mix()` — no second variable required.
Dark mode

Swap lightness only

Pair a base hue/sat channel set with a separate lightness var. Flip the lightness in `[data-theme=dark]` and the whole UI re-tones without redefining every color.
Component lib

Pass color as prop

Components that accept a color prop (Button, Badge, Alert) can read `var(--accent)` directly. Consumers override once at `:root` and every variant follows.
Opacity tints

10% alpha for backgrounds

With HSL channels, `hsl(var(--accent) / 10%)` produces a soft tint without a separate variable per opacity step. Tailwind v4 uses the same pattern.
Email-safe

Fallback for legacy email clients

Emit both a HEX fallback and the channel form so older render engines still pick up the brand color while modern clients use the tokenized one.
Design-to-code

Sync with Figma variables

Figma Variables export as the same kind of CSS shape. Generate here, paste into Tokens Studio or Style Dictionary, and one source of truth lights up Figma and your codebase.

How it works

The methodology — every transformation documented so the output is reproducible.

01

Parse the input

HEX, RGB, or HSL — all normalized to a canonical color model. Invalid input is flagged inline.

02

Emit channel-only forms

Modern CSS treats `hsl(220 80% 50%)` and `rgb(255 0 0)` as space-separated channel triples. We emit just the channel string so it composes with opacity (`/`) and `color-mix()`.

03

Wrap in :root

Output is a ready-to-paste `:root { ... }` block. Drop into `globals.css` or any layer-0 stylesheet.

04

Reference anywhere

Use `color: hsl(var(--brand))` for full opacity; `color: hsl(var(--brand) / 50%)` for 50% alpha — no extra variable needed.

Worked examples

InputResultNotes
#7A3DFF--brand: 263 100% 62%;HSL channel form. Use `hsl(var(--brand))` or `hsl(var(--brand) / 50%)`.
#C8102E--red: 350 85% 41%;Red-family channel. Lightness 41% gives strong contrast on white.
rgb(20 40 160)--accent: 232 78% 35%;Normalized to HSL channels. Original RGB form also emitted.
hsl(160 60% 45%)--mint: 160 60% 45%;Pass-through when input already HSL — useful for systematic palettes.

Common mistakes to avoid

Storing full color strings

`--brand: rgb(0 100 200)` cannot be alpha-modulated. Always store channel components so `rgb(var(--brand) / 50%)` and `color-mix()` work.

Mixing comma and space syntax

Modern CSS expects spaces: `rgb(0 100 200)`. Old browsers accept commas. Stay consistent or use a PostCSS plugin to normalize.

Naming by HEX, not by role

`--color-c8102e` ages worse than `--brand-primary`. Tokens should describe role first, value second.

Forgetting dark-mode lightness

Same hue at 50% lightness reads fine on white, terrible on near-black. Either flip lightness in dark mode or keep one var per theme.

Frequently Asked Questions

Why channel-form variables won the design-token war

Until 2020 the default was --brand: #7A3DFF: one variable, one HEX. The pattern broke the moment you needed a 50% alpha background — you had to add --brand-50: rgba(122, 61, 255, 0.5) for every opacity step. Channel-form variables solve this by storing the components (263 100% 62%) and letting the CSS color function re-assemble them at use site: hsl(var(--brand) / 50%) gives 50% alpha; hsl(var(--brand) / 10%) gives 10% — no second variable.

color-mix() unlocks runtime palette generation

With channel variables in hand, color-mix() can generate tints and shades at runtime: color-mix(in oklch, var(--brand-hsl) 70%, white). That removes the need for a token per shade — your design system ships one variable per role and the browser interpolates the rest in a perceptually-uniform space (OKLCH or sRGB-linear, your choice).

Naming tokens by role, not by value

A token named --purple-600 describes a value. A token named --primary describes a role. The second survives a rebrand. The pattern most design systems converge on has two tiers:

  • Reference tokens: --color-purple-600 — name follows value.
  • Semantic tokens: --primary, --surface, --text-muted — name follows role, value points at a reference token.

Generate semantic tokens for everyday use; keep reference tokens as the immutable palette layer underneath.

Related tools

CSS Variable Generator — Custom Properties... | PantoneTools