Let's assume this HTML:

   <p>Piggy</p>    <!-- Want this one -->

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:

   <p>Piggy</p>    <!-- Want this one -->

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!