CSSStructural Pseudo-Classes (:nth-child, :first-of-type)

Structural Pseudo-Classes (:nth-child, :first-of-type)

Structural pseudo-classes select elements based on their POSITION in the document structure — first, last, only, or nth in some sequence — rather than by class, attribute, or state. They let you style "the first item in this list" or "every row except the last" directly in CSS, without adding a special class to that one element in your markup.

The basics
  • :first-child — matches an element only if it is the very first child of its parent, regardless of element type.

  • :last-child — matches an element only if it is the very last child of its parent.

  • :first-of-type — matches an element if it is the first child of its specific element TYPE among its siblings (other types are ignored when counting).

  • :last-of-type — the last child of its specific element type among its siblings.

  • :only-child — matches an element that is the one and only child of its parent (no siblings at all).

:first-child vs. :first-of-type — a common source of confusion

:first-child

:first-of-type

Must be the first child of ANY type in its parent

Must be the first child of its OWN element type — other types before it don't disqualify it

In mixed content, only matches if that exact element happens to be first overall

Matches the first occurrence of that tag, even if other tags come before it

Worked example — the difference, concretely

HTML
<article>
  <span>Byline</span>
  <p>First paragraph.</p>
  <p>Second paragraph.</p>
</article>

CSS
/* p:first-child — matches NOTHING here.
   The <p> is not the first child overall; <span> is. */
article p:first-child {
  font-weight: bold;
}

/* p:first-of-type — matches "First paragraph."
   It IS the first <p> among the <p> elements, even though
   a <span> came before it in the markup. */
article p:first-of-type {
  font-weight: bold;
}

This is exactly the trap that catches people: if you want to style "the first paragraph" in content that might have other elements (a byline, a figure, a heading) mixed in before it, :first-child silently matches nothing the moment something else precedes it. :first-of-type is almost always the one you actually want for "the first element of this tag", while :first-child is for "the first thing in this container, whatever it is".

:only-child and :last-of-type in practice

CSS
/* Style a card differently if it's the only item in its grid */
.grid-item:only-child {
  max-width: 400px;
  margin: 0 auto;
}

/* Remove the bottom border from the last paragraph of an article,
   even if a <footer> or <aside> follows it in the markup */
article p:last-of-type {
  border-bottom: none;
}
Next: nth-child() formulas
first/last/only cover fixed positions. For matching every 2nd, 3rd, or Nth item — alternating row colors, staggered animation delays, arbitrary positional patterns — see the dedicated [:nth-child() & :nth-of-type() Formulas](/css/nth-child) page.
Tip
When in doubt with mixed-content containers, reach for the `-of-type` variant first — it's more resilient to markup changes (adding an icon or label before your target element) than the plain `-child` variants.