Chapter 1.2☕ 12 min read

Selectors & Specificity

Auto stand ka numbering — kaun jeeta rule game mein. Master selectors and specificity once and for all.

01Selector Types — The Full Toolkit

CSS has many selector types. Each one targets elements differently. Here's the full toolkit:

  • Elementh1, 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.
  • CombinatorsA 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 attribute
a:hover { }Pseudo-class — hover state
p::before { }Pseudo-element — before content
02Combinators — Connecting Elements

Combinators 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 nested
h2 + 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.

03Specificity — The Score Card

Every selector has a specificity score: (IDs, Classes, Elements). Higher score wins. Same score? Last one in the file wins.

Selector IDs Classes Elements Winner
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!
🚨
Pro Tip: Specificity calculator: ID count = hundreds place, Class count = tens place, Element count = ones place. #main p = (1,0,1) = 101. .card .title = (0,2,0) = 020. So #main p wins!
04The Cascade — Final Boss

When specificity is tied, the cascade decides. Three factors in order:

  • Importance: !important beats 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.

05Exercise — Selector Playground

Write selectors below and see which elements they target. Practice makes perfect!

1

Open VS Code. Create selectors-practice.html.

2

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:

💡
Try this: Write .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 !important in normal code — only for utility overrides
  • ✅ Same specificity? Last rule in file wins (cascade)
  • ✅ BEM naming (.block__element--modifier) avoids specificity wars
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase