Grow your CSS skills. Land your dream job.

The Difference Between :nth-child and :nth-of-type

Published by Chris Coyier

Let's assume this HTML:

<section>
   <p>Little</p>
   <p>Piggy</p>    <!-- 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, in "Plain English," means select an element if:

  1. It is a paragraph element
  2. It is the second child of a parent

Our :nth-of-type selector, in "Plain English," means:

  1. 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>    <!-- 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!

Comments

  1. Permalink to comment#

    for that matter, :last-child would work as well…

  2. Permalink to comment#

    Great explanation. Believe it or not, I fell foul of this only today, for about an hour!

    • 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 ><

  3. Permalink to comment#

    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.

  4. Permalink to comment#

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

  5. Permalink to comment#

    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.

    • Bridget

      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.

  6. Permalink to comment#

    Really awesome Chris. Thanks for the tip.

  7. Clear as a crystal! Thanks for that wonderful example and description!

  8. Fantastically useful. I printed it out and put it in my random “snippets” folder. Thanks a lot.

  9. Permalink to comment#

    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 ^^

  10. Bridget

    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.

  11. I’m curious about the stated paragraph requirement of nth-of-child. Yesterday I used nth-child to style this markup

    <ul id="company" class="span-24">
        <li><a href="???">Home</a></li>
        <li><a href="???">Register</a></li>
        <li><a href="???">Sign In</a></li>
        <li><input id="searchBar" name="searchBar" type="text"></li>
        <li><a href="???">Cart</a></li>    
    </ul>

    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…

  12. Can anyone explain “why” it was decided that nth-child should not ignore display:none elements?

  13. Gifford

    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!

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".