CSS Reference Concept

Combinators

Selectors can contain multiple simple selectors, but between each simple selector, there has to be a combinator. There are several combinators we can use and each describes the relationship between the selectors.

Descendant combinator

A descendant combinator targets any element that is nested within another element. The nesting can be as many levels deep as possible, i.e. child, grandchild and beyond. Descendant combinators will match every instance of an element under its ancestor, and can be chained to increase specificity. Each selector in the chain is separated by a single whitespace.

Say you have some HTML that looks like this:

<article>
  <h2>Lollipop muffin sweet cake</h2>
  <p>Chocolate cookie tootsie roll tiramisu tart lemon drops chocolate cake cheesecake biscuit.</p>

  <aside>
    <h2>Tiramisu sweet roll ice cream</h2>
    <p>Cake jelly-o jelly-o sweet roll powder muffin marshmallow dragée.</p>
  </aside>

  <p>Cake chocolate cake brownie brownie marshmallow biscuit. Chocolate bar chocolate cake sugar plum.</p>
</article>

Descendant selectors will match any instance of the selector regardless of where it is nested within the document tree. If we apply styles to article h2, then both headings, including the one in the aside element will match.

articleh2ph2ppaside

Browsers read selectors from right to left, and we don’t want to over-qualify selectors. It’s not necessary to write selectors like html body article aside h2, because it’s safe to assume the article element will be in the body which will definitely be in the html. Also, if you have to chain more than 2 selectors, you might want to consider just applying a class instead.

Child combinators (>)

A child combinator targets the direct descendant of a parent element and uses the greater-than (>) sign as the separator between elements. The parent element must always be on the left of the “>”. Only immediate child elements in the document tree will be matched.

With reference to the same HTML used in the descendant selector example, say we have the following styles:

article > h2 {
  background-image: linear-gradient(to right, #4776E6, #8E54E9);
  color: transparent;
  -webkit-background-clip: text;
}

Only the first h2 would be targeted because there is an aside element between the article and the second h2 element in the document tree.

articleh2ph2ppaside

Sibling combinators

There are 2 types of sibling combinators, the general sibling combinator and the adjacent sibling combinator. Both handle elements that exist on the same level.

General sibling combinator (~)

A general sibling combinator targets elements that appear anywhere after the simple selector within the same parent, and uses the tilde (~) as the separator between elements.

Say we had a set of radio buttons like so:

<label>
  <input type="radio" name="fruit" value="apple">
  <span>Option 1</span>
  <img src="img/apple.jpg" alt="A red apple">
  <span>Apple</span>
</label>

<label>
  <input type="radio" name="fruit" value="banana">
  <span>Option 2</span>
  <img src="img/banana.jpg" alt="A yellow banana">
  <span>Banana</span>
</label>

<label>
  <input type="radio" name="fruit" value="cherry">
  <span>Option 3</span>
  <img src="img/cherry.jpg" alt="Pair of red cherries">
  <span>Cherry</span>
</label>

The general sibling selector can be used to style the text in the label after the radio button when an option is checked.

input:checked ~ span {
  color: #860038;
}

labelinputimgspanspan

Adjacent sibling combinator (+)

An adjacent sibling combinator targets the element that appears immediately after the simple selector within the same parent, and uses the plus sign (+) as the separator between elements.

There are a couple use cases where the adjacent sibling selector comes in really handy. For example, it’s quite common to see feature articles with the first paragraph styled differently from the rest of the article. Assuming the title is marked up as a h2 element, the CSS will look like this:

h2 + p {
  font-size: 125%;
  font-style: italic;
}

articleh2ppp

Trivia & Notes

Descendant selectors were originally called contextual selectors in the original W3C recommendation for the CSS level 1 back in 17 December 1996. The first working draft of the CSS2 specification in 4 November 1997 retained the term contextual selectors and introduced the concept of parent-child relationships, as well as sibling relationships between selectors. Sibling selectors were originally called sequential selectors.

That working draft specified the use of the tilde (~) for parent-child selectors and a rather complex syntax for sequential selectors. The equivalent to a general sibling selector today was a forward slash preceding the first selector and immediately after the second selector, which looked like this:

/H1 H2/ { margin-top: -5mm }

The equivalent to an adjacent sibling selector today applied if there was a tilde between the 2 selectors, and looked like this:

/H1~P/ { font-size: 125% }

What we know as the first-child pseudo-class was first proposed under sequential selectors as well. The syntax is unrecognisable now but it involved having a double-forward slash before the first selector, looking like this:

//P/ EM { font-weight : bold }

By the time the next working draft was released in 28 Jan 1998, the terms had been updated to become descendant selectors, child selectors and adjacent selectors, with the general sibling selector deferred to Level 3 of the CSS specification instead.

Examples

Say we have this HTML:

<h1>Chinese language on the web</h1>
<p>The most common text layout on the web is horizontal top-to-bottom, as is the case for Latin-based scripts. However, East Asian scripts like Chinese and Japanese are traditionally laid out vertically, from right-to-left.</p>
<p>This article will explore the history of the Chinese writing system and how to use CSS to lay out text for vertical scripts.</p>
<h2>Table of contents</h2>
<ul>
  <li><a href="#some-background-and-history">Some background and history</a></li>
  <li><a href="#chinese-fonts-offline-and-online">Chinese fonts, offline and online</a></li>
  <li><a href="#laying-out-chinese-fonts">Laying out Chinese fonts on the web</a>
    <ul>
      <li><a href="#basic-terminology">Basic terminology</a>
      </li>
      <li><a href="#writing-mode-property">writing-mode property</a></li>
      <li><a href="#text-orientation-property">text-orientation property</a></li>
      <li><a href="#text-combine-upright-property">text-combine-upright property</a></li>
    </ul>
  </li>
  <li><a href="#wrapping-up">Wrapping up</a></li>
</ul>

We can make the opening paragraph italicised and slightly larger than the rest of the text in the article, with the use of an adjacent sibling selector as follows:

h1 + p {
  font-size: 125%;
  font-style: italic;
}

Using a combination of both a general sibling selector and a child selector, allows us to target just the top level list items. This rule would not apply to the nested list items because their parent ul does not have a preceding h2 sibling.

h2 ~ ul > li {
  margin-bottom: 1em;
}

If we want only the nested list items to be italicised and have a serif font, the following rule will do the job, because only the inner ul would have another ul as its parent.

ul ul {
  font-family: serif;
  font-style: italic;
}

You can see the code in action in the live demo below.

Browser Support

All the above combinators are supported in Chrome, Firefox, Safari, Opera 9.5+, Internet Explorer 9+, and on Android and iOS.

CSS3 selectors

Advanced element selection using selectors including: `[foo^="bar"]`, `[foo$="bar"]`, `[foo*="bar"]`, `:root`, `:nth-child()`, `:nth-last-child()`, `:nth-of-type()`, `:nth-last-of-type()`, `:last-child`, `:first-of-type`, `:last-of-type`, `:only-child`, `:only-of-type`, `:empty`, `:target`, `:enabled`, `:disabled`, `:checked`, `:not()`, `~` (general sibling)

W3C Recommendation

Supported from the following versions:

Desktop

  • 4
  • 3.5
  • 9
  • 9.5
  • 3.2

Mobile / Tablet

  • 3.2
  • 2.1
  • all
  • 123
  • 124

* denotes prefix required.

  • Supported:
  • Yes
  • No
  • Partially
  • Polyfill

Stats from caniuse.com

Written by . Last updated December 17, 2016 at 4:07 pm by Manoela Ilic.

Do you have a suggestion, question or want to contribute? Submit an issue.