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:

:root

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

E:nth-child(n)

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

E:nth-last-child(n)

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).

E:nth-of-type(n)

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.

E:nth-last-of-type(n)

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.

E:first-child

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

E:last-child

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

:first-of-type

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

E:last-of-type

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

E:only-child

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

E:only-of-type

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.

E:empty

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&gt . In CSS Selectors Level 4, well get p:blank that will match <p> </p>.

E:lang(en)

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.

E:not(exception)

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.

Frequently Asked Questions on Structural Pseudo-Classes

What are the different types of structural pseudo-classes?

Structural pseudo-classes are a subset of CSS pseudo-classes that allow you to select and style elements based on their position in the document tree. They include :root, :nth-child(), :nth-last-child(), :nth-of-type(), :nth-last-of-type(), :first-child, :last-child, :first-of-type, :last-of-type, :only-child, :only-of-type, and :empty. Each of these pseudo-classes has a unique function that allows for more precise styling of HTML elements.

How does the :nth-child() pseudo-class work?

The :nth-child() pseudo-class matches elements based on their position among a group of siblings. It takes an argument, which can be a number, a keyword, or a formula. For example, :nth-child(2) would select the second child of its parent, while :nth-child(odd) or :nth-child(2n+1) would select all odd-numbered children.

What is the difference between :nth-of-type() and :nth-child()?

While both :nth-of-type() and :nth-child() select elements based on their position, they differ in how they count those positions. :nth-child() counts all elements as siblings, regardless of their type, while :nth-of-type() only counts elements of the same type. For example, if you have a list with both

  • and

    elements, :nth-child() would count both types of elements, while :nth-of-type() would only count either

  • or

    elements, depending on which you specify.

  • How can I select and style the first child of a parent element?

    To select and style the first child of a parent element, you can use the :first-child pseudo-class. For example, if you want to change the color of the first

  • element within a
      , you would use the following CSS: ul li:first-child { color: red; }.
  • What does the :only-child pseudo-class do?

    The :only-child pseudo-class matches an element that is the only child of its parent. This is useful when you want to apply styles to an element only when it has no siblings. For example, you might want to add special styling to a

    element only when it’s the only child of a

    .

    How can I use the :empty pseudo-class?

    The :empty pseudo-class matches any element that has no children. This includes text nodes, comments, or other elements. For example, you can use it to hide an empty

    that would otherwise take up space on the page: div:empty { display: none; }.

    Can I combine structural pseudo-classes?

    Yes, you can combine structural pseudo-classes to create more specific selectors. For example, you could use :nth-of-type() and :last-child together to select the last

    element of its type within its parent, only if it’s also the last child of its parent.

    Are structural pseudo-classes supported in all browsers?

    Most modern browsers support structural pseudo-classes, but there may be some inconsistencies or lack of support in older versions of browsers. It’s always a good idea to check the current level of support on a site like Can I Use before using a particular pseudo-class in your CSS.

    Can structural pseudo-classes be used with pseudo-elements?

    Yes, structural pseudo-classes can be used in conjunction with pseudo-elements. For example, you could use the ::before pseudo-element with the :first-child pseudo-class to add content before the first child of a parent element.

    How can I use structural pseudo-classes to create dynamic styles?

    Structural pseudo-classes can be used to create dynamic styles that respond to the structure of your HTML. For example, you could use the :nth-child() pseudo-class with a formula to create a zebra-striped table, or the :hover pseudo-class to change the color of a link when it’s moused over. The possibilities are endless and limited only by your creativity.