Benchvale

Palette to CSS variables

This turns a pasted color palette into CSS custom properties, SCSS variables or a JSON token file. It also carries each color's contrast ratio into the output as a comment, so the file that lands in your codebase records which pairs were checked and which ones failed. All three formats, free, no account.

Your palette

Format

Measured on this page, in this browser
Network requests
·
Our own script
·

Was this tool useful?

Your palette never leaves your browser: this page doesn't send it to us or anywhere else. Once the page has loaded, you can disconnect and keep working. How we build tools
Requests: · listed · unlisted Script · Updated

Why the contrast notes are the point

Exporting a palette to CSS variables is a find-and-replace with extra steps, and you could do it by hand in a few minutes. The export is not the point of this page.

The useful part is what the file remembers. A token file that arrives as eight hex values tells the next developer nothing about which combinations are safe, so they pick two that look nice and ship a 2.8:1 label. A token file that arrives with /* on paper 5.12:1 AA, on ink 3.19:1 Fail */ next to each color answers the question at the moment it gets asked, which is while somebody is writing the CSS, not during an audit six months later.

The notes compare each color against the lightest and darkest colors in the palette, because that is what a palette actually gets used as: something dark for text on something light, and the reverse. For every pair rather than the two extremes, use the contrast grid.

Naming

Names become the variable names, lowercased with anything that is not a letter or a digit turned into a hyphen. "accent deep" becomes --bnv-accent-deep.

Two different colors that slug to the same name are a collision, not a duplicate. The first keeps the name; later ones get a numeric suffix such as --bnv-brand-red-2 and the status line names the collision so nothing is silently overwritten. Identical hex and name on two lines still collapses to one entry, which is the correct duplicate.

A name that starts with a digit or is only punctuation would produce a custom property that does not parse, so those get a color- prefix rather than being emitted broken. It is a small thing that turns a file which silently fails to apply into one that works.

Worth saying because it is the most common regret in a design system: name colors for what they are, not what they currently do. --brand-blue survives a redesign. --button-color becomes a lie the first time a button changes.

Three formats, one paste

CSS custom properties are the default because they are the only one that works at run time, which is what you want for a theme switch or dark mode. SCSS variables are compile time and cannot be swapped in the browser, but they are still what a lot of existing codebases are built on.

The JSON output is a flat token file, which is the shape most design token pipelines accept as a starting point. It is deliberately simple rather than being any particular vendor's schema, because converting simple JSON to a specific format is easy and converting one vendor's format to another is not.

Questions

How do I turn a color palette into CSS variables?

Paste one color per line, hex first, then the name you want. You'll get a :root block with one custom property per color, such as --bnv-accent-deep: #0E6B78;. Each line notes its contrast against your lightest and darkest colors. Change or clear the prefix under Name prefix. Pick SCSS variables or JSON tokens instead if you like, then copy or download.

How are the variable names made?

Each name is lowercased. Every run of characters other than a to z and 0 to 9 becomes a single hyphen, and hyphens at either end are dropped. So "accent deep" becomes --bnv-accent-deep. A name that starts with a digit gets color- in front, which turns "2nd brand" into --bnv-color-2nd-brand. When two different colors share a name, the second one gets -2 and the status line says so.

How do I add opacity to a CSS color variable?

Mix it with transparent. MDN's color-mix() page shows this pattern, and color-mix(in srgb, var(--bnv-accent) 50%, transparent) gives you the accent at half opacity. This page won't write alpha values itself. It outputs 6-digit hex, and it won't read an 8-digit code like #2FBFD080.

Can it read or write OKLCH, rgb() or Tailwind colors?

No. It reads hex only, 3 or 6 digits, and writes 6-digit hex. Lines with rgb() or oklch() aren't read. Neither are lines of existing CSS like --bnv-ink: #131A22;, because each entry has to start with the hex code. Output comes as CSS custom properties, SCSS variables or JSON. There's no Tailwind config.

Is there a dark mode block?

No. The output is one :root block for the colors you paste, with no dark variants and no prefers-color-scheme rule. For a dark theme, paste your dark colors as a second palette and set the prefix to dark, so ink becomes --dark-ink. Then point your variables at those inside your own @media (prefers-color-scheme: dark) rule or theme class.

Does this upload my palette?

No. The conversion runs in this tab, and Download file builds the file in the page. Before any update to this page goes live, an automated check types into every box and presses every button, and blocks the update if what it typed turns up in a request. A share link carries your palette after the # in the address, which browsers don't send to a server.

Related tools

Before exporting, check the whole set with the palette contrast grid, or a single pair with the contrast checker. Worth also running it through the color blindness simulator, since contrast and hue are separate problems and passing one says nothing about the other.

Maintained by Aaron Wilson
Published . Last updated . How the tools work and how we check them: how we build tools. Something wrong? Tell us.