In CSS, what do the selectors `div p`, `div > p`, `div + p`, and `div ~ p` each match?
answer
- four relationships, not four elements
- whitespace is itself a combinator
- direct parent versus any ancestor
- adjacent versus any following sibling
- rightmost compound is what gets styled
basics
~20 sdiv p matches a p at any depth inside a div. div > p matches only a p that is a direct child. div + p matches the p immediately after a div, sharing a parent. div ~ p matches any later p sibling.
solid answer
~50 sThose are the four structural combinators, and each says how the two elements must be related in the document tree. The whitespace in `div p` is the descendant combinator: it matches every `p` anywhere inside a `div`, however deeply nested. `div > p` is the child combinator and matches only a `p` whose direct parent is the `div`, so grandchildren are excluded. `div + p` is the next-sibling combinator: it matches a `p` that comes immediately after a `div` in the same parent, with no element between them. `div ~ p` is the subsequent-sibling combinator: it matches every `p` that follows a `div` among the same parent's children, not just the first one. I always read a selector right to left — the last compound is the element being styled, and everything to its left is a condition on it.
code
html · 13 lines<style>
div p { color: blue; } /* both paragraphs inside the div */
div > p { font-weight: bold; } /* only the direct child */
div + p { text-decoration: underline; } /* the one right after */
div ~ p { font-style: italic; } /* every later sibling */
</style>
<div>
<p>direct child</p>
<section><p>grandchild</p></section>
</div>
<p>immediately after the div</p>
<span>in between</span>
<p>later sibling</p>go deeper
Be ready to point at markup and name exactly which elements each of the four combinators matches, and to say that whitespace itself is the descendant combinator.
Explain that adjacency for + and ~ is measured in element siblings sharing one parent, and show when the child combinator prevents a rule leaking into nested instances of a component.
Show judgment about reach: long descendant chains couple a rule to markup structure, so justify each combinator you keep and prefer the tightest relationship that still expresses the intent.
Frame combinator depth as a coupling decision across a codebase — deep descendant chains make markup refactors break styles silently, and that risk is what team-wide selector conventions exist to bound.
## What a combinator actually is A CSS selector is a chain of *compound selectors* joined by *combinators*. A compound selector is one or more simple selectors written with no space between them, all of which must match the same element: `p`, `.note`, `a.btn[target]`. A combinator is the token *between* two compounds, and it states the structural relationship the two matched elements must have in the document tree. Selectors Level 4 defines four structural combinators. All four have existed in browsers for well over a decade, so none of them needs a support caveat: | Combinator | Written | Relationship | |---|---|---| | Descendant | whitespace | anywhere inside | | Child | `>` | direct parent/child | | Next-sibling | `+` | immediately after, same parent | | Subsequent-sibling | `~` | anywhere after, same parent | The crucial reading habit: **the rightmost compound is the element that gets styled**. Everything to its left is a *condition* on that element, never a second thing being selected. `nav ul li a` styles `a` elements, not navs, uls or lis. ## Descendant — `div p` Whitespace is a real combinator, which is why `div p` and `divp` mean completely different things and why `.card .title` and `.card.title` are unrelated selectors. `div p` matches a `p` that has a `div` somewhere among its ancestors — one level up, or ten. This is the loosest relationship in CSS and the one that leaks most often: a rule written for a page-level container silently reaches into any component that later gets nested inside it. ## Child — `div > p` `>` demands that the `div` be the *direct* parent. Given: ```html <div> <p>matched by both div p and div > p</p> <section><p>matched only by div p</p></section> </div> ``` the second paragraph is a descendant of the `div` but not its child, so `div > p` skips it. The child combinator is the tool for making a rule stop at one level — useful when a component may contain nested instances of itself, such as a menu containing submenus. ## Next-sibling — `div + p` `+` matches an element that shares a parent with the element on the left and is the *immediately following element sibling*. "Element" matters: text nodes and comments are skipped when deciding adjacency, but another element in between breaks the match. In `<div></div><span></span><p></p>` the `p` is **not** matched by `div + p`, because the `span` sits between them. A typical use is spacing or punctuation that only applies when two things are adjacent, such as `h2 + p { margin-top: 0; }` to tighten the paragraph that directly follows a heading. ## Subsequent-sibling — `div ~ p` `~` relaxes `+`: the element must still share the parent and still come *after* the left element in source order, but any number of siblings may sit between them. `div ~ p` matches every following `p` sibling, so in `<div></div><p>a</p><span></span><p>b</p>` both paragraphs match, while `div + p` matches only the first. ## What combinators cannot express All four combinators look *down* the tree or *forward* among siblings. There is no combinator that selects an ancestor, and neither sibling combinator can look backwards at an element that precedes it. That asymmetry is the single most common source of "why can't I style the parent" frustration, and it is why layout is usually arranged so that the element you want to style comes *after* the element whose state you are reacting to. Combinators also cannot cross the parent boundary: `+` and `~` require the same parent, so two elements that merely look adjacent on screen but live in different wrappers are not siblings as far as CSS is concerned. ## Chaining and grouping Combinators chain freely, and each one applies to the compounds on either side of it: `.sidebar > ul li + li` reads as "an `li` that immediately follows another `li`, inside a `ul` that is a direct child of `.sidebar`". Mixing combinator types in one chain is normal and each is evaluated independently. Do not confuse a combinator with the comma. A comma builds a *selector list* — several independent selectors that share one declaration block — while a combinator builds a single selector with a structural condition. ## Reading a selector under interview pressure Work right to left and say each step out loud: for `main > article h2 + p`, that is "a paragraph, immediately after an h2, somewhere inside an article, that is a direct child of main". If you can narrate a selector this way, you can answer nearly every markup-matching question an interviewer puts in front of you.
- Why does an element between them break `div + p` but not `div ~ p`?`+` requires the paragraph to be the immediately following *element* sibling, so any element in between disqualifies it. `~` only requires that the paragraph come after the div among the same parent's children, with any number of siblings in between. Text nodes and comments are ignored by both — only elements count when deciding adjacency.
- When would you deliberately choose the child combinator over the descendant combinator?When the component can contain nested copies of itself or arbitrary third-party markup. `menu > li` styles one level of a menu and leaves a nested submenu's items alone, whereas `menu li` would reach into every level. It is also the honest choice when the rule is genuinely about direct structure rather than "anywhere inside".
- Can any combinator select an element's parent or a previous sibling?No. All four structural combinators look downward or forward only: descendant and child go down the tree, `+` and `~` look at following siblings sharing the same parent. Selecting upward is not something a combinator can do, which is why layouts are usually ordered so the element you want to react to comes first in source order.
saying these in an interview costs you the question
- Thinking `div p` and `div > p` mean the same thing
- Saying `div + p` styles the div as well as the p
- Believing `~` matches siblings before the element too
- Reading a selector left to right as "style the first thing"
- Assuming `+` works across different parent elements