8 min read

In this article by Ben Frain, the author of Responsive Web Design with HTML5 and CSS3 Second Edition, we’ll cover the following topics:

  • What are pseudo classes
  • The :last-child selector
  • The nth-child selectors
  • The nth rules
  • nth-based selection in responsive web design

(For more resources related to this topic, see here.)

CSS3 gives us more power to select elements based upon where they sit in the structure of the DOM.

Let’s consider a common design treatment; we’re working on the navigation bar for a larger viewport and we want to have all but the last link over on the left.

Historically, we would have needed to solve this problem by adding a class name to the last link so that we could select it, like this:

<nav class="nav-Wrapper">
<a href="/home" class="nav-Link">Home</a>
<a href="/About" class="nav-Link">About</a>
<a href="/Films" class="nav-Link">Films</a>
<a href="/Forum" class="nav-Link">Forum</a>
<a href="/Contact-Us" class="nav-Link nav-LinkLast">Contact Us</a>
</nav>

This in itself can be problematic. For example, sometimes, just getting a content management system to add a class to a final list item can be frustratingly difficult. Thankfully, in those eventualities, it’s no longer a concern. We can solve this problem and many more with CSS3 structural pseudo-classes.

The :last-child selector

CSS 2.1 already had a selector applicable for the first item in a list:

div:first-child {
/* Styles */
}

However, CSS3 adds a selector that can also match the last:

div:last-child {
/* Styles */
}

Let’s look how that selector could fix our prior problem:

@media (min-width: 60rem) {
.nav-Wrapper {
   display: flex;
}
.nav-Link:last-child {
   margin-left: auto;
}
}

There are also useful selectors for when something is the only item: :only-child and the only item of a type: :only-of-type.

The nth-child selectors

The nth-child selectors let us solve even more difficult problems. With the same markup as before, let’s consider how nth-child selectors allow us to select any link(s) within the list.

Firstly, what about selecting every other list item? We could select the odd ones like this:

.nav-Link:nth-child(odd) {
/* Styles */
}

Or, if you wanted to select the even ones:

.nav-Link:nth-child(even) {
/* Styles */
}

Understanding what nth rules do

For the uninitiated, nth-based selectors can look pretty intimidating. However, once you’ve mastered the logic and syntax you’ll be amazed what you can do with them. Let’s take a look.

CSS3 gives us incredible flexibility with a few nth-based rules:

  • nth-child(n)
  • nth-last-child(n)
  • nth-of-type(n)
  • nth-last-of-type(n)

We’ve seen that we can use (odd) or (even) values already in an nth-based expression but the (n) parameter can be used in another couple of ways:

As an integer; for example, :nth-child(2) would select the 
second item

As a numeric expression; for example, :nth-child(3n+1) would start at 1 and then select every third element

The integer based property is easy enough to understand, just enter the element number you want to select.

The numeric expression version of the selector is the part that can be a little baffling for mere mortals. If math is easy for you, I apologize for this next section. For everyone else, let’s break it down.

Breaking down the math

Let’s consider 10 spans on a page (you can play about with these by looking at example_05-05):

<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>

By default they will be styled like this:

span {
height: 2rem;
width: 2rem;
background-color: blue;
display: inline-block;
}

As you might imagine, this gives us 10 squares in a line:

OK, let’s look at how we can select different ones with nth-based selections.

For practicality, when considering the expression within the parenthesis, I start from the right. So, for example, if I want to figure out what (2n+3) will select, I start with the right-most number (the three here indicates the third item from the left) and know it will select every second element from that point on. So adding this rule:

span:nth-child(2n+3) {
color: #f90;
border-radius: 50%;
}

Results in this in the browser:

As you can see, our nth selector targets the third list item and then every subsequent second one after that too (if there were 100 list items, it would continue selecting every second one).

How about selecting everything from the second item onwards? Well, although you could write :nth-child(1n+2), you don’t actually need the first number 1 as unless otherwise stated, n is equal to 1. We can therefore just write :nth-child(n+2). Likewise, if we wanted to select every third element, rather than write :nth-child(3n+3), we can just write :nth-child(3n) as every third item would begin at the third item anyway, without needing to explicitly state it. The expression can also use negative numbers, for example, :nth-child(3n-2) starts at -2 and then selects every third item.

