HTML & CSS
Article
By Guy Routledge

AtoZ CSS Screencast: nth-child and nth-of-type

By Guy Routledge
Last chance to win! You'll get a... FREE 6-Month Subscription to SitePoint Premium Plus you'll go in the draw to WIN a new Macbook SitePoint 2017 Survey Yes, let's Do this It only takes 5 min

Loading the player…

This screencast is a part of our AtoZ CSS Series. You can find other entries to the series here.
--ADVERTISEMENT--

Transcript

:nth-child is a pseudo class used to select elements by a numeric expression.

The syntax is quite different to most other aspects of CSS and can be a bit tricky to get your head around, to begin with.

In this episode we’ll look at:

  • the various ways of using :nth-child,
  • the slightly more flexible :nth-of-type selector
  • and their counterparts selectors :nth-last-child and :nth-last-of-type.

:nth-child

:nth-child selects child elements if their position in the document matches a pattern described by an algebraic expression.

The :nth-child selector looks a bit like this:

li:nth-child(expression); {}

The “expression” can either be the keywords even or odd, a whole number or a formula in the pattern of an+b where a and b are whole numbers – positive or negative.

As :nth-child can be used to select a range of different elements under different circumstances, it’s difficult to explain how it works and what it’s for. Let’s look at a series of examples to illustrate its uses.

I have an unordered list, with 12 list items. Let’s see how we can use :nth-child to match a specific item or pattern of items:

<ul> 
  <li>lorem ipsum</li> 
  <li>lorem ipsum</li> 
  <li>lorem ipsum</li> 
  <li>lorem ipsum</li> 
  <li>lorem ipsum</li> 
  <li>lorem ipsum</li> 
  <li>lorem ipsum</li> 
  <li>lorem ipsum</li>  
  <li>lorem ipsum</li> 
  <li>lorem ipsum</li> 
  <li>lorem ipsum</li> 
  <li>lorem ipsum</li> 
</ul>

To select the third list-item, I could use li:nth-child(3).

To select all the even items, I can use even keyword. Conversely, I can use :nth-child(odd) to select all the odd numbered items. These are commonly used selectors to stripe the background colour of alternate rows in a table of data.

To select every third item, I can use li:nth-child(3n).

To select the first 4 items, I can use li:nth-child(-n+4). To select everything except the first 4 items, I can use li:nth-child(n+5).

The an+b expression

We’ve seen how :nth-child(odd) can select all the odd numbered items in a list. An alternative approach to using the odd keyword is to use the expression 2n+1.

But how does the expression work?

When the expression, in the format an+b contains non-zero values for a and b, the child elements are split into groups of a elements.

If the expression was 2n+1, the child elements would be split into groups of 2. Each element in the group is then given an index, starting at 1. The matched element in each group is bth index. In this example, that would be the first element.

If the expression was 3n+2, the list items would be grouped into sets of 3 and the second item in each group would be matched.

If the value of b is negative, the matched element in the group is the bth index but counted backwards from index 1. In this instance, the matched element from a group will no longer match an element in that group, but in one above it.

The even keyword can be expressed as 2n. In this case, there is no value for b in the an+b expression so each ath element is matched instead; 2n would match every second element, 3n every third, 4n every fourth an so on.

I personally find this idea of splitting child elements into groups and working out the matched index for each group very confusing – although that is how the CSS selectors spec describes it.

I can cope with the idea of matching every nth element – every 2nd or 3rd or 4th etc. and then I like to think as the second part of the expression as an offset.

In the case of 2n+1 I would read it as follows: “Find every second element, move the selection down by 1.”

If the expression was 3n-5 it would read: “Find every third element and move the selection up by 5.”

Other :nth-child selectors

:nth-child has a corresponding :nth-last-child pseudo class which works in the same way as :nth-child but in reverse.

li:nth-last-child(3n) starts at the last child element and works backwards, matching every third element from the bottom of the list. This is far less common and something I don’t think I’ve ever used in a production site before.

It is however, very common to select either the first or last child element. This could be done with :nth-child(1) or :nth-last-child(1) but is so common, there are :first-child and :last-child pseudo classes available as well. :first-child is the only one of this family of child selectors that works in IE8 – :last-child and any of the :nth selectors do not.

:nth-of-type

Something that often catches me out with :nth-child is that the selector just matches based on index of child elements and doesn’t take the type of element into account.

Let’s look at the following markup for a snippet of content.

