Skip to main content

How to Normalize CSS Variables So Your Custom Properties Stay in Sync

Normalize CSS variables and custom properties to one kebab-case convention. Trim whitespace, fix the leading --, and keep a design-token file consistent and dedupe-safe.

Published By Li Lei
#css #css-variables #custom-properties #design-tokens #frontend

How to Normalize CSS Variables So Your Custom Properties Stay in Sync

A design-token file looks tidy until three people have touched it. Someone writes --brandBlue because they think in JavaScript. Someone else writes --brand-blue because that is how the rest of the file reads. A third person pastes --Brand-Blue straight out of a Figma export with a stray space in front of it. Open the file a month later and you cannot tell which spelling is the real one, or whether you now have one variable or three.

That last question is not rhetorical. It has a concrete, surprising answer that bites people who assume CSS is forgiving about case.

The trap: CSS custom property names are case-sensitive

Here is the point most teams learn the hard way. CSS custom property names ARE case-sensitive. --Brand-Blue and --brand-blue are two completely different variables, and var(--brand-blue) will never read a value you stored under --Brand-Blue. This is the opposite of how the rest of CSS behaves — selectors, property names like color, and most keyword values are case-insensitive, so your instincts are wrong here precisely because they are right everywhere else.

The result is quiet duplication. A token file that mixes casing does not throw an error. It silently creates parallel tokens that look identical to a human skimming the file but are invisible to each other at runtime. You set --Accent in your theme block, a component reads var(--accent), the value falls through to its fallback, and you spend an afternoon wondering why the color is off by a shade.

The fix is not heroic. It is just consistency: pick one spelling convention and make every declaration obey it. The CSS Variable Normalizer does exactly that — it reads each custom property out of pasted text or an uploaded local file and rewrites it to one consistent form, so --Brand-Blue and --brandBlue collapse onto the single kebab-case name they were always meant to be. (Always confirm the exact target convention the tool emits against the manifest before you bulk-apply it to a shipped file.)

What "normalize" actually does to a variable

Normalizing a custom property is a few small, boring operations applied with no exceptions:

  • Trim whitespace. Pasted exports drag in leading and trailing spaces, and copied web text often hides non-breaking spaces you cannot see. --brand-blue becomes --brand-blue.
  • Ensure the leading --. A custom property is only a custom property because of those two dashes. A name pasted as brand-blue gets the -- restored so it reads as a real variable.
  • Settle on one casing convention. Mixed --camelCase and --kebab-case names get rewritten to the single convention, which is what actually defeats the case-sensitivity trap above.

After that the tool can keep unique rows only, sort the output, and flag anything that will not parse cleanly with the reason attached. An invalid row is not dropped — it stays visible so you know which declaration still needs a hand. That matters: when you are cleaning a token dump, the rows that don't normalize are usually the ones hiding the real bug.

A worked example

Say you inherited this mess from two merged theme files, complete with the spacing and casing crimes of a real copy-paste:

  --Brand-Blue
--brandBlue
--brand-blue
--Spacing_Lg
 --spacing-lg
--brand-blue

Six lines, and a human reading quickly would call it "the brand blue and a spacing token." CSS sees something far worse: --Brand-Blue, --brandBlue, and --brand-blue are three distinct variables, and --Spacing_Lg is a fourth that no kebab-case var() call will ever reach.

Run it through the normalizer with dedupe and sort on, and the output settles to:

--brand-blue
--spacing-lg

Whitespace gone, the leading -- guaranteed, every name folded to one kebab-case spelling, and the duplicates that were only "duplicates" after normalization finally merged. Two real tokens, which is what you actually had all along. From there you can export the clean list as plain lines, CSV, JSON, a SQL IN clause, or a TypeScript union — useful when you want the token names as a typed set rather than loose strings.

Why a token file needs one spelling

A design-token file is a contract. Components on one side promise to read var(--brand-blue); the theme on the other side promises to define it. The contract only holds if both sides spell the name identically, byte for byte, including case. The moment the file allows --brandBlue and --brand-blue to coexist, the contract has a loophole, and loopholes in a token file show up as visual bugs nobody can reproduce because they depend on which spelling a given author happened to type.

One convention closes the loophole. Kebab-case is the conventional choice for CSS custom properties — it matches how built-in CSS properties are written and it sidesteps the case-sensitivity hazard entirely, because lowercase-with-hyphens has exactly one form. There is no --brandBlue versus --brand-blue debate to lose track of when the only legal spelling is --brand-blue.

How I use it

I keep a habit from cleaning up a shared theme last year: before I commit any change that touches the token file, I dump the whole :root block into the normalizer and look at the row count. If the file claims forty tokens and the normalized, deduplicated output shows thirty-six, I know four names drifted — usually a casing slip or a -- someone dropped — and I go find them before they ship. It takes about fifteen seconds and it has caught a "missing" variable for me more than once that turned out to be a --Capitalized twin hiding in plain sight. Because the parsing runs entirely in the browser tab, I never think twice about pasting an internal theme file into it.

Where it fits with the rest of your cleanup

The normalizer is one stop in a small toolchain. When you only need to pull custom properties out of a wall of CSS, the CSS Variable Extractor does the extraction step on its own. If your file is mostly colors, the Hex Color Extractor pulls the #rrggbb values out the same way. And when the variable name still parses but the file itself is grubby with mixed line endings or trailing spaces, run it through the Text File Cleaner first so the normalizer sees clean input.

A token file does not need to be clever. It needs to be consistent. Pick one casing, trim the junk, guarantee the --, and let the duplicates that were never duplicates finally merge. The case-sensitivity rule that surprises everyone stops mattering the instant every name in the file is spelled the same way.


Made by Toolora · Updated 2026-06-13