You can also change the direction. By default, once the first part of the selection is found, the subsequent ones go down the elements in the DOM (and therefore from left to right in our example). However, you can reverse that with a minus. For example:

span:nth-child(-2n+3) {
background-color: #f90;
border-radius: 50%;
}

This example finds the third item again, but then goes in the opposite direction to select every two elements (up the DOM tree and therefore from right to left in our example):

Hopefully, the nth-based expressions are making perfect sense now?

The nth-child and nth-last-child differ in that the nth-last-child variant works from the opposite end of the document tree. For example, :nth-last-child(-n+3) starts at 3 from the end and then selects all the items after it. Here’s what that rule gives us in the browser:

Finally, let’s consider :nth-of-type and :nth-last-of-type. While the previous examples count any children regardless of type (always remember the nth-child selector targets all children at the same DOM level, regardless of classes), :nth-of-type and :nth-last-of-type let you be specific about the type of item you want to select. Consider the following markup (example_05-06):

<span class="span-class"></span>
<span class="span-class"></span>
<span class="span-class"></span>
<span class="span-class"></span>
<span class="span-class"></span>
<div class="span-class"></div>
<div class="span-class"></div>
<div class="span-class"></div>
<div class="span-class"></div>
<div class="span-class"></div>

If we used the selector:

.span-class:nth-of-type(-2n+3) {
background-color: #f90;
border-radius: 50%;
}

Even though all the elements have the same span-class, we will only actually be targeting the span elements (as they are the first type selected). Here is what gets selected:

We will see how CSS4 selectors can solve this issue shortly.

CSS3 doesn’t count like JavaScript and jQuery!

If you’re used to using JavaScript and jQuery you’ll know that it counts from 0 upwards (zero index based). For example, if selecting an element in JavaScript or jQuery, an integer value of 1 would actually be the second element. CSS3 however, starts at 1 so that a value of 1 is the first item it matches.

nth-based selection in responsive web designs

Just to close out this little section I want to illustrate a real life responsive web design problem and how we can use nth-based selection to solve it.

Remember the horizontal scrolling panel from example_05-02? Let’s consider how that might look in a situation where horizontal scrolling isn’t possible. So, using the same markup, let’s turn the top 10 grossing films of 2014 into a grid. For some viewports the grid will only be two items wide, as the viewport increases we show three items and at larger sizes still we show four. Here is the problem though. Regardless of the viewport size, we want to prevent any items on the bottom row having a border on the bottom. You can view this code at example_05-09.

Here is how it looks with four items wide:

See that pesky border below the bottom two items? That’s what we need to remove. However, I want a robust solution so that if there were another item on the bottom row, the border would also be removed on that too. Now, because there are a different number of items on each row at different viewports, we will also need to change the nth-based selection at different viewports. For the sake of brevity, I’ll show you the selection that matches four items per row (the larger of the viewports). You can view the code sample to see the amended selection at the different viewports.

@media (min-width: 55rem) {
.Item {
   width: 25%;
}
/* Get me every fourth item and of those, only ones that are in the last four items */
.Item:nth-child(4n+1):nth-last-child(-n+4),
/* Now get me every one after that same collection too. */
.Item:nth-child(4n+1):nth-last-child(-n+4) ~ .Item {
   border-bottom: 0;
}
}

You’ll notice here that we are chaining the nth-based pseudo-class selectors. It’s important to understand that the first doesn’t filter the selection for the next, rather the element has to match each of the selections. For our preceding example, the first element has to be the first item of four and also be one of the last four.

Nice! Thanks to nth-based selections we have a defensive set of rules to remove the bottom border regardless of the viewport size or number of items we are showing.

Summary

In this article, we’ve learned what are structural pseudo-classes. We’ve also learned what nth rules do. We have also showed the nth-based selection in responsive web design.

Resources for Article:

 


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here