March 9, 2014

CSS nth-child Selector Pwned

The CSS3 :nth-child() selector pseudo-class allows you to select elements based on their position in the set of children of their parent. It accepts an argument in the form of an + b. How exactly does it work? Let me explain.

In very simple words, the expression an + b matches every ath element in the set starting from the bth element keeping in mind that (i) the index numbering starts at 1 (ii) zero and negative values do not represent any element (iii) text and non-element nodes are not counted. The following corollaries exist:

  • a can be zero or an can be omitted – in which case there is no "every ath element in the set" clause and only the bth element is matched.
  • a can be negative – in which case every ath element is matched going backwards, towards non-existing elements.
  • b can be zero or negative – in which case the matching starts from a non-existing element.
  • The argument can be odd or even – which represent the expressions 2n + 1 and 2n respectively.

The following chart shows how the expressions match elements:

CSS nth-child Arguments Cheat Sheet

These rules apply to the following CSS3 pseudo-classes:

  • :nth-child() – matches elements that are nth child of their parent.
  • :nth-last-child() – matches elements that are nth child of their parent counting backwards, i.e. 1 represents the last element, 2 represents second last, and so on.
  • :nth-of-type() – matches elements that are nth element of their type among the children of their parent.
  • :nth-last-of-type() – matches elements that are nth element of their type among the children of their parent counting backwards.

Combined Example

Consider the following HTML markup:

<dl>
    <dt>Term 1</dt>
    <dd>Description 1</dd>
    <dt>Term 2</dt>
    <dd>Description 2</dd>
    <dt>Term 3</dt>
    <dd>Description 3</dd>
    <dt>Term 4</dt>
    <dd>Description 4</dd>
</dl>

The aforementioned CSS pseudo classes match as follows:

dl > :nth-child(2n + 1)     /* match elements that are odd children (all dt elements) */
dl > dd:nth-child(2n)       /* match dd elements that are even children (all dd elements) */
dl > dt:nth-child(2n)       /* match dt elements that are even children (no match) */

dl > :nth-last-child(1)     /* match elements that are first child counting from end (last element) */
dl > dt:nth-last-child(1)   /* match dt elements that are first child counting from end (no match) */
dl > dd:nth-last-child(1)   /* match dd elements that are first child counting from end (last dd element) */

dl > :nth-of-type(2n + 1)   /* match elements that are odd elements of their type (first and third dt and dd elements) */
dl > dt:nth-of-type(2n + 1) /* match dt elements that are odd elements of their type (first and third dt elements) */
dl > dd:nth-of-type(2n + 1) /* match dd elements that are odd elements of their type (first and third dd elements) */

dl > :nth-last-of-type(1)   /* match elements that are first elements of their type counting from end (last dt and dd element) */
dl > dt:nth-last-of-type(1) /* match dt elements that are first elements of their type counting from end (last dt element) */
dl > dd:nth-last-of-type(1) /* match dd elements that are first elements of their type counting from end (last dd element) */

Use the following demo to test the arguments.