RunLocalTools

Remove Duplicate CSS — Merge Repeated Selectors & Declarations

Paste or upload a stylesheet and get back a cleaned version with duplicate selectors merged, repeated declarations collapsed to the one that actually wins, and media queries left untouched. Free, runs entirely in your browser.


What it does

Paste CSS — or drop a .css file — and this tool finds and removes the genuinely safe kinds of duplication: the same selector declared twice anywhere in the file, and the same property declared twice inside one rule. It merges what’s safe to merge, reports what’s worth a second look (like a shorthand and a longhand property both being set), and never touches anything inside @media, @supports, @keyframes, or @font-face in a way that could change what actually renders.

How it works

The tool builds a real structural parser rather than using regular expressions to hunt for patterns in the raw text — that’s what lets it correctly handle url(data:image/png;base64,...) values, a content: "}" string containing a literal brace, and nested @media blocks without getting confused.

  • Duplicate selectors — if the exact same selector text appears more than once anywhere in the same scope, the declarations are merged: a later occurrence’s value wins for any property both share, and any property only the earlier one set is kept. This still applies even if a completely different rule sits between the two duplicates in the file — which covers the overwhelming majority of real-world stylesheets, since matching-and-conflicting specificity from a rule with a different selector sitting in between is a genuinely rare edge case.
  • Duplicate declarations within one rule — color: red; color: blue; in the same rule is always safe to collapse to the last value, since that’s exactly what the browser would do anyway.
  • Scoping is respected — a selector duplicated inside one @media block is only merged against other rules in that same block, never against the top level or a different media query, since those are genuinely different rendering contexts.
  • Shorthand/longhand overlaps are reported, never auto-changed — if a rule sets both margin and margin-top, order matters in a way this tool can’t safely guess at, so it’s flagged as a warning instead of silently rewritten.
  • Custom properties (--x) are never confused with a different custom property (--y), and a vendor-prefixed property like -webkit-transform is never conflated with its unprefixed form.

How to use it

  1. Paste your CSS into the left pane, or drop a .css file onto the dropzone underneath it.
  2. Toggle Strip comments, Remove empty rules, Group identical rules into one selector list, and Minify output to match what you need — all four default to sensible settings for a typical cleanup pass.
  3. Read the summary line for a quick count of what changed, and check the byte-savings figure.
  4. Scroll the diff panel underneath to see exactly which lines were added or removed, line by line.
  5. Copy the cleaned CSS, or download it directly as a .css file.

If your source CSS came out of a build tool or a CMS export with messy line breaks first, you may want to run it through CSS Specificity Calculator afterward to double-check nothing in the cleaned output collides in a way you didn’t expect.

FAQ

Will this ever change how my page actually looks? The core merges (duplicate selectors, duplicate declarations) are designed to be behavior-preserving in essentially all real-world cases. The one documented edge case — a different-selector rule with identical specificity sitting between two duplicates and fighting over the exact same property — is rare enough that production CSS minifiers make the same trade-off. When in doubt, use the diff panel to review every change before you ship it.

Why weren’t the duplicate selectors inside my @media block merged with the ones at the top level? Because a media query is a genuinely different rendering context — a rule only applies there when the condition matches, so merging it with an unconditional top-level rule could change what the visitor actually sees depending on their viewport. This tool only merges duplicates within the same scope.

Why does the tool say part of my CSS “couldn’t be parsed”? Usually an unmatched bracket or brace somewhere earlier in the file. Rather than guessing or dropping content, the tool preserves everything from that point onward exactly as you pasted it, and flags it so you can go find the actual typo.

Does it touch my @keyframes or @font-face rules? No — those are preserved completely untouched, including any duplication inside them, since deduping animation frames or font declarations isn’t really “duplicate CSS” in the same sense and carries more risk than benefit.

What about comments? On by default, comments are stripped. Turn off Strip comments to keep the ones sitting between rules — comments nested inside a single selector or declaration are always removed either way, since there’s no lossless place to put them back in the regenerated output.

Limitations

  • Grouping rules with byte-for-byte identical declaration lists into one comma-separated selector is optional and on by default — turn it off if you’d rather keep each original rule visually separate.
  • The diff view is skipped above roughly 1,500 lines to keep the tab responsive; the dedupe itself still runs at any size, you just won’t get the line-by-line highlight for very large files.