Skip to content
Laviyx Learn

Try

CSS course menu

CSS Combinators: Descendant, Child, Adjacent Sibling and General Sibling

Learn the four CSS combinators with live examples: descendant (space), child (>), adjacent sibling (+) and general sibling (~), how they read from right to left, and when to use each one.

Beginner6 min readUpdated
On this page

Combinators select elements based on where they are in the HTML tree relative to other elements: inside them, directly inside them, or next to them.

CombinatorExampleMatches
Descendant (space)nav aEvery a anywhere inside a nav
Child (>)ul > lili elements that are direct children of a ul
Adjacent sibling (+)h2 + pA p that comes immediately after an h2
General sibling (~)h2 ~ pEvery p that comes anywhere after an h2, with the same parent

Descendant: a space#

CSS
.menu a {
  color: white;
  background: #2f5fe0;
  padding: 2px 8px;
}
HTML
<nav class="menu">
  <a href="#">Home</a>
  <span><a href="#">Courses</a></span>
</nav>
<p><a href="#">A link outside the menu</a> is not affected.</p>
Result

Both menu links are matched, even "Courses", which is inside a <span>. Descendant means "at any depth".

Child: >#

> only matches direct children, one level down:

CSS
.tree > li {
  border-left: 4px solid crimson;
  padding-left: 8px;
  margin-bottom: 4px;
}
HTML
<ul class="tree">
  <li>Fruits
    <ul>
      <li>Mango</li>
      <li>Banana</li>
    </ul>
  </li>
  <li>Vegetables</li>
</ul>
Result

"Fruits" and "Vegetables" are direct children of .tree, so each gets a crimson border. "Mango" and "Banana" are grandchildren (inside the inner <ul>), so they do not get their own border. With .tree li (a space) instead of >, all four items would.

Be careful when testing this with text colour: properties such as color are inherited, so nested items would turn crimson anyway, just because their parent is. Borders are not inherited, which makes the difference visible. Inheritance is explained in Cascade, Specificity and Inheritance.

Adjacent sibling: +#

+ matches the element immediately after another, at the same level:

CSS
h2 + p {
  font-size: 1.15em;
  color: #555;
}
HTML
<h2>Getting started</h2>
<p>This intro paragraph comes right after the heading.</p>
<p>This second paragraph is normal.</p>
Result

A classic use is styling the first paragraph after each heading as an introduction.

General sibling: ~#

~ matches all later siblings, not just the next one:

CSS
.warning ~ p {
  color: #b26a00;
}
HTML
<p>Before the warning.</p>
<p class="warning"><strong>Warning:</strong> read carefully.</p>
<p>After the warning.</p>
<p>Also after the warning.</p>
Result

Siblings only look forward: the paragraph before the warning is not matched.

Reading complex selectors#

Read selectors from right to left: the right-most part is what gets styled; everything to the left is a condition.

CSS
.sidebar ul > li a { }

"Style a elements, which are inside an li, which is a direct child of a ul, which is inside .sidebar."

Keep selectors short. Long chains like this are tied to the exact HTML structure and break when the HTML changes. Usually a class on the element you want to style is simpler: .sidebar-link { }.

Practice#

Practice exercise

Using combinators only (no new classes), style this HTML so that: links inside the footer are grey; only the direct li children of .steps get a blue left border; and the paragraph directly after the h3 is italic.

HTML
<h3>Recipe</h3>
<p>Serves two.</p>
<ol class="steps">
  <li>Boil water</li>
  <li>Add rice</li>
</ol>
<footer><a href="#">More recipes</a></footer>
Show solution
CSS
footer a { color: grey; }
.steps > li { border-left: 3px solid #2f5fe0; padding-left: 6px; }
h3 + p { font-style: italic; }
HTML
<h3>Recipe</h3>
<p>Serves two.</p>
<ol class="steps">
  <li>Boil water</li>
  <li>Add rice</li>
</ol>
<footer><a href="#">More recipes</a></footer>
Result

Key takeaway#

Finished this lesson?