Specificity Wars: Why Your CSS Becomes a Mess and How to Fix It
CSS stands for "Cascading Style Sheets". The word "cascading" is beautiful, but hides a trap: styles overlap in not-always-obvious ways.
Thiago Saraiva

Specificity Wars: Why Your CSS Becomes a Mess and How to Fix It
Let me guess: you've written CSS like this?
Each line was added to "fix" the previous one. And now nobody knows which style actually applies without opening DevTools.
Welcome to the Specificity Wars.
The Problem: Cascade and Inheritance
CSS stands for "Cascading Style Sheets". The word "cascading" is beautiful, but hides a trap: styles overlap in not-always-obvious ways.
How Specificity Works
Each selector has a "weight" calculated like this:
| Type | Weight | Example |
|---|---|---|
| Inline styles | 1000 | style="color: red" |
| IDs | 100 | #header |
| Classes, attributes, pseudo-classes | 10 | .card, [type="text"], :hover |
| Elements, pseudo-elements | 1 | div, ::before |
The selector with the highest weight wins. In a tie, the last declared wins.
Where Things Go Wrong
Each fix requires a more specific selector. It's an arms race that only ends with !important — the nuclear bomb of CSS.
The Top-Down Approach (That Doesn't Work)
The old pattern was to style "from the top down":
- Define global styles on elements
- Override by page section
- Override by specific component
- Override by special context
- Use
!importantwhen nothing else works
The problem is this creates context dependency. An <h2> behaves differently depending on where it is on the page. This is:
- Hard to predict
- Impossible to reuse
- A nightmare to maintain
The Solution: Modular CSS
The modern approach inverts the logic:
Instead of styling elements and overriding by context, we style independent components that work anywhere.
Principle 1: Single Responsibility
Each class does one thing:
Principle 2: Single Source of Truth
Each style is defined in one place only:
Principle 3: Low Specificity
Keep selectors simple:
Methodologies That Implement These Principles
BEM (Block Element Modifier)
Pros: Explicit, predictable, easy to understand Cons: Long class names, verbose
CSS Modules
The bundler transforms .title into .Card_title_x7h3k, ensuring isolation.
Pros: Automatic isolation, short names Cons: Requires build step, dynamic classes are awkward
Tailwind CSS
Pros: High productivity, no naming, consistent design Cons: Verbose HTML, learning curve
CSS-in-JS (styled-components, Emotion)
Pros: Styles with components, dynamic props Cons: Runtime overhead, less caching
Which to Choose?
There's no universal answer. It depends on:
| Factor | Best Option |
|---|---|
| Large team, long project | BEM or CSS Modules |
| Rapid prototyping | Tailwind |
| Complex React app | CSS-in-JS or CSS Modules |
| Simple static site | Vanilla CSS with conventions |
The important thing is to choose one approach and be consistent.
Migrating from Legacy CSS
If you have a project with chaotic CSS:
1. Stop Adding Specificity
Resist the temptation to solve problems with more specific selectors.
2. Create a New Layer
Instead of refactoring existing CSS, create new components with your chosen methodology. Gradually replace the legacy.
3. Use CSS Layers (@layer)
Modern CSS supports specificity layers:
4. Document Conventions
Create a style guide that defines:
- How to name classes
- When to create a new component
- How to handle variations
The Culture of Sharing
One beautiful thing about our industry: we share knowledge freely. Blogs, tutorials, public repos, Stack Overflow answers — all so others can learn.
The CSS best practices we use today came from years of discussions at conferences, coffee shops, and pull requests. Each methodology was refined by thousands of developers facing the same problems.
If you discover something useful — a convention that works, a pattern that avoids bugs — share it. The next person fighting a Specificity War will thank you.