Chapter 17: Selectors & Specificity
Selectors & Specificity.
This is the part that decides which style wins when multiple rules try to style the same element. If you don’t understand selectors + specificity well, you’ll spend hours wondering:
“Why is my red color not applying?” “Why does this button look different on another page?” “Why does adding one class suddenly break everything?”
Let’s explain it like we’re sitting together in VS Code, going line-by-line, with lots of examples you can copy-paste and play with right now.
1. What is a CSS Selector?
A selector is simply how CSS finds the HTML element(s) you want to style.
Examples you already know:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
p { color: navy; } /* element selector */ .intro { font-size: 1.3rem; } /* class selector */ #header { background: #1e40af; } /* id selector */ input[type="email"] { border: 2px solid green; } /* attribute selector */ a:hover { color: red; } /* pseudo-class */ p::first-letter { font-size: 3rem; } /* pseudo-element */ |
2. The Cascade – Why Multiple Rules Fight Each Other
CSS = Cascading Style Sheets → when several rules target the same element, the browser uses a strict set of rules to decide the winner.
The full order of priority (from strongest to weakest):
- Transition / animation declarations (almost never relevant for beginners)
- !important (very last resort – avoid it like over-spicy mirchi 😅)
- Inline styles (style=”color: red;”) – very high priority
- Specificity (the main thing we’re learning today)
- Source order – if specificity is exactly equal, the rule that appears later in the CSS file wins
3. Specificity – How the Browser Calculates “Who Wins”
Specificity is a four-part score: a-b-c-d
| Part | What adds to it | Example that adds 1 point here | Score contribution |
|---|---|---|---|
| a | Inline style attribute | <p style=”color:red;”> | 1,0,0,0 |
| b | ID selectors (#id) | #main-header | 0,1,0,0 |
| c | Classes .class, attributes [type=”…”], pseudo-classes :hover, :nth-child() | .card, [type=”email”], :hover | 0,0,1,0 |
| d | Elements p, div, pseudo-elements ::before | p, ::first-letter | 0,0,0,1 |
Higher number in left-most digit wins. If tie → move to next digit. Still tie → later rule in file wins.
4. Real Examples – Specificity Battles
Copy-paste this HTML + CSS and open with Live Server. Change things and watch which color wins.
index.html
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Selectors & Specificity – Webliance</title> <link rel="stylesheet" href="style.css"> </head> <body> <div id="main" class="container featured important"> <h1 class="title">Specificity Demo</h1> <p id="intro" class="lead text">This paragraph will show which rule wins.</p> <button class="btn primary">Click Me</button> </div> </body> </html> |
style.css – lots of competing rules on purpose
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/* 1 */ p { color: gray; } /* 0,0,0,1 */ p.text { color: purple; } /* 0,0,1,1 */ #intro { color: orange; } /* 0,1,0,0 */ .container p { color: blue; } /* 0,0,1,1 */ #main .text { color: green; } /* 0,1,1,0 */ #main p.lead.text { color: red; } /* 0,1,2,1 */ div#main.container.featured.important p.text.lead { color: hotpink !important; /* wins because !important */ } /* Remove !important above and see what happens ↓ */ div#main.container.featured.important p.text.lead { color: black; /* 0,1,4,2 – very high specificity */ } /* Inline style in HTML would beat almost everything */ |
What wins right now? → hotpink (because of !important)
Remove !important → now black wins (highest specificity: 0,1,4,2)
Add this inline to the
in HTML:
|
0 1 2 3 4 5 6 |
<p id="intro" class="lead text" style="color: lime;">...</p> |
→ lime wins (inline = 1,0,0,0)
5. Quick Specificity Score Calculator Table
| Selector Example | Specificity Score | Winner against… |
|---|---|---|
| p | 0,0,0,1 | Almost nothing |
| .card | 0,0,1,0 | Beats element selectors |
| #header | 0,1,0,0 | Beats classes |
| .card.featured | 0,0,2,0 | Beats single class |
| #main .card p | 0,1,1,1 | Very strong |
| div#main.container > p.text.lead | 0,1,3,2 | Extremely specific |
| Inline style=”color: cyan;” | 1,0,0,0 | Beats almost all CSS rules |
| !important | Overrides everything except another !important with higher specificity | — |
6. Best Practices in 2026 (So You Don’t Fight Specificity Later)
- Use classes for almost everything — avoid IDs for styling (save IDs for JS or anchors)
- Keep specificity low & flat — prefer .card-title over #main .card h2
- Use BEM-like naming (optional but helps a lot):
- .card
- .card__title
- .card–featured (modifier)
- Never use !important except for debugging or overriding third-party libraries
- Avoid deep nesting — .container .section .card p strong is a red flag
- Order matters — put more general rules first, specific later
7. Your 5-Minute Experiment
- Open the demo above
- Remove !important from the hotpink rule → see black win
- Add !important back to the black rule → see black win again
- Add style=”color: yellow;” to the <p> → yellow wins
- Remove inline style → play with deleting selectors one by one and see color changes
That hands-on feeling is how you really get specificity.
How does it feel now? Any rule confusing? Want to see more battles (like pseudo-classes vs classes)?
Next possible lessons:
- “BEM naming convention for cleaner selectors”
- “CSS variables + specificity”
- “when to use :where() and :is() to control specificity”
- “Flexbox – next core after selectors”
You’re tackling one of the hardest parts of CSS — proud of you! 🚀 Chai thanda ho gaya? Fresh kar le, phir code karte hain 😄
