:nth-child() vs :nth-of-type()
nth-child() counts every one of the parent’s elements, regardless of tag. nth-of-type() only counts siblings that share the same tag as the chosen selector.
Side-by-side comparison
#What it counts
- :nth-child()
- Every element of the parent, regardless of tag
- :nth-of-type()
- Only siblings with the same tag
Argument syntax
- :nth-child()
- number,
odd,even,An+B - :nth-of-type()
- The same patterns: number,
odd,even,An+B
Counting by class (`of selector`)
- :nth-child()
- Yes, e.g.
:nth-child(2 of .hot) - :nth-of-type()
- No, it only counts tags
Argument-free versions
- :nth-child()
:first-child,:last-child- :nth-of-type()
:first-of-type,:last-of-type
Typical trap
- :nth-child()
- Mixed tags in the parent give a surprising result
- :nth-of-type()
- You need to remember it only counts the given tag, not the class
Typical use
- :nth-child()
- Striped table rows:
tr:nth-child(even) - :nth-of-type()
- A paragraph in an article with interleaved images
Example
#p:first-child { background: #7c3aed; color: #fff; }<article class="stage">
<h4 style="margin: 0 0 6px;">Heading</h4>
<p style="margin: 0 0 6px;">First paragraph</p>
<p style="margin: 0;">Second paragraph</p>
</article>Nothing gets highlighted: the article’s first child is the h4, not a paragraph.
Definition and usage
#The :nth-child() pseudo-class numbers every child of the parent, starting at 1, regardless of what tag they are. It accepts a specific number, the words odd and even, or an An+B pattern, exactly like its sibling pseudo-class.
:nth-of-type() uses the same argument syntax, but only counts siblings that share the same tag as the element on the left side of the selector. In a parent where paragraphs alternate with images, p:nth-of-type(2) points to the second paragraph, even if other elements come before it.
A classic trap is p:first-child, which matches nothing if a heading comes before the first paragraph, because the heading is the parent’s actual first child. p:first-of-type solves that. On the other hand, only :nth-child() understands the newer of <selector> syntax, which counts by class rather than by tag.
Syntax
#:nth-child( <number> | odd | even | An+B [of <selector>]? )
:nth-of-type( <number> | odd | even | An+B )More examples
#p:first-of-type { background: #7c3aed; color: #fff; }<article class="stage">
<h4 style="margin: 0 0 6px;">Heading</h4>
<p style="margin: 0 0 6px;">First paragraph</p>
<p style="margin: 0;">Second paragraph</p>
</article>Now the first paragraph gets highlighted, even though it comes after the heading in the markup.
span:nth-of-type(even) { background: #7c3aed; color: #fff; }<div class="stage" style="display: flex; gap: 6px; flex-wrap: wrap;">
<span class="box">1</span><em>a</em><span class="box">2</span><span class="box">3</span><em>b</em><span class="box">4</span>
</div>nth-of-type only counts among the span elements (2 and 4), ignoring the em elements sitting between them. nth-child(even) would count completely different elements.
Good practices
#- When different tags mix inside a parent,
:nth-of-type()usually gives a more predictable result than:nth-child(). - Only
:nth-child()understands the "of selector" syntax, e.g.:nth-child(2 of .hot), which counts by class. - Classic trap:
p:first-childwon’t work if a heading comes before the first paragraph. Usep:first-of-type.
Related entries
#- :nth-child()Selects elements by position among siblings: every other one, every third, the first three, or everything from the seventh on.
- :nth-of-type()Selects elements by position among siblings with the same tag, for example every other image or the third paragraph.
- :first-childMatches an element that is the first child of its parent.
- :last-childMatches an element that is the last child of its parent.
- :not()Selects elements that match neither the given selector nor any selector in the list.
Spotted a mistake or missing an example? Write to us.