Pseudo-class Selectors

A pseudo-class selector acts as if you have added a class to an element in your markup.

The CSS Layout Workshop: Pseudo-class selectors

You are likely to be familiar with at least two pseudo-class selectors, the ones we use for selecting the states of a link.

a:link {}
a:visited {}

These selectors work by acting as if they added a class depending on the state of the link. In this case whether the link is visited or unvisited.

The other pseudo-classes we might use for a link are actually dynamic pseudo-classes. They apply based on something that happens in the document. A link being hovered over, tabbed to or activated.

a:hover {}
a:active {}
a:focus {}

To use a pseudo-class we append it to the element we want to target with a colon :.

We have several other useful pseudo-classes to play with.

:first-child

Target an element when it is the first child of a parent.

The first-child selector was part of CSS2.1. In this example we have a set of paragraphs.

<div class="wrapper">

<p>Paragraph one.</p>
  
<p>Paragraph two.</p>

To only apply CSS to the first paragraph inside wrapper we use the first-child selector.

.wrapper p:first-child { }

This only works if there is a paragraph element as the first element directly inside that container. If we add a level one heading here then the first-child selector will no longer select the paragraph.

:last-child

Target an element when it is the last child of a parent.

The Selectors Level 3 specification brought us some new pseudo-class selectors. The last-child selector is just like first-child except it targets the last child of the parent.

.wrapper p:last-child { }

It can be handy to achieve things such as removing the bottom border from a list, or the margin from the final element.

:nth-child

Select multiple elements according to their position in the document tree.

The nth-child selector is very useful indeed. A simple example is to use this selector to stripe table rows.

<table>
  <tr>
    <th>Name</th>
    <th>Favourite colour</th>
    <th>Favourite animal</th>
  </tr>
  <tr>
    <td>Rachel</td>
    <td>Purple</td>
    <td>Cat</td>
  </tr>
    <tr>
    <td>Joe</td>
    <td>Pink</td>
    <td>Albatross</td>
  </tr>
    <tr>
    <td>Eloise</td>
    <td>Green</td>
    <td>Slug</td>
  </tr>
</table>

We can apply CSS to the odd rows with the following selector.

tr:nth-child(odd)  { }

Or the even rows:

tr:nth-child(even)  { }

These keywords are not the only way to use nth-child. We can target a specific row. This selector would only select row 2.

tr:nth-child(2)  { }

The keyword value ‘odd’ is equal to this selector, in which we select the first element and every second element after that.

tr:nth-child(2n+1) td { }

There are some excellent resources to help you get your head around how nth-child works. Rather than reproduce all of that here take a look at:

:nth-of-type

Select multiple elements according to their position in the document tree BUT only those elements that are the same as the type the rule is applied to.

Once you have wrapped your head around how nth-child works you can use the same syntax for nth-of-type. This selector selects only those elements that are the same type as the element it is applied to.

My example below shows headings and paragraphs.

To apply CSS to every other paragraph but ignore the headings I could use the following selector.

p:nth-of-type(odd) { }

:only-child

The only-child pseudo-class will match if the element is the only child of the parent - for example a list with only one list item.

li:only-child { }

This can be a useful selector when designing around variable amounts of content coming from a CMS.

:empty

The empty pseudo-class will match if an element is completely empty or just contains an HTML comment.

p:empty { }

It will not match if there is whitespace inside the element.

<p></p>
<p><!-- a comment --></p>
<p> </p>

The empty pseudo-class would match the first two, but not the last paragraph.

:not

The not pseudo-class allows you to do something if a selector does not match. The selector you wish to exclude goes inside the round braces. In the below example we make the font bold if it is not inside a td with a class of animal.

td:not(.animal) {
  font-weight: bold;
}