Structural Pseudo-Classes

The following is an extract from our book, HTML5 & CSS3 for the Real World, 2nd Edition, written by Alexis Goldstein, Louis Lazaris, and Estelle Weyl. Copies are sold in stores worldwide, or you can buy it in ebook form here.

So far, we’ve seen how we can target elements based on their attributes and states. CSS3 also enables us to target elements based simply on their location in the markup. These selectors are grouped under the heading structural pseudo-classes.

These might seem complicated right now, but they’ll make more sense as we look at ways to apply them later on. These selectors are supported in IE9 and newer, as well as current and older versions of all the other browsers but not in IE8 and below:


The root element, which is the html element in our HTML files.


The element E that is the nth child of its parent. The n parameter is explained in the note below.


The element F that is the nth child of its parent E, counting backwards from the last one. li:nth-last-child(1) would match the last item in any listthis is the same as li:last-child
(see the note below).


The element that is the nth element of its type in a given parent element.The difference between :nth-child and :nth-of-type is explained in the note below.


Like nth-of-type(n), except counting backwards from the last element in a parent.

Note: Parameters of Structural Selectors

There are four pseudo-classes that take the equation an+b as a parameter in parentheses, or the keywords odd and even. The structural pseudo-classes include :nth-child(an + b), :nth-last-child(an + b), :nth-of-type(an + b), and :nth-last-of-type(an + b). In the equation an+b, a is the multiplier as an integer, b is the offset as an integer, and n is always the variable n.

In the simplest case, you can pass an integer. For example, E:nth-of-type(3) will target the third E element child of a single parent element. You can pass one of the two keywords odd or even, targeting every other element. You can also, more powerfully, pass a
number expression such as E:nth-of-type(3n+1). 3n means every third element, defining the frequency, and +1 is the offset. The default offset is zero, so where :nth-of-type(3n) would match the 3rd, 6th, and 9th elements in a series, :nth-of-type(3n+1 would match the 1st, 4th, 7th, and so on.

Negative offsets are also allowed. CSS is based on linguistic languages, not programming languages, so the count starts at 1 not 0. There can be no space between the multiplier a and the variable n, and the offset must come last.

With these numeric pseudo-classes, you can pinpoint which elements you want to target without adding classes to the markup. The most common example is a table where every other row is a slightly darker color to make it easier to read. We used to have to add odd or even classes to every tr to accomplish this. Now, we can simply declare tr:nth-of-type(odd) to target every odd line without touching the markup. You can even take it a step further with three-colored striped tables: target tr:nth-of-type(3n), tr:nth-of-type(3n+1), and tr:nth-of-type(3n+2) and apply a different color to each.


The element E if E is the first child of its parent. This is the same as E:nth-child(1).


The element E if E is the last child of its parent, same as E:nth-last-child(1).


The same as :nth-of-type(1).


The same as :nth-last-of-type(1).


Element E if E is the only child of its parent.


Element E if E is the only element of type E that is a direct child of its parent element.

Note: Child versus Type

In employing the structural selectors of nth-of-type and nth-child, its important to understand what child and type mean in this case. Child looks at all the child elements that match the count and check if the precursor is a match. Type looks at all the elements that match the precursor first, then matches based on the count.

In the case of p:nth-child(3n), the browser looks at every third child of a parent. If that child is a p, there is a match; if not, no match. In the case of p:nth-of-type(3n), the browser looks at all the p children of the parent, and matches every third p.

Structural pseudo-classes are based on the parent, and restart counting for each new parent. They only look at elements that are the direct children of the parent. Text nodes are not part of the equation.


An element that has no children; this includes text nodes, so <p>hello</p> and <p> </p> will not be matched by p:empty, but <p></p> and <p><!-- comment --></p> will be. This selector also matches empty or void elements, such as <br> and <input> . In CSS Selectors Level 4, well get p:blank that will match <p> </p>.


An element in the language denoted by the two-letter abbreviation, such as en. Unlike E:[lang|=en], where the lang attribute must be present as an attribute of element E, E:lang(en) will match E if the language was declared on the element itself or any ancestor.


This is a particularly useful one: it will select elements that dont match the selector in the parentheses.

Selectors with the :not pseudo-class match everything to the left of the colon, and then exclude from that matched group the elements that also match whats to the right of the colon. The left-hand side matching goes first. For example, p:not(.copyright) will match all the paragraphs in a document first, and then exclude all the paragraphs from the set that also have the class of copyright. You can string several :not pseudo-classes together. input:not([type=checkbox]):not([type=radio]) will match all input elements on a page except those that are of type checkbox or radio.