Selecting a Range of Elements with :nth-child()

Picking out elements between two fixed indexes with CSS is a surprisingly easy task that tends to trip people up. The trick is chaining two :nth-child() selectors together, and the logic bends a bit if you expect the selectors to behave like a union rather than an intersection.

Start at an Index and Go Up

Selecting from a certain index onward is straightforward:

div:nth-child(n + 2) {

}
/* [ ]  [x]  [x]  [x]  [x]  [x]  [x]  [x], etc. */

Here, when n starts at 0, the expression evaluates to 2 and grows with every increment, matching the second element and everything after it.

Cap the Range from the Top

To create an upper bound, invert the direction of n:

div:nth-child(-n + 6) {

}
/* [x]  [x]  [x]  [x]  [x]  [ ]  [ ]  [ ], etc. */

This matches only the first five elements. As n increases, the computed value drops to 0 and then into negative indexes, so nothing past the fifth element qualifies.

Combining Both Boundaries

The key insight is that multiple pseudo-selectors on the same rule are additive in the sense that every condition must be true for an element to match. It’s not that :nth-child() expressions accumulate matches; it’s that each element must independently satisfy both expressions.

To select elements two through five, chain the two selectors together:

div:nth-child(n + 2):nth-child(-n + 6) {
  background: green;
}

An element must be at index 2 or greater and at index 5 or less to qualify. That intersection gives you exactly the second through fifth elements.

This pattern of nesting multiple nth-style pseudo-selectors is also the foundation of quantity queries, where you can apply styles based on how many total elements exist in the DOM.

div:nth-last-child(n+2):nth-last-child(-n+5):first-child, 
div:nth-last-child(n+2):nth-last-child(-n+5):first-child ~ div {
  /* Only select if there are at least 2 and at most 5 */
}