|<<>>|52 of 283 Show listMobile Mode

TIL: nth-of-type() and na+b in CSS

Published by marco on

I’ve known about nth-child(n) for a long time. It selects the nth child from a structure if that child happens to match the given tag. You can always select the nth child by omitting the tag.

For example, div :nth-child(2) (two selectors) will match the second child of any div, regardless of type. However, div span:nth-child(2) will only match if the second child is also a span.

You cannot write a selector that says “select the second span” using nth-child. That’s where nth-of-type(n) comes in. The selector div span:nth-of-type(2) does exactly that. I can’t recall that I’ve ever had this need before, but it’s also possible that I ended up adding extra tags or convoluted selectors in order to achieve what could have been more elegantly done with nth-of-type.

Additionally, while I was aware that nth-child supported constants and the keywords odd and even, I didn’t know that it also supported a formula an + b. The a is a multiplier and b is an offset. With this formula, you can select every third or fifth (or whatever) element and then move the selection by a given offset.

The selectors first-of-type, last-of-type, etc. also exist, as well as only-of-type, which matches an element when it’s the only child of that type in the parent. See Meet the Pseudo Class Selectors by Chris Coyier (CSS Tricks) for more information.

You may see where this is heading. The article The wondrous world of CSS counters by Chen Hui Jeng includes an example where he writes the famous FizzBuzz program with CSS.

Start with an ordered list,

<ol>
  <li></li>
  …add more li elements, like 30 of them…
  <li></li>
</ol>

Then apply the following CSS to it,

ol { list-style-position: inside } /* To line-up all items neatly */

li:nth-of-type(3n+3),
li:nth-of-type(5n+5),
li:nth-of-type(3n+3):nth-of-type(5n+5) {
  list-style: none /* When text of Fizz, Buzz or FizzBuzz appears, get rid of the numbers */
}

li:nth-of-type(3n+3)::before {  content: "Fizz" }
li:nth-of-type(5n+5)::before {  content: "Buzz" }
li:nth-of-type(3n+3):nth-of-type(5n+5)::before {  content: "FizzBuzz" }

Put it all together and you get CSS FizzBuzz.