Let’s assume this HTML:
<section>
<p>Little</p>
<p>Piggy</p> <!-- We want this one -->
</section>
These will do the exact same thing:
p:nth-child(2) { color: red; }
p:nth-of-type(2) { color: red; }
There is a difference though of course.
Our :nth-child
selector above, in “Plain English,” means select an element if:
- It is a paragraph element
- It is the second child of a parent
Our :nth-of-type
selector, in “Plain English,” means:
- Select the second paragraph child of a parent
:nth-of-type
is… what’s a good way to say it… less conditional.
Let’s say our markup changed to this:
<section>
<h1>Words</h1>
<p>Little</p>
<p>Piggy</p> <!-- We want this one -->
</section>
This breaks:
p:nth-child(2) { color: red; } /* Now incorrect */
This still works:
p:nth-of-type(2) { color: red; } /* Still works */
By “breaks”, I mean that the :nth-child
selector above is now selecting the word “Little” instead of “Piggy” because that element fulfills both 1) it’s the second child and 2) it’s a paragraph element. By “still works,” I mean that “Piggy” is still being selected because it’s the second paragraph under that parent element.
If we were to add an <h2>
after that <h1>
, the :nth-child selector wouldn’t select anything at all, because now the second child is no longer a paragraph so that selector finds nothing. The :nth-of-type
again still works.
I feel like :nth-of-type
is less fragile and more useful in general, despite :nth-child
being more common (in my eyes). How often do you think “I want to select the second child of a parent if it just happens to be a paragraph.” Possibly sometimes, but more likely you want to “select the second paragraph” or “select every third table row,” which are cases where :nth-of-type
is (again, in my eyes) a stronger choice.
I find most of my “crap, why isn’t this :nth-child selector working?!” moments are because it turns out I’ve tag-qualified the selector and that number child isn’t really that tag. So when using :nth-child
, I find it’s generally best to specify the parent and leave :nth-child
un-tag-qualified.
dl :nth-child(2) { } /* is better than */
dd:nth-child(2) { } /* this */
But, of course, it all depends on the exact situation.
Browser support for :nth-of-type
is fairly decent… Firefox 3.5+, Opera 9.5+, Chrome 2+, Safari 3.1+, IE 9+.
I’d say if you need deeper support, jQuery would have your back (use the selector there, apply a class, and style with that class), but in fact jQuery dropped support for :nth-of-type. Seems weird to me. I heard it was because of low usage. If you want to go that route here is a plugin to get them back. jQuery 1.9 does now support :nth-of-type
again (back to IE 6), so that is an option.
Related: don’t forget about the awesome cousins :first-of-type
, :last-of-type
, :nth-last-of-type
and :only-of-type
. Learn more here.
If you want to play around with a visual example, check out this tool!
for that matter, :last-child would work as well…
Great explanation. Believe it or not, I fell foul of this only today, for about an hour!
I also must say, this behaviour is confusing!
If you wanted to apply CSS on hover, you’d add
p:hover {}
So it stands to reason that if you wanted to apply CSS to every nth p you’d use:
p:nth-child(2)
Of course, that is not the case.
Exactly, it’s just a bit wonky and doesn’t always jive with natural assumptions.
I really need to check a few dozen stylesheets right now ><
For what’s it’s worth, I agree with you, nth-of-type is really usefull.
And to ensure it’s compatibility with officially unsupported browsers: this is a job for the mighty selectivzr.
Whoops! Small typo in that link. Try http://selectivizr.com/ instead.
Selectivizr is actually by Keith Clark who also did the jquery plugin that Chris linked to in his post, so I’m guessing Selectivizr is probably the more up-to-date option.
I actually ran into this problem last week. It took me about an hour to realise that I should use :north-of-type.
I couldn’t quite understand why this was, until now :)
Good article. I think most of the time you’d want nth-of-type over nth-child.
However one instance of nth-child which would be useful, and I think worth highlighting, is where you want the nth element, but don’t care what type the element is. eg.
.some-parent :nth-child(n)
Then it doesn’t matter if it’s full of spans, divs, whatever, you’ll always get the nth element..
Yep, that’s the technical use case, but what’s a real use case? I’m sure there are some here and there, but it’s not common.
The real use case is probably limited, but predictable — such as use tin highlighting specific table rows or columns…or certain list items. In cases like those you can be certain that a tr remains a tr or an li remains an li, thereby making the nth-child a de net choice. But, like you mentioned, nth-of-type will work fine, too.
Really awesome Chris. Thanks for the tip.
Clear as a crystal! Thanks for that wonderful example and description!
Fantastically useful. I printed it out and put it in my random “snippets” folder. Thanks a lot.
there is :first-child
is there any :first-of-type?
just curios about it there is :first-child
is there any :first-of-type?
just curios about it ^^
No Julian,
First-of-type is not applicable and that attrb not updated in css3
Sorry …for the prev post…
http://reference.sitepoint.com/css/pseudoclass-firstoftype
just look at this for ur solutions
It’s a shame jQuery dropped nth-of-type. Recently, I have found myself using it quite a bit to reduce the number of classes I use in my markup. Using nth-of-type makes it easy to fine tune what element I want to target. Hopefully they will reinstate it in the near future, once people realize what a powerful tool it is.
I’m curious about the stated paragraph requirement of nth-of-child. Yesterday I used nth-child to style this markup
So, for instance, I used #company li:nth-child(2) to specify the Register button. Works fine in FF and Safari, haven’t done any other testing yet, just a rough edit mockup…
My understanding is that nth-child works for any child element, irregardless of the type of element. What am I missing?
Thanks!
Paragraphs were just an example in this article. In your example, you used li:nth-child(2), so that selector will only select if the second child is a list item. If the second child is any other element, it won’t match.
Cool, got it. And just wanted to thank you for putting together this great resource. Definitely end up here a couple times a week researching how to do this or that…
Can anyone explain “why” it was decided that nth-child should not ignore display:none elements?
CHRIS, thanks for this! I was going crazy because I followed one of your podcasts (“A Quick Useful Case for Sass Math and Mixins” from 3/13) and then I threw a “ in before my boxes and everything hit the fan… this cleared it right up!