What Is the Difference Between nth-child and nth-of-type?
The primary difference between CSS :nth-child() and
:nth-of-type() lies in how they count sibling elements:
:nth-child() counts every sibling regardless of its tag or
type, whereas :nth-of-type() filters siblings by their
specific element tag before calculating position. Choosing the wrong
selector can cause styling rules to fail when mixed HTML elements share
the same parent container.
How :nth-child() Works
The :nth-child(n) pseudo-class targets an element based
on its absolute index among all siblings inside a shared parent
container.
When a selector like p:nth-child(2) is used, the browser
evaluates the DOM in two distinct steps:
- It locates the second child element of the parent container, regardless of what tag it is.
- It checks whether that second child is a
<p>element.
If the second child matches the tag, the style applies. If the second
child is a different element (such as an <h1> or
<div>), the selector matches nothing, and no styling
is applied.
<div>
<h1>Heading</h1> <!-- 1st child -->
<p>First paragraph</p> <!-- 2nd child (Matches p:nth-child(2)) -->
<p>Second paragraph</p><!-- 3rd child -->
</div>If an <h2> were inserted directly above
<p>First paragraph</p>, that paragraph would
become the 3rd child, causing p:nth-child(2) to fail
completely.
How :nth-of-type() Works
The :nth-of-type(n) pseudo-class ignores siblings of
other tag types and counts only elements sharing the exact same HTML
tag.
When p:nth-of-type(2) is evaluated, the browser:
- Filters the container's direct children down to only
<p>elements. - Selects the second item in that filtered list.
<div>
<h1>Heading</h1> <!-- Ignored (not a <p>) -->
<p>First paragraph</p> <!-- 1st <p> -->
<div>Callout</div> <!-- Ignored (not a <p>) -->
<p>Second paragraph</p><!-- 2nd <p> (Matches p:nth-of-type(2)) -->
</div>Even if other HTML elements are added or rearranged around the
paragraphs, p:nth-of-type(2) consistently targets the
second <p> tag in the container.
Side-by-Side Comparison
| Feature | :nth-child() |
:nth-of-type() |
|---|---|---|
| Counting Scope | All siblings inside the parent | Only siblings with the specified tag |
| Fragility to DOM Changes | High (sensitive to unrelated siblings) | Low (isolated to identical tags) |
| Best Use Case | Uniform grids, lists, table rows | Heterogeneous content, mixed article layouts |
| Tag Agnostic Behavior | Works with generic class selectors | Groups strictly by underlying HTML tag |
When to Use Each Selector
Use :nth-child() when working with homogeneous lists
where every child element is identical, such as alternating background
colors across table rows (tr:nth-child(even)) or structured
navigation links (li:nth-child(3)).
Use :nth-of-type() when styling mixed layouts where
different tags live side-by-side, such as blog posts containing
arbitrary headings, blockquotes, and images interspersed among
paragraphs.