Skip to main content

How to Deduplicate CSS Variables: Finding Repeated Custom Properties in a Merged Stylesheet

Deduplicate CSS variables fast: spot repeated --token custom property declarations in a merged stylesheet, and handle the case-sensitivity trap that trips most dedupe tools.

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

How to Deduplicate CSS Variables: Finding Repeated Custom Properties in a Merged Stylesheet

The fastest way to end up with a polluted :root block is to merge stylesheets. You pull a token file from the design system, another from a legacy theme, a third from a vendor widget, and paste them into one file. Now the same --brand-primary is declared three times with three slightly different blue values, and the browser silently uses whichever one wins the cascade. Nobody notices until a button turns the wrong shade in production.

I built a habit of running every merged token block through a deduplicator before I commit it. This post walks through how to find repeated --token declarations, why CSS custom property names are case-sensitive in a way that matters for deduplication, and how the CSS Variable Deduplicator actually treats case so you do not get surprised.

Why merged stylesheets accumulate duplicate variables

CSS custom properties are scoped, inherited, and overridable. That flexibility is the whole point, but it means a name can be declared as many times as you like and the last valid declaration in scope wins. There is no compiler warning, no lint error by default, and no runtime complaint. A repeated declaration is perfectly legal CSS.

So when you concatenate token exports, the duplicates pile up quietly:

  • Two teams both define --space-4, one as 1rem and one as 16px.
  • A theme override redeclares --text-color inside the same :root it was already defined in.
  • A copy-paste from a support ticket brings hidden whitespace, so --radius and --radius look identical to your eye but not to a naive string compare.

A duplicate --token across merged files is rarely cosmetic. More often it is a real collision: two sources disagree about what that token should be. Finding the repeat is the first step to deciding which value is correct.

The case-sensitivity nuance that trips most dedupe tools

Here is the part people get wrong. CSS custom property names are case-sensitive. --Brand-Blue and --brand-blue are two genuinely different variables. The browser treats them as separate entries. If you reference var(--brand-blue) you will never pick up the value declared under --Brand-Blue, even though the names look like the same thing.

This breaks the usual instinct for deduplication. When you dedupe a list of emails or domains, folding case is the right move, because User@Example.com and user@example.com route to the same inbox. Do the same thing to CSS variables and you merge two real, distinct tokens into one, throwing away a declaration the stylesheet actually depends on.

So what does this tool do? By default, the CSS Variable Deduplicator dedupes case-insensitively — it lowercases the variable name before comparing, so --Brand-Blue and --brand-blue collapse into a single row. That default is convenient for the most common cleanup job (catching the same token typed with inconsistent casing), but it is technically wrong for the CSS spec, where those two names are different variables.

To match real CSS semantics, turn on the Case sensitive checkbox before you dedupe. With that toggle on, the comparison preserves case, --Brand-Blue and --brand-blue stay as two separate rows, and you only collapse names that are truly identical. My rule of thumb: if you are cleaning up a token file that ships to a browser, switch on case-sensitive matching, because the browser is case-sensitive and your dedupe should be too. If you are hunting for accidental casing typos, leave it off so the variants surface together.

A worked example

Say you merged two token files and pasted this into the tool:

--brand-primary
--space-4
--brand-primary
--Brand-Blue
--space-4
--brand-blue

There are two kinds of repetition here. --brand-primary and --space-4 each appear twice with identical casing — those are true duplicates. --Brand-Blue and --brand-blue differ only in case — under CSS rules they are distinct variables.

With Case sensitive turned on, the deduper keeps the first occurrence of each genuinely identical name and reports the rest as repeats:

--brand-primary   (count 2, first line 1)
--space-4         (count 2, first line 2)
--Brand-Blue      (count 1, first line 4)
--brand-blue      (count 1, first line 6)

Four canonical rows. The two true duplicates collapsed; the case-variant pair stayed distinct, exactly as the browser would treat them. If you left the case-sensitive toggle off, --Brand-Blue and --brand-blue would also collapse into one row — and you would lose one of two real variables. That single checkbox is the difference between an honest cleanup and a silent bug.

Reading the output: counts and first-seen lines

The deduplicator does not just hand you a shorter list. For each canonical row it keeps the duplicate count and the first source line where the value appeared. That matters when you are explaining a merge to a teammate. "We had --brand-primary declared twice, lines 1 and 3, with different hex values" is an actionable bug report. A bare deduped list is not.

You can also keep invalid rows in the output for review. A common malformed entry is a token missing its leading dashes — brand-primary instead of --brand-primary — which the validator flags with a reason instead of silently dropping. When you are reconciling exports from different tools, those invalid rows are usually where the interesting mistakes hide. Before deduplicating, it is worth normalizing the input, because copied web text often carries hidden whitespace that makes two identical tokens look different to a string compare.

Everything runs in the browser. You paste the block (or load a local text file), and the parser, validator, and deduper all work in the tab without uploading the source — handy when those tokens come from an internal design system you would rather not send anywhere.

Where this fits in a token cleanup workflow

Deduplication is one step. The CSS Variable Deduplicator shares its engine with a small family of related tools, and you can chain them depending on what your merged file needs:

  • If you first need to pull every --token out of a noisy stylesheet or pasted HTML, start with the CSS variable extractor.
  • If you want to confirm each name is a syntactically valid custom property, run the CSS variable list validator.
  • To standardize spacing and wrapping before comparing, the CSS variable normalizer cleans the list first.
  • And when you are also auditing the color values those tokens hold, the hex color extractor pulls every #rrggbb out of the same paste.

Once the list is deduped, you can export it as CSV, JSON, Markdown, a SQL IN clause, a TypeScript union, or plain lines — whichever artifact your next step wants, without hand-adding quotes and commas.

The whole job takes under a minute, and it turns a pile of merged tokens into a list you can actually reason about: every name once, every true collision surfaced, and case treated the way the browser treats it as long as you remember that one checkbox.


Made by Toolora · Updated 2026-06-13