CSS :nth-of-type() Intro

:nth-of-type() selects elements based on their position among siblings of the same tag name. It’s like saying: “Give me the 3rd <li>” or “Every even <article>.”

Two key ideas to keep in your brain’s RAM:

  • “Type” means tag name (like li, p, article), not a class.
  • It counts only within the same parent (siblings), and only among the same type.
.list > li:nth-of-type(2) {
  outline: 3px solid #111;
  background: #ffef9a;
}
  
.list > li:nth-of-type(3) {
  outline: 3px solid #111;
  background: #b8f2e6;
}
  
.list > li:nth-of-type(4) {
  outline: 3px solid #111;
  background: #ffd6e0;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.demo {
  font-family: system-ui, Arial, sans-serif;
  padding: 18px;
  max-width: 980px;
}

.list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 10px;
}

.list > li {
  border: 2px solid #111;
  border-radius: 14px;
  padding: 12px 14px;
  background: #f6f6f6;
}

.list strong {
  font-weight: 700;
}
  
  • Item 1 – first <li>
  • Item 2 – second <li>
  • Item 3 – third <li>
  • Item 4 – fourth <li>
  • Item 5 – fifth <li>

CSS :nth-of-type() First

To select the first element of a given type, you have two options:

  • :nth-of-type(1) (explicit and math-friendly)
  • :first-of-type (more readable)
.cards > article:nth-of-type(1) {
  background: #e6f7ff;
  border-color: #0b63ce;
}
  
.cards > article:first-of-type {
  background: #e6f7ff;
  border-color: #0b63ce;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.demo {
  font-family: system-ui, Arial, sans-serif;
  padding: 18px;
  max-width: 980px;
}

.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.cards article {
  border: 2px solid #111;
  border-radius: 16px;
  padding: 14px;
  background: #f6f6f6;
}

.cards h4 {
  margin: 0 0 6px;
  font-size: 16px;
}

.cards p {
  margin: 0;
  opacity: 0.85;
}

@media (max-width: 720px) {
  .cards {
    grid-template-columns: 1fr;
  }
}
  

Article A

The first <article> inside .cards.

Article B

Still an <article> sibling.

Article C

Third <article> sibling.

CSS :nth-of-type() Last and Second to Last

For “last,” you can use:

  • :last-of-type
  • :nth-last-of-type(1) (same thing, more consistent with patterns)

For “second to last,” use :nth-last-of-type(2).

.timeline > li:last-of-type {
  background: #eaffea;
  border-color: #148b2c;
}
  
.timeline > li:nth-last-of-type(1) {
  background: #eaffea;
  border-color: #148b2c;
}
  
.timeline > li:nth-last-of-type(2) {
  background: #fff3d6;
  border-color: #b06b00;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.demo {
  font-family: system-ui, Arial, sans-serif;
  padding: 18px;
  max-width: 980px;
}

.timeline {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 10px;
}

.timeline > li {
  border: 2px solid #111;
  border-radius: 16px;
  padding: 12px 14px;
  background: #f6f6f6;
  display: grid;
  gap: 4px;
}

.timeline .meta {
  font-size: 13px;
  opacity: 0.75;
}
  
  1. Step 1
    Oldest
  2. Step 2
    Still going
  3. Step 3
    Almost there
  4. Step 4
    Newest (last)

CSS :nth-of-type() Even and Odd

even and odd are shortcuts for common patterns:

  • :nth-of-type(even) = 2nd, 4th, 6th, …
  • :nth-of-type(odd) = 1st, 3rd, 5th, …
.zebra > li:nth-of-type(even) {
  background: #eef3ff;
}
  
.zebra > li:nth-of-type(odd) {
  background: #fff1f1;
}
  
.zebra > li:nth-of-type(odd) {
  background: #fff1f1;
}

.zebra > li:nth-of-type(even) {
  background: #eef3ff;
}

.zebra > li {
  border-style: dashed;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.demo {
  font-family: system-ui, Arial, sans-serif;
  padding: 18px;
  max-width: 980px;
}

.zebra {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 10px;
}

.zebra > li {
  border: 2px solid #111;
  border-radius: 16px;
  padding: 12px 14px;
  background: #f6f6f6;
}
  
  • Row 1
  • Row 2
  • Row 3
  • Row 4
  • Row 5
  • Row 6

CSS :nth-of-type() Range

CSS doesn’t have a built-in “between 3 and 6” syntax, but you can create ranges using two selectors:

  • :nth-of-type(n + A) means “A and onward”
  • :nth-of-type(-n + B) means “up to B”

Combine them to target a slice: A through B.

.grid > div:nth-of-type(n + 3):nth-of-type(-n + 6) {
  background: #ffe9b5;
  border-color: #b06b00;
  transform: translateY(-2px);
}
  
.grid > div:nth-of-type(n + 2):nth-of-type(-n + 4) {
  background: #d7f9ff;
  border-color: #0b63ce;
  transform: translateY(-2px);
}
  
.grid > div:nth-of-type(n + 5):nth-of-type(-n + 8) {
  background: #eaffea;
  border-color: #148b2c;
  transform: translateY(-2px);
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.demo {
  font-family: system-ui, Arial, sans-serif;
  padding: 18px;
  max-width: 980px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}

.grid > div {
  border: 2px solid #111;
  border-radius: 16px;
  padding: 14px 10px;
  background: #f6f6f6;
  text-align: center;
  font-weight: 700;
}

@media (max-width: 720px) {
  .grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
  
1
2
3
4
5
6
7
8

Snippet 1 (:nth-of-type(n + 3):nth-of-type(-n + 6)) targets items 3 through 6. Snippet 2 (:nth-of-type(n + 2):nth-of-type(-n + 4)) targets items 2 through 4, and snippet 3 (:nth-of-type(n + 5):nth-of-type(-n + 8)) targets items 5 through 8.

Learn more about targeting ranges in the CSS :nth-child() tutorial, which also applies to :nth-of-type() since they share the same formula syntax. CSS Nth Child Interactive Tutorial.

CSS :nth-of-type() Formulas (an + b)

The power move is the an + b formula. It reads like:

  • a = step size (every a items)
  • b = starting offset

Example: 3n + 2 selects 2, 5, 8, 11, … (every 3rd item, starting at 2).

.tiles > li:nth-of-type(3n + 2) {
  background: #efe7ff;
  border-color: #5a2ea6;
}
  
.tiles > li:nth-of-type(4n) {
  background: #eaffea;
  border-color: #148b2c;
}
  
.tiles > li:nth-of-type(5n + 1) {
  background: #ffe9b5;
  border-color: #b06b00;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.demo {
  font-family: system-ui, Arial, sans-serif;
  padding: 18px;
  max-width: 980px;
}

.tiles {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 10px;
}

.tiles > li {
  border: 2px solid #111;
  border-radius: 16px;
  padding: 14px 10px;
  background: #f6f6f6;
  text-align: center;
  font-weight: 700;
}

@media (max-width: 840px) {
  .tiles {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

CSS :nth-of-type() vs :nth-child()

This is where many selectors go to pretend they’re not confused. The difference is simple:

  • :nth-child() counts all element types among siblings.
  • :nth-of-type() counts only the same tag name.

The best way to feel this difference is to mix elements.

.mixed > :nth-child(3) {
  background: #ffe9b5;
  border-color: #b06b00;
}
  
.mixed > p:nth-of-type(3) {
  background: #d7f9ff;
  border-color: #0b63ce;
}
  
.mixed > p:nth-child(3) {
  background: #ffd6e0;
  border-color: #9a1a3a;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.demo {
  font-family: system-ui, Arial, sans-serif;
  padding: 18px;
  max-width: 980px;
}

.mixed {
  display: grid;
  gap: 10px;
}

.mixed > * {
  border: 2px solid #111;
  border-radius: 16px;
  padding: 12px 14px;
  background: #f6f6f6;
}

.mixed code {
  font-family: ui-monospace, SFMono-Regular, Menlo;
  font-size: 0.95em;
}
  

1) <p> First paragraph

2) <div> A random div (still a child!)

3) <p> Second paragraph

4) <p> Third paragraph

5) <span> A span sneaks in

6) <p> Fourth paragraph

Try each snippet: :nth-child(3) targets the 3rd child (regardless of tag), while p:nth-of-type(3) targets the 3rd <p> only.

