Understanding CSS Combinators

How to use them and why

Matthew Croak
Oct 21 · 6 min read
Photo by Émile Perron on Unsplash

Stylesheets reference specific elements in your HTML by using what are known as selectors. These selectors can be classes, IDs, the elements themselves, etc.

The selector we will be focusing on for this post is the combinator.

“ They combine other selectors in a way that gives them a useful relationship to each other and the location of content in the document.” — MDN Web Docs

Combinators can ensure your CSS is precise by maximizing element associations without overwhelming your HTML. Take a look at this example:

<div>
<div>
<h1>Team 1</h1>
<ul>
<li>
<div>
<h2>Player 1</h2>
<ul>
<li>Average points per game: 20</li>
</ul>
</div>
</li>
</ul>
</div>
</div>

As it is, this HTML structure is not too complex. But what if the team had more than one player, or if there was more than one team — what if you wanted to add more stats per player? Classes and IDs work but as the HTML grows it can limit the flexibility of your CSS.

As the demands of your website grow, so too will the number of elements. The more nested your elements become, the more difficult it will be to access them.

This may also be problematic when you want to make a small adjustment to an element (or elements) that have a shared class. This could lead to you either creating more classes or ids, resorting to inline styling, or using !important.

Overuse of classes and IDs can also create more presentational markup in your HTML, creating more work for you and anyone else working with the code. Combinators alleviate the strain of overly specific selectors and heavier markup by efficiently associating elements on your page. Let’s dive into the different kinds of combinators we can use.

Adjacent Sibling

This combinator is identified by the + symbol and selects the element next to the provided tag.

h1 + p

The example above will select the first p tag to comes after the h1 tag.

Let’s say you have a blog post and you want just the introductory paragraph to have a red background and white text, as shown:

*results may vary

Here is the code:

p{
font-size: 20px;
}
h1 + p {
background-color: red;
color: white;
padding: 10px;
}

Using the adjacent sibling combinator we’re able to isolate just the first p tag and apply our style. What if we wanted to apply the above style to every p tag that comes after our h1 tag? In that case we can use the general sibling combinator.


General Sibling

This combinator is identified by the ~ symbol.

h1 ~ p 

The above code will select all p tags that come after our h1 tag.

If you took the code from the previous example and changed h1 + p to h1 ~ p you would get this:

It even works when there are other elements (like the img above) between selectors.

This is not the case for the adjacent sibling combinator.

The adjacent sibling combinator only works if the element is directly adjacent to the first tag. We can, however, add a byline (p tag) before the image and give it a grey background:

p {
font-size: 20px;
}
h1 ~ p {
background-color: red;
color: white;
padding: 10px;
}
h1 + p {
background-color: grey;
}

The above code gives us this result:

Now that we’ve covered siblings, let’s talk about children.


Child Combinator

The first child-related combinator is, simply enough, the child combinator. This combinator, identified by the > symbol,only selects direct children of an element.

Let’s add a sidebar to our blog page to the right of our article and wrap them both in a parent div. The sidebar will contain a ul of what to read next. It will have two lis for related and unrelated content. Each of those will contain a ul of lis which represent articles. The first ul should have a left border to separate it from the main article and no list style. The nested uls should not have borders and default list style. We can achieve this with the code below:

div > ul {
border-left: solid 1px black;
margin-left: 10px;
padding-left: 10px;
list-style: none;
width:300px;
}

By using the child combinator, we’re selecting only ul tags that are direct children (our new sidebar) of the parent div. This will apply a left border and no list style to the ul tag that contains the sub uls but not the sub ul’s themselves. Let’s give our parent div a display of flex so our article and sidebar are aligned horizontally. This is the result:

*articles are not real

As you can see, only the direct child ul has a left border and no list style. The nested uls have no borders and default list style. Those li tags look a little squished. How can we make every li tag in both ul’s have a bottom margin of 10px? We can do this with our last combinator, the descendant combinator.


Descendant Combinator

These combinators are identified by a space between selectors and, unlike child combinators, they not only direct children, but every descendant of a selector.

ul li {
margin-bottom: 10px;
}

The CSS above will create a margin of 10px beneath every li tag, like this:

Now, let’s say we want to underline all of the article titles but not the section titles (li’s identified by Related Articles and Unrelated Articles). Let’s add the below CSS, using a slightly more specified descendant combinator.

ul li ul li {
text-decoration: underline;
}

The results are shown below.

You may have noticed the conveniently placed ad underneath the introductory paragraph. This ad demonstrates how we can combine combinators to target elements even further.

div div > div > p + p {
color: purple;
font-size: 15px;
}

This set of selectors is targeting any p tag that’s adjacent to a p tag that’s a child of the div. The div is targeted by retrieving a div that’s the child of the div containing our article and sidebar.

Still with me?

We are using the descendant, child and adjacent sibling combinators to select the second p tag in the ad div, so we can apply a different style.

Combinators help keep our HTML flexible and relatively clean. All the code in this post can be found in this codepen. Feel free to mess around with the combinators to see how far you can push the styling without using any classes or IDs.


Better Programming

Advice for programmers.

Matthew Croak

Written by

UI Engineer at Analytic Partners 📲 💻 📈 | Dog Lover 🐶

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade