CSS combinators let you write selectors that describe a relationship between elements, rather than just targeting one element type or class in isolation. Instead of adding extra classes everywhere, you can say "style a paragraph, but only when it's directly inside this container" or "style the element that comes right after this one." There are four combinators, each written with a different symbol, and mixing them up is one of the most common sources of selectors that silently select the wrong thing.

Descendant Combinator (space)

A plain space between two selectors means "any matching element nested anywhere inside the first, no matter how deep."

<div class="card">
  <p>Direct child paragraph</p>
  <div>
    <p>Nested paragraph, two levels deep</p>
  </div>
</div>
.card p {
  color: #374151;
}

This matches both paragraphs — the one directly inside .card and the one nested two levels deeper. The descendant combinator doesn't care about depth, only that the second element is somewhere inside the first.

Child Combinator (>)

The > combinator is stricter — it only matches a direct child, one level down, not grandchildren.

.card > p {
  color: #374151;
}

Using the same HTML as above, this matches only the first paragraph — the one that is a direct child of .card. The nested paragraph inside the inner <div> is skipped entirely, because it's a grandchild, not a child.

Adjacent Sibling Combinator (+)

+ matches an element only when it comes immediately after another specific element, at the same nesting level.

<h2>Section Title</h2>
<p>This paragraph gets extra top margin.</p>
<p>This one does not — it's not adjacent to the h2.</p>
h2 + p {
  margin-top: 4px;
}

This gives the first paragraph (directly after the <h2>) a small top margin, but leaves the second paragraph untouched, since it's adjacent to the first paragraph, not the heading.

General Sibling Combinator (~)

~ is the loosest of the three sibling-related combinators — it matches any sibling that comes after the first element, not just the immediately adjacent one.

h2 ~ p {
  color: #6b7280;
}

Using the same markup, this matches both paragraphs, since both come after the <h2> at the same nesting level — it just requires them to share a parent and follow the <h2> somewhere in the sibling order, with no adjacency requirement.

Choosing the Right One

A quick way to remember all four: space means "anywhere inside," > means "directly inside," + means "right after," and ~ means "after, anywhere among the siblings." Reaching for the most specific combinator that still does the job keeps your specificity predictable and avoids accidentally styling elements several levels deeper than you intended.