“Nth of type class” and the Modern “of S” Syntax

People often ask for something like “the 2nd element of this class.” :nth-of-type() cannot count classes, because it counts tag names.

But newer CSS Selectors Level 4 added an “of S” feature (for :nth-child and friends) that can count only elements matching a selector: :nth-child(2 of .featured).

Browser support is still relatively limited, so treat it as progressive enhancement. Check support here: caniuse.com/css-nth-child-of

@supports selector(:nth-child(2 of .featured)) {
  .menu > li:nth-child(2 of .featured) {
    background: #eaffea;
    border-color: #148b2c;
  }
}

@supports not selector(:nth-child(2 of .featured)) {
.note {
display: block;
}
} 
*,
::before,
::after {
  box-sizing: border-box;
}

.demo {
  font-family: system-ui, Arial, sans-serif;
  padding: 18px;
  max-width: 980px;
}

.menu {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 10px;
}

.menu > li {
  border: 2px solid #111;
  border-radius: 16px;
  padding: 12px 14px;
  background: #f6f6f6;
}

.menu > li.featured {
  border-style: dashed;
}

.note {
  display: none;
  margin-top: 12px;
  padding: 12px 14px;
  border: 2px solid #111;
  border-radius: 16px;
  background: #fff3d6;
}
  
Your browser may not support :nth-child(… of …) yet, so this demo is showing the fallback note.

If supported, the rule targets: the 2nd element among the .featured items only. Notice we used :nth-child(2 of .featured), not :nth-of-type().

Learn more about the ":nth-of-class" selector in the CSS Nth Child (N of Selector) Interactive Tutorial.

When :nth-of-type() “Is Not Working”

If :nth-of-type() seems broken, it’s usually doing exactly what you told it… just not what you meant. Here’s a practical checklist.

1) “Type” means tag name, not class

  • li:nth-of-type(2) counts <li> elements
  • .item:nth-of-type(2) only works if .item is on elements that share the same tag name

2) Mixed elements change the counting (and that’s the point)

If your parent contains <p>, <div>, <span>, etc., then p:nth-of-type(2) counts only paragraphs, ignoring the others.

3) You might be selecting from the wrong parent

:nth-of-type() counts siblings under the same parent. If you expected it to count across multiple groups, you probably need to select the correct container first.

4) You’re targeting the wrong element type

Example: you wrote .list :nth-of-type(2) but the items are <div> not <li>. Be explicit when debugging:

  • .list > li:nth-of-type(2)
  • .list > div:nth-of-type(2)

5) The styles apply, but you can’t tell

Sometimes the selector matches fine, but the visual change is too small (or overridden). When debugging, temporarily use something loud: outline: 4px solid red;

.debug > p:nth-of-type(2) {
  outline: 4px solid #c40000;
  background: #ffd6d6;
}
  
.debug > :nth-child(2) {
  outline: 4px solid #0b63ce;
  background: #d7f1ff;
}
  
.debug > p:nth-child(2) {
  outline: 4px solid #148b2c;
  background: #d6ffe0;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.demo {
  font-family: system-ui, Arial, sans-serif;
  padding: 18px;
  max-width: 980px;
}

.debug {
  display: grid;
  gap: 10px;
}

.debug > * {
  border: 2px solid #111;
  border-radius: 16px;
  padding: 12px 14px;
  background: #f6f6f6;
}
  

1) <p> First paragraph

2) <div> A div in the middle

3) <p> Second paragraph (this is p:nth-of-type(2))

4) <p> Third paragraph

Use the snippets to see which selector matches what: p:nth-of-type(2) vs :nth-child(2) vs p:nth-child(2).

Summary

  • :nth-of-type() counts siblings with the same tag name.
  • Use :nth-of-type(1) / :first-of-type for “first”.
  • Use :nth-last-of-type(1) / :last-of-type for “last”, and :nth-last-of-type(2) for “second to last”.
  • odd / even are great for zebra patterns.
  • Ranges are done by combining n + A and -n + B.
  • For “nth of this class,” look at :nth-child(… of .class) with progressive enhancement and check support: caniuse.com/css-nth-child-of