CSS3 offers a ton of brand new ways that you can select elements in ways we’ve never thought of before. Today I want to focus on exclusively the structural pseudo-classes, which are ways of selecting elements based on the document tree. CSS2.1 limited us to `:first-child`

and IE7 and 8 have done a great job since then at limiting our imagination. But today I’m pretending IE7 and 8 don’t exist and I’m going to share some patterns in CSS3’s structural pseudo-classes that you probably thought were confined to JavaScript.

## Our New Structural Pseudo Classes

### Algebraic Pseudo Classes

These take an algebraic argument of some sort. In the parenthesis you would provide either an integer, `n`

, and possibly some basic addition and subtraction ( − or +). As you can figure from the names, you can create mathematical arguments of either any old element in the tree, or an element of a specific type.

`:nth-child()`

`:nth-last-child()`

`:nth-of-type()`

`:nth-last-of-type()`

### Ordinal Pseudo Classes

These don’t require any argument. The names are fairly descriptive of what they do, I’d consider these first before taking on an algebraic pseudo-class.

`:first-child`

`:last-child`

`:first-of-type`

`:last-of-type`

### Parent-type Pseudo-Classes

These pseudo-classes deal with the mere presence of child elements. `:only-child`

and `:only-of-type`

will target elements that have no siblings, whereas `:empty`

will target an element with nothing at all.

`:only-child`

`:only-of-type`

`:empty`

### Miscellaneous Pseudo-Classes

I absolutely don’t get `:root`

. It’s supposed to target the root of the document. As far as I know, this would be `html`

. I don’t know of any cases where `html`

wouldn’t be the root. As for `:not()`

, it’s exactly what you think. Insert the selector you *aren’t* targeting.

`:root`

`:not()`

### Understanding the Type Selectors

It’s a bit hard to understand the difference between `:first-child`

and `:first-of-type`

. So let’s assume the following, completely fictional HTML.

<article> <h2>Eat Moar Bacon</h2> <h2>Otherwise the pigs win</h2> <h3>George Orwell was right</h3> <p>Communists don't like bacon</p> </article>

The first element in your article is an `h2`

, and it is immediately followed by another one. When you write `h2:first-child{red}`

, you’ll find that “Eat Moar Bacon” is red.

However, if you you write `h3:first-child{color:red}`

, “George Orwell was right” won’t be red. That’s because it’s not the first element in your `article`

. Instead, you should write `h3:first-of-type{color:red}`

. So, the `type`

selectors aren’t just counting items in the document tree, they’re counting specific elements. This becomes insanely useful when you’re dealing with a CMS that could be kicking out some unwanted markup.

## Counting Elements with CSS3

Yeah, you saw right, we can count the elements with CSS3. What you’ll notice in the list below is that I use `:nth-last-child(){}`

as my first selector very frequently. Basically, I’m starting at the end, and counting towards the beginning. That puts my final selector at the beginning of the document tree, which then enables me to add a combinator in order to select everything after it. So now, let’s figure out how to create a style for only three articles.

I start with article, then add in my `nth-last-child(n+3)`

. So this tells the rendering engine to look for the third-to-last article. Then I add in `first-child`

, which tell the browser to find the third-to-last article that is *also* the first one. I then use my non-adjacent sibling selector (`~`

) to select everything after this first-child of a group of three.

`article:nth-last-child(n+3):first-child ~ article{width: 33%}`

Now, that method targeted everything *after* the first-child in a set of three. You probably still want to target the first child in our set of three. Therefore, you should add in a selector just for that:

`article:nth-last-child(n+3):first-child,article:nth-last-child(n+3):first-child ~ article{width: 33%}`

Of course you can try this method with `nth-child`

and `last-child`

, where you’d be selecting the *final* article in a set of three; a great way to get in that missing 1% of your width:

`article:nth-child(n+3):last-child ~ article{width: 34%}`

## The Big idea with CSS3’s Pseudo-Classes

If you’re figuring out what’s going on here, **we’re using CSS’ Pseudo-Classes to act like media queries**. We can read how many… things are in the DOM, and create a style that supports this. How cool is that? And before you poo-poo this Chuck-Norris-style-roundhouse-kick to unpredictable content layouts’ face because it won’t work in IE7 or IE8, remember that this *totally* works for mobile devices— reaffirming that this is a justifiable approach when you’re in need of media queries.

So below you’ll find some tables of different patterns that I’ve put together. It’s not a crazy comprehensive list, but the idea is to show you a pattern for you to use in your own mobile project or crazy cool modern-browser design. You can use these patterns to solve these common problems:

- Adjust width or height of elements based on the number that appear on the page
- Create Zebra-stripe patterns unique to whether you have even or odd numbered rows or columns
- Switch from liquid, to fluid, to semi elastic widths or heights by including or excluding outermost elements within a group
- Demonstrate more stylistic complexity that can make tables easier to read
- Produce Layouts that can adapt easily to even vs. odd-numbered columns

I haven’t touched on the `:not()`

selector here. It’s so wicked awesome that it deserves its own separate post. On to the tables!

### Rules for x amount of elements:

Selector | What it does |
---|---|

:nth-child(n+3) | Starting at third element AND all elements thereafter |

:nth-child(-n+3) | Only first three elements |

:nth-last-child(3):first-child | First of exactly 3 elements |

:nth-last-child(-n+3):first-child | First element of three or more elements |

:nth-last-child(-n+2):nth-child(-n+2) | First, Second, and Middle of three elements |

:nth-child(2):nth-last-child(2) | Middle element of exactly three elements |

:last-child:nth-child(3) | Last element of exactly three elements |

:last-child:nth-child(n+3) | Last element of three or more elements |

:last-child:nth-child(-n+3) | Last element for up-to three elements |

### Getting the Elements in the middle

Selector | What it does |
---|---|

:nth-last-child(n+2):nth-child(n+2) | All elements except the first and last |

:nth-last-child(n+3):nth-child(n+3) | All elements except the first two and the last two |

### Getting Elements that are Products (multiples)

Selector | What it Does |
---|---|

:nth-child(3n) | Every third element starting at three |

:nth-child(3n+1) | Starting with 1, every third element thereafter |

:nth-child(3n+12) | Elements that are multiples of three, starting at 12 |

:nth-child(-3n+9) | Elements which are multiples of three, but stopping after nine |

:nth-child(2n):nth-child(3n) | Elements which are multiples of both two and three |

:nth-last-child(3n):first-child | First element out of a group of elements that’s a multiple of three |

:nth-last-child(3n):nth-last-child(2n):first-child | First element out of a group of elements that’s a multiple of both two and three |

### Evens and Odds

Selector | What it Does |
---|---|

:nth-child(even) | All even-numbered elements |

:nth-child(odd) | All odd-numbered elements |

:nth-last-child(odd):first-child | First element in a group of odd-numbered elements |

:nth-last-child(even):first-child | First element in a group of even-numbered elements |

:nth-child(even):nth-last-child(odd) | Last child in a group of even numbered elements ONLY when the group is an even number |

:nth-child(even):nth-last-child(even) | even numbered elements only if the group is odd-numbered |

:nth-child(odd):nth-last-child(even) | Odd numbered elements only if the group is even-numbered |

:nth-child(odd):nth-last-child(odd) | Odd numbered elements only if the group is odd-numbered |

I’ve found an excuse to use most of these selectors at least once in a project. So if you have questions, drop me a line.