A Neat Little CSS Hack: Duplicates in Chained Selectors

Last Friday I gave a presentation on CSS at lunch. At one point, as I was knee-deep in the section talking about chaining selectors to increase specificity, one of our crack QA engineers asked a question that I didn’t know the answer to: Is it possible to chain the same thing in a selector multiple times? For example, does a selector like .first.first.first match an element such as <div class="first">?

The answer might seem obvious, but I would counter that it isn’t for two reasons:

  1. It’s kind of an edge case. Browsers don’t always agree on edge cases.
  2. IE doesn’t always agree with other browsers in general.

So Jansen, our fearless QA engineer, set out to determine whether or not browsers would just do the right thing with confronted with a chain of duplicate selectors. The results may (or may not) surprise you.

Duplicated Class Selectors

Example: .first.first
Result: matches <div class="first"> in all major browsers: Chrome, Firefox, Safari, and IE 8+.

Duplicated ID Selectors

Example: #container#container
Result: matches <div id="container"> in Chrome/FF/Safari. IE didn’t want to come out to play for this one.

Duplicated Pseudoclass Selectors

Example: #container > :last-child:last-child
Result: matches the last-child of <div id="container"> in Chrome/FF/Safari/IE9+. (IE8 doesn’t support :last-child, and I didn’t bother coming up with a test case in IE8 – it may very well work).

But Uncle Redfin, Why Do I Care?

Honestly, maybe you don’t. We’ve written our share of CSS here at Redfin, and it hasn’t come up before, so there’s probably a reasonable chance you can just ignore it and walk away whistling.

If you don’t feel like whistling, here’s a hypothetical story: you could imagine using this to increase the specificity of a selector without actually providing more information. For example, if you had a selector like .list .item, but you couldn’t add type selectors to the chain, but you needed to increase the specificity of the you could just change it to .list .item.item. Problem solved. (Hopefully.)

Anybody have any real-world examples of usage like this? And is it a feature or a bug?

Simple test case Gist is here: https://gist.github.com/roblg/eb2629d69982e2e8135c