Selectors & Specificity
Auto stand ka numbering — kaun jeeta rule game mein. Master selectors and specificity once and for all.
CSS has many selector types. Each one targets elements differently. Here's the full toolkit:
- Element —
h1, p, div, *— Targets all elements of a type. The broadest brush. - Class & ID —
.card, #hero— .class for reusable groups, #id for unique elements. - Attribute —
[type="text"]— Targets elements with a specific attribute value. - Pseudo-class —
:hover, :nth-child— Targets elements in a specific state or position. - Pseudo-element —
::before, ::after— Targets virtual elements before/after an element. - Combinators —
A B, A > B, A + B— Targets elements based on their relationship to others.
/* Element selector — targets ALL elements of this type */
div { background: #f8fafc; }
h1 { color: #f97316; }
/* Class selector — targets ALL elements with this class */
.card { border-radius: 8px; padding: 16px; }
/* ID selector — targets ONE unique element */
#hero { background: linear-gradient(135deg, #1a1a2e, #16213e); }
/* Attribute selector — targets elements with specific attributes */
[type="text"] { border: 1px solid #ccc; }
[href^="https"] { color: #f97316; }
/* Pseudo-class — targets elements in a state */
button:hover { background: #f97316; }
li:first-child { font-weight: bold; }
/* Pseudo-element — targets virtual parts */
p::before { content: "→ "; }
p::after { content: " ←"; }
div { }Element selector — all <div> tags.card { }Class selector — reusable#hero { }ID selector — unique[type="text"]Attribute selector — specific attributea:hover { }Pseudo-class — hover statep::before { }Pseudo-element — before contentCombinators let you target elements based on their relationship to other elements. This is where selector power really kicks in.
.nav liDescendant — any <li> inside .nav, no matter how deep.nav > liChild — only direct <li> children of .nav, not nestedh2 + pAdjacent sibling — <p> immediately after <h2>h2 ~ pGeneral sibling — all <p> siblings after <h2><!-- HTML structure -->
<nav class="nav">
<ul>
<li>Home</li>
<li>About
<ul>
<li>Team</li>
</ul>
</li>
<li>Contact</li>
</ul>
</nav>
<h2>Heading</h2>
<p>First paragraph</p>
<p>Second paragraph</p>
/* .nav li → Targets ALL 4 <li> elements (Home, About, Team, Contact) */
/* .nav > li → Targets only 3 direct <li> (Home, About, Contact) — NOT Team */
/* h2 + p → Targets ONLY the first paragraph after h2 */
/* h2 ~ p → Targets ALL paragraphs after h2 */
Pro Tip: The space combinator is the most commonly used — it targets any descendant at any depth. Use > when you want only direct children to avoid styling nested elements.
Every selector has a specificity score: (IDs, Classes, Elements). Higher score wins. Same score? Last one in the file wins.
p
001
—
.intro
010
.intro wins
#main p
101
#main p wins
.card .title
020
.card .title wins
div.card#main p.title
122
Highest!
#main p = (1,0,1) = 101. .card .title = (0,2,0) = 020. So #main p wins!When specificity is tied, the cascade decides. Three factors in order:
- Importance:
!importantbeats everything (use sparingly!) - Specificity: Higher score wins — ID > Class > Element
- Source Order: Same specificity? Last rule in the file wins
- Inline styles beat any CSS file selector (score 1,0,0,0)
/* Cascade demo — same specificity, last one wins */
p { color: red; }
p { color: blue; } /* This wins — it's last */
/* Different specificity — .text has higher score */
p { color: red; } /* (0,0,1) — element selector */
.text { color: blue; } /* (0,1,0) — class selector — This wins! */
/* !important overrides everything — but AVOID using it */
p { color: red !important; } /* This ALWAYS wins, but don't use !important */
Never use !important in normal code. It breaks the cascade and makes debugging a nightmare. Only use it for utility overrides (like a .hidden class). Use BEM naming (.block__element--modifier) to avoid specificity wars entirely.
Write selectors below and see which elements they target. Practice makes perfect!
Open VS Code. Create selectors-practice.html.
Use the starter code below and practice different selectors:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Selector Practice</title>
<style>
/* HTML structure:
* <div class="box">
* <p class="title">Title</p>
* <p>Paragraph</p>
* <span>Span</span>
* </div>
*/
/* Try different selectors! */
.box p { color: #f97316; font-size: 16px; }
.box > p { background: #fff7ed; padding: 8px; }
p + span { color: #10b981; font-weight: bold; }
</style>
</head>
<body>
<div class="box">
<p class="title">Title</p>
<p>Paragraph inside box</p>
<span>Span after paragraph</span>
</div>
</body>
</html>
Practice these selectors:
.box p vs .box > p — see the difference in what gets targeted. Then try adding nested elements and see how the selectors behave.Done — Key Points:
- ✅ 6 selector types: element, class/ID, attribute, pseudo-class, pseudo-element, combinators
- ✅
space= descendant,>= child,+= adjacent,~= general sibling - ✅ Specificity = (IDs, Classes+Pseudo-classes, Elements+Pseudo-elements)
- ✅ Never use
!importantin normal code — only for utility overrides - ✅ Same specificity? Last rule in file wins (cascade)
- ✅ BEM naming (.block__element--modifier) avoids specificity wars
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login