<section> 
  <h1>lorem ipsum;</h1> 
  <p>Aenean commodo ligula eget dolor. Vestibulum dapibus nunc ac augue;</p> 
  <p>Nunc sed turpis. Donec posuere vulputate arcu;</p> 
</section>

I have a section with a heading and sub-heading and a series of paragraphs beneath. I want to make the first paragraph stand out a bit by increasing the font-size to 1.5em.

I might try section p:first-child, as I want to style the first paragraph in the section. But this doesn’t work as the first child of the section is actually a h1 element. In this case, I need to use the :first-of-type selector.

There are a series of these type selectors; :first-of-type, :last-of-type, :nth-of-type and :nth-last-of-type. These behave the same way as :nth child but match the nth instances of a certain type of element.

These selectors are complex but very powerful. The browser support is IE9+ with the exception of :first-child which is IE8+. Bear this in mind when using them, but they’ve certainly gotten me out of a few difficult situations in the past.

Bonus: Quick Tip

In this quick tip, we’ll look at when you can use nth-child and when you should use a standard class.

When should I use nth-child?

This is a question I get asked by students quite frequently. The first thing to note is that (unfortunately) it depends on the situation. But I’ll try and provide some good baseline criteria.

Firstly, all the :nth-child like selectors are only supported in IE9 and above (with the exception of :first-child) so the first thing to check is the age of browser your project needs to support.

If you need to support IE8 (firstly, sorry to hear that!) then there’s really only one thing you can do; use classes or use :first-child.

Tip 1: Use :first-child when supporting IE8

Imagine you have a horizontal unordered list of nav links and your design needs to have a border to the right of each item – but not the last item.

Instead of adding the border on the right and needing to remove it from the last one, add the border on the left and remove it from the first one.

.site-nav li {
  border-left: 2px solid grey;
}
.site-nav li:first-child {
  border: 0;
}

You can use a similar trick for borders on top/bottom too.

If you’re lucky enough to not need support for IE8, read on…

Tip 2: Use :first-child and :last-child instead of classes

If you’re building or using a grid system and need to do something special for your first and last columns in a row, I’d favour using the :first-child and :last-child pseudo classes over adding classes like .first or .last direct in the HTML.

This will keep your HTML neater and means that you don’t have to think too much when crafting your layout. Layout can be sometimes difficult, so the less thinking you have to do about it the better.

Tip 3: Use :nth-child for alternating styles

A classic example of alternating styles would be having different colored backgrounds for even or odd rows in a table. Another could be floating even or odd blocks of content to the left and right side of a page or container – perhaps for a comment thread or message conversation.

For these kind of situations, I use :nth-child(odd) and :nth-child(even). To keep your code lean, you should just write the first state without any nth-child and then use the higher specificity of using nth-child to set up the alternate style.

/* do this */
.data-table tr {
  background: white;
}
.data-table tr:nth-child(even) {
  background: lightgrey;
}

/* not this */
.data-table tr:nth-child(odd) {
  background: white;
}
.data-table tr:nth-child(even) {
  background: lightgrey;
}

Tip 4: Avoid weird and complex nth-child expressions

For other, more complex selections of the page, I’d favor using classes directly in the HTML over confusing nth-child expressions.

li:nth-child(-n+3) or li:nth-child(5n+1):not(nth-child(3n-1)) are just a bit too crazy and take a lot of brain power to decipher what they actually means (Hint: I have no idea – I just made the last one up, although technically it could work!)

Unfortunately, some designs are so complex that often an approach like this feels necessary but imagine coming back to this kind of code months later and trying to work out what you were trying to do – it could take a while even for the most competent of CSS experts!

Tip 5: Use nth-child when you can’t control the HTML

This may sound like an odd statement. Surely, as the developer or designer one of our most important jobs is to control the HTML.

The situation I’m talking about here is when you’re dealing with a content management system.

When building templates for a CMS based website, you’ll likely be able to control the HTML structure and add your classes and data attributes as and when needed. But sometimes your template will have a place where it spits out a whole load of content from a text field or text area from within the CMS. A classic example is WordPress’ the_content which is one big chunk of HTML which you may have little or no control over.

In these cases, the :first-child, :last-child and :nth-child selectors can get you out of a tight corner.

So, there you have it. 5 tips for using (or not using) one of the most powerful and flexible CSS selectors there is.

More:
Login or Create Account to Comment
Login Create Account
Recommended
Sponsors
Get the most important and interesting stories in tech. Straight to your inbox, daily.
Is it good?Is it good?