by

CSS3: Structural Pseudo-Class Patterns

Reading Time: 4 minutes

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:

  1. Adjust width or height of elements based on the number that appear on the page
  2. Create Zebra-stripe patterns unique to whether you have even or odd numbered rows or columns
  3. Switch from liquid, to fluid, to semi elastic widths or heights by including or excluding outermost elements within a group
  4. Demonstrate more stylistic complexity that can make tables easier to read
  5. 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:

SelectorWhat 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-childFirst of exactly 3 elements
:nth-last-child(-n+3):first-childFirst 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

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

SelectorWhat 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-childFirst element out of a group of elements that’s a multiple of three
:nth-last-child(3n):nth-last-child(2n):first-childFirst element out of a group of elements that’s a multiple of both two and three 

Evens and Odds

SelectorWhat it Does
:nth-child(even)All even-numbered elements
:nth-child(odd)All odd-numbered elements
:nth-last-child(odd):first-childFirst element in a group of odd-numbered elements
:nth-last-child(even):first-childFirst 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.