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:

  1. It locates the second child element of the parent container, regardless of what tag it is.
  2. 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:

  1. Filters the container's direct children down to only <p> elements.
  2. 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.