Combinators, Revisited
Master descendant, child, and sibling combinators for surgical, class-light selection.
You already met the four combinators. Now let's talk about when to reach for each one, because used well they let you write far fewer classes and keep your markup clean.
The four relationships
A B— anyBnested anywhere insideA. Powerful, but greedy.A > B— only direct children. This is the one that saves you from accidental cascades into nested components.A + B— the single element immediately afterA. Perfect for “space between adjacent things”.A ~ B— every following sibling, not just the next.
The lobotomized owl
One of the most quietly brilliant selectors ever written is * + *. It reads “any element that follows any element” — in other words, everything except the first child. It's the classic way to add rhythm to a stack without touching the first or last item:
.stack > * + * {
margin-block-start: 1rem;
}No trailing margin, no :first-child reset, no fuss. That's the mark of a combinator used with intent.
Example
When to use it
- A developer uses the general sibling combinator (.error ~ .hint) to show a hint paragraph only when an error element precedes it.
- A developer uses the child combinator (.menu > li > a) to style top-level nav links without accidentally styling links inside nested sub-menus.
- A designer uses the adjacent sibling combinator (h2 + p) to remove the top margin from the first paragraph after each section heading.
More examples
Child combinator for direct-only styles
Uses > to style only direct list children of .nav while leaving deeply nested sub-menu items in their own block flow.
/* Only direct li children, not nested ones */
.nav > li {
display: inline-block;
position: relative;
}
/* Nested sub-items are unaffected */
.nav li li {
display: block;
}Adjacent sibling for post-heading spacing
Targets the single paragraph immediately following an h2 to remove its top margin and de-emphasize it as a subtitle.
h2 { margin-bottom: 24px; }
/* Remove extra top space from the first p after h2 */
h2 + p {
margin-top: 0;
color: #555;
font-size: 1.1rem;
}General sibling for conditional visibility
Uses the ~ general sibling combinator to reveal a .hint element whenever a .field-error sibling is present in the DOM.
.field-error {
display: none;
}
/* Show hint whenever an error is present anywhere after .form-group */
.field-error ~ .hint {
display: block;
color: #888;
font-size: 0.85rem;
}
Discussion