Selectors and combinators

CSS · Essentials · 10 min

Precise selectors are how you style exactly the elements you mean and nothing else.

Selectors choose which elements a rule applies to.

Simple selectors:

  • type: p, button
  • class: .card (any element with class="card"; elements can have many classes)
  • id: #main (unique on the page; avoid for styling because it's very specific)
  • attribute: [disabled], [type="email"], [href^="https"] (starts with), [href$=".pdf"] (ends with)
  • universal: *

Chain them with no space to require all at once: button.primary[disabled] is a disabled button that also has class primary.

Combinators select by relationship:

  • nav a (space): an a anywhere inside a nav (descendant).
  • ul > li: an li that is a direct child of a ul.
  • h2 + p: the p immediately after an h2 (adjacent sibling).
  • h2 ~ p: every p sibling after an h2 (general sibling).

A comma makes a selector list: h1, h2, h3 { ... } applies to all three.

Browsers match selectors right to left: for .sidebar a they look at every a and then check for a .sidebar ancestor. That's fast in practice, so write selectors for clarity. The bigger risk is fragility: long chains like main div > ul li a break when the markup changes. Prefer short selectors built around classes that describe what a component is.

Example

/* <nav class="menu"><a href="/">Home</a> <a href="/docs.pdf">Docs</a></nav> */
.menu a { text-decoration: none; }          /* descendant */
.menu > a { padding: 4px 8px; }             /* direct child */
a[href$=".pdf"]::after { content: " (PDF)"; } /* attribute: ends with */

h2 + p { margin-top: 0; }                   /* first p right after an h2 */

input[type="checkbox"] { accent-color: teal; }

button.primary { background: royalblue; color: white; }  /* both at once */
button .icon { width: 1em; }                /* .icon INSIDE a button */

Remember

  • Class selectors are the workhorse; avoid ids for styling
  • space = descendant, > = child, + = next sibling, ~ = later siblings
  • No space means 'same element': a.b is different from a .b

Watch out for

  • Writing 'button .primary' (descendant) when you meant 'button.primary' (same element).

Check yourself

  1. Which elements does 'ul > li' match in <ul><li>A<ol><li>B</li></ol></li></ul>?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: developer.mozilla.org/en-US/docs/Web/CSS/Guides/Selectors