Key Takeaways
- CSS offers selectors known as child-indexed pseudo-classes for matching elements based on their position in the document subtree. These include :first-child, :last-child, :only-child, :nth-child(), and :nth-last-child().
- The :nth-child() and :nth-last-child() pseudo-classes are functional and can accept the odd keyword, the even keyword, an integer, or an argument in the form An+B[5] where A is a step interval, B is the offset, and n is a positive integer.
- The :only-child pseudo-class matches elements if they are the only child of another element. The :empty pseudo-class can select elements that have no children, not even whitespace.
- CSS provides typed child-indexed pseudo-classes, which match elements based on the value of their indexes but are limited to elements of a particular type. These include :first-of-type, :last-of-type, :only-of-type, :nth-of-type(), and :nth-last-of-type().
The following is an extract from our book, CSS Master, written by Tiffany B. Brown. Copies are sold in stores worldwide, or you can buy it in ebook form here.
CSS also provides selectors for matching elements based on their position in the document subtree. These are known as child–indexed pseudo-classes, because they rely on the position or order of the element rather than its type, attributes, or ID. There are five:
-
:first-child
-
:last-child
-
:only-child
-
:nth-child()
-
:nth-last-child()
:first-child
and :last-child
As you’ve probably guessed from the names, the :first-child
and :last-child
pseudo-classes make it possible to select elements that are the first child or last child of a node (element). As with other pseudo-classes, :first-child
and :last-child
have the fewest side effects when qualified by a simple selector.
Let’s take a look at the HTML and CSS below:
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<title>:first-child and :last-child</title>
<style type="text/css">
body {
font: 16px / 1.5 sans-serif;
}
:first-child {
color: #e91e63;
}
:last-child {
color: #4caf50;
}
</style>
</head>
<body>
<h2>List of fruits</h2>
<ul>
<li>Apples</li>
<li>Bananas</li>
<li>Blueberries</li>
<li>Oranges</li>
<li>Strawberries</li>
</ul>
</body>
</html>
You can see what this looks like in the figure below.
Because :first-child
is unqualified, both the h2
element and first li
element are hot pink. After all, h2
is the first child of body
, and li
is the first child of the ul
element. But why are the remaining li
elements green? Well, that’s because :last-child
is also unqualified, and ul
is the last child of body
. We’ve essentially typed *:first-child
and *:last-child
.
If we qualify :first-child
and :last-child
by adding a simple selector, it all makes more sense. Let’s limit our selection to list items. Change :first-child
to li:first-child
and :last-child
to li:last-child
. the image below shows the result.
:nth-child()
and :nth-last-child()
The ability to select the first and last children of a document is fine. But what if we want to select odd or even elements instead? Perhaps we’d like to pick the sixth element in a document subtree, or apply styles to every third element. This is where the :nth-child()
and the :nth-last-child()
pseudo-classes come into play.
Like :not()
, :nth-child()
and :nth-last-child()
are also functional pseudo-classes. They accept a single argument, which should be either:
-
the
odd
keyword -
the
even
keyword -
an integer such as 2 or 8, or
-
an argument in the form An+B[5] where A is a step interval, B is the offset, and n is a variable representing a positive integer.
That last item has a degree of complexity. We’ll come back to it in a moment.
What’s the difference between :nth-child()
and :nth-last-child()
? The starting point: :nth-child()
counts forwards and :nth-last-child()
counts backwards. CSS indexes use counting numbers and start with one rather than zero.
Both :nth-child()
and :nth-last-child()
are useful for alternating patterns. Creating zebra-striped table row colors is the perfect use case. The CSS that follows gives even-numbered table rows a light bluish-gray background, the result of which can be seen in the figure below:
tr:nth-child(even) {
background: rgba(96, 125, 139, 0.1);
}
Switching :nth-child
to :nth-last-child
inverts this banding, since the counting begins from the bottom, shown below.
How about trying some complex examples using more complex arguments? We’ll start with the document shown below, which contains 20 items.
With :nth-child()
and :nth-last-child()
, we can select a single child at a particular position. We can select all of the children after a particular position, or we can select elements by multiples, with an offset. Let’s change the background color of the sixth item:
.item:nth-child(6) {
background: #e91e63;
}
This gives us the result below.
But what if we want to select every third element? Here’s where the An+B syntax comes in:
.item:nth-child(3n) {
background: #e91e63;
}
Again, A is a step interval. It’s almost like a multiplier for n, which starts at 1. So if A = 3, then 3n would match the 3rd, 6th, 9th, and so on elements. That’s exactly what happens, as you can see in below.
Here’s where matters become a little more interesting. We can use :nth-child()
and :nth-last-child()
to select all elements after a certain point. Let’s try selecting all but the first seven elements:
.item:nth-child(n+8) {
background: #e91e63;
}
Here, there is no step value. As a result, n+8
matches every element n beginning with the eighth element, as shown below.
Note: Negative Offsets
Negative offset and range values are also valid. Using :nth-child(-n+8)
would invert our selection, and match the first eight elements.
We can also use the offset and step values to select every third element, starting with the fifth:
.item:nth-child(3n+5) {
background: #e91e63;
}
You can see the results of this selector below.
:only-child
The :only-child
pseudo-class matches elements if they are the only child of another element. Below are two unordered lists. The first has one item while the second contains three:
<ul>
<li>Apple</li>
</ul>
<ul>
<li>Orange</li>
<li>Banana</li>
<li>Raspberry</li>
</ul>
Using li:only-child{color: #9c27b0;}
will select <li>Apple</li>
, since it’s the only child of our first list. None of the items in the second list match, however, because there are three siblings. You can see what this looks like below.
:empty
It’s also possible to select elements that have no children using the :empty
pseudo-class. Now when we say :empty
, we mean empty. In order for an element to match the :empty
pseudo-class, it can’t contain anything else—not even whitespace. In other words, <p></p>
will match, but <p> </p>
will not.
Sometimes WYSIWYG (What You See Is What You Get) editors insert empty p
elements to your content. You could use :empty
in combination with the :not()
pseudo-class to avoid applying styles to these elements; for example p:not(:empty)
.
Selecting Elements of a Particular Type by their Index
The pseudo-classes discussed in the previous section match elements if they occupy the given position in a document subtree. For instance, p:nth-last-child(2)
selects every p
element that is the next-to-last element of its parent.
In this section, we’ll discuss typed child-indexed pseudo-classes. These pseudo-classes also match elements based on the value of their indexes; however, matches are limited to elements of a particular type. Selecting the fifth p
element, or even-indexed h2
elements, for example.
There are five such pseudo-classes with names that mirror those of their untyped counterparts:
-
:first-of-type
-
:last-of-type
-
:only-of-type
-
:nth-of-type()
-
:nth-last-of-type()
The difference between these and child-indexed pseudo-classes is a subtle one. Where p:nth-child(5)
matches the fifth item only if it is a p
element, p:nth-of-type(5)
matches all p
elements, then finds the fifth p
element among those.
Let’s start with a slightly different document. It still has 20 items, but some of them are p
elements and some of them are div
elements. The p
elements have rounded corners, as can be seen below.
Using :first-of-type
, :last-of-type
, and :only-type
With :first-of-type
, we can select the first element that matches a selector. How about we give our first p
element a lime green background:
p:first-of-type {
background: #cddc39;
}
This will match every p
element that’s the first p
element of its parent, shown below.
The :last-of-type
pseudo-class works similarly, matching the last such element of its parent as presented below. However, :only-of-type
will match an element if it’s the only child element of that type of its parent, illustrated underneath.
Let’s look at another example of using :first-of-type
, but this time with a pseudo-element. Remember the ::first-letter
pseudo-element from earlier in this chapter? Well, as you saw, it created an initial capital for every element to which it was applied. How about we go one step further, and limit this initial capital to the first paragraph instead:
p:first-of-type::first-letter {
font: bold italic 3em / .5 serif;
color: #3f51b5;
}
As the image below shows, now our paragraph will have an initial capital, even if it’s preceded by a headline.
Using :nth-of-type
and :nth-last-of-type
The :nth-of-type()
and :nth-last-of-type()
are also functional pseudo-classes. They accept the same arguments as :nth-child()
and :nth-last-child()
. But like :first-of-type
and :last-of-type
, the indexes resolve to elements of the same type. For example, to select the first p
element and every other subsequent p
element, we can use the odd
keyword with :nth-of-type()
:
p:nth-of-type(odd) {
background: #cddc39;
color: #121212;
}
As you can see from teh image below, this only matches odd-numbered p
elements, rather than odd-numbered children.
Similarly, using :nth-last-of-type(even)
selects even-numbered p
elements, but the count begins from the last p
element in the document—in this case, item 18 (shown below).
If this still seems fuzzy, play with Paul Maloney’s Nth-Test tool, or view the examples at Nth Master. Both projects are excellent ways to learn more about these pseudo-classes.
Frequently Asked Questions on CSS Pseudo-Classes and Styling Elements Based on Their Index
What is a CSS Pseudo-Class?
A CSS pseudo-class is a keyword added to selectors that specifies a special state of the selected element(s). For example, :hover can be used to change a button’s color when the user’s pointer hovers over it. Pseudo-classes, along with classes and IDs, are a way to apply styles to elements without altering the HTML markup.
How does the :nth-child pseudo-class work?
The :nth-child pseudo-class matches elements based on their position in a group of siblings. It uses a function-like syntax, :nth-child(an+b), where “a” and “b” are integer values. The “n” is a counter starting at 0, and increases by increments of 1 for each element. The “an+b” represents the elements to select, starting from the first one (b=1).
What is the difference between :nth-child and :nth-of-type?
While :nth-child matches elements based on their position among all sibling elements, :nth-of-type only considers the position among siblings of the same type. For example, p:nth-child(2) would select the second child if it’s a
element, while p:nth-of-type(2) would select the second
element, regardless of its position among other sibling elements.
How can I select the first, second, or third element with a given class name?
You can use the :nth-child pseudo-class in combination with a class selector. For example, .myClass:nth-child(1) would select the first element with the class “myClass”. Remember that this will only work if the element is the first child of its parent.
Can I use negative values with :nth-child?
No, negative values are not allowed with :nth-child. The smallest value you can use is 0, which selects no elements.
How can I select every even or odd element?
You can use the keywords “even” and “odd” with :nth-child to select every even or odd element. For example, :nth-child(even) would select every second element, starting from the first one.
Can I use :nth-child with other pseudo-classes?
Yes, you can combine :nth-child with other pseudo-classes. For example, :nth-child(2):hover would apply styles when the user’s pointer hovers over the second child element.
Is there a performance difference between :nth-child and :nth-of-type?
In most cases, the performance difference is negligible. However, :nth-of-type can be slightly faster when dealing with large numbers of elements, as it only considers siblings of the same type.
Can I use :nth-child with pseudo-elements?
No, pseudo-elements cannot be used with :nth-child, as they are not considered part of the document tree.
Are there any browser compatibility issues with :nth-child?
:nth-child is well-supported in all modern browsers. However, it is not supported in Internet Explorer 8 or earlier. For these browsers, you may need to use JavaScript or jQuery to achieve similar effects.
Tiffany B. Brown is a freelance web developer and technical writer based in Los Angeles. Brown offers web development and consulting services to larger agencies and small businesses. A former member of the Opera Software developer relations team, Brown is also co-author of SitePoint's JumpStart HTML5 book. She sporadically writes about web development technology on her blog. You can follow her on Twitter at @webinista.