Selectors & Combinators

CSS selectors pick which elements a rule applies to. Combinators add structural context.

CSS5 min readConcept 2 of 43

Selectors: from simple to structural

A selector is the part of a CSS rule that identifies target elements. The simplest selectors match by tag name (h2), class (.card), or id (#hero). Attribute selectors go further: [type=email] matches inputs of a specific type, [href^=https] matches links that start with https.

Combinators describe how elements relate to each other in the DOM tree. A space means "any descendant": nav a matches every <a> anywhere inside <nav>. The > child combinator is strict: ul > li only matches <li> elements that are direct children of <ul>, not grandchildren.

The adjacent sibling + matches the element immediately after: h2 + p targets the first <p> right after an <h2>. The general sibling ~ matches all following siblings: h2 ~ p targets every <p> that follows an <h2> under the same parent.

Selectors define the scope of every declaration

Every CSS property declaration is useless without a selector that points it at the right elements. Precise selectors keep styles predictable and prevent unintended side effects on elements you did not mean to target.

Selectors also determine specificity, which controls which rule wins when two rules declare the same property. Understanding selector types is therefore inseparable from understanding the cascade.

Combining selectors for precise targeting

A **type selector** (p) targets all elements of that tag. A **class selector** (.btn) targets all elements with that class. An **id selector** (#main) targets a single unique element. Classes are the workhorse of real-world CSS because they are reusable, low-specificity, and easy to add or remove via JavaScript.

Chain selectors without a space to narrow targeting: .btn.primary matches elements that have both classes. Combine a type and class: button.btn matches only <button> elements with the .btn class, not other elements.

**Descendant** nav a - any <a> inside <nav>, any depth. **Child** ul > li - only direct <li> children. **Adjacent sibling** h2 + p - the <p> directly after <h2>. **General sibling** h2 ~ p - all <p> after <h2> under the same parent.

Try it

Pick a selector type and watch which nodes in the sample DOM tree light up.

p { ... }

Targets every <p> element on the page.

Sample DOM tree

<section id="hero">
<h2> Heading
<p> First paragraphmatched
<ul>
<li> Item one
<li class="highlight"> Item two
<li data-tag="new"> Item three
<p class="highlight"> Highlighted paramatched
<p data-tag="note"> Note paragraphmatched

3 elements match this selector.

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1Which selector targets only `<li>` elements that are DIRECT children of `<ul>`, not deeper descendants?
  2. 2You want to select the `<p>` element immediately following an `<h2>`. Which selector is correct?
  3. 3Which has the HIGHEST specificity?

Remember this

  • Type (h2), class (.btn), id (#hero), attribute ([type=email]) are the four main selector types.
  • > = direct child only. Space = any descendant. + = immediately adjacent sibling. ~ = all following siblings.
  • Ids have very high specificity (0,1,0,0). Prefer class selectors for reusable, overridable styles.
  • Chain selectors without a space to AND them: .btn.primary matches elements with both classes.

Done with this concept?

Mark it complete to track your progress. No login needed.