:nth-child


Le sélecteur :nth-child (“n-ième enfant”) vous permet de sélectionner un ou plusieurs éléments en fonction de leur ordre dans la source et selon des critères que vous déterminez. La spécification W3C le range parmi les “pseudo-classes structurelles”, ce qui signifie qu'il est utilisé pour appliquer un style au contenu en fonction de ses relations avec les éléments parents et enfants.

Supposons que nous ayons une grille CSS et que nous voulions retirer la marge sur chaque quatrième module :

//HTML
<section class="grid">
  <article class="module">One</article>
  <article class="module">Two</article>
  <article class="module">Three</article>
  <article class="module">Four</article>
  <article class="module">Five</article>
</section>

Plutôt que d'ajouter une classe à chaque quatrième item, nous pouvons utiliser :nth-child :

//CSS
.module:nth-child(4n) {
  margin-right: 0;
}

Comme vous le voyez, :nth-child prend un argument (c'est le n-ième enfant, mais il faut bien préciser comment on détermine ce n). Cela peut être un simple chiffre, les mots-clés even (pair) ou odd (impair), ou bien une formule.

Si un chiffre est spécifié, seul un élément sera sélectionné, par exemple :nth-child(2) sélectionnerait le deuxième module dans notre HTML ci-dessus.

Si c'est un mot-clé ou une formule, une itération permettra de sélectionner le ou les éléments correspondants. Par exemple, :nth-child(even) sélectionnerait les modules 2 et 4. :nth-child(3n+1) séléctionnerait les modules 1 et 4.

Au passage, on voit ici que :nth-child(even) est l'équivalent de :nth-child(2n) et :nth-child(odd) est l'équivalent de :nth-child(2n+1) - sachant que lorsque la valeur de l'argument est inférieure ou égale à zéro, il n'y a pas de sélection. Inférieure à zéro ? Oui, car on pourrait très bien utiliser une formule du type :nth-child(2n-1) et pour n=0 on aurait un argument égal à -1. Dans ce cas, aucun élément ne serait sélectionné.

Pour illustrer tout ceci, voici quelques exemples de sélecteurs :nth-child :

See the Pen CSS-Tricks: :nth-child by Zachary Kain (@zakkain) on CodePen.

À noter

  • :nth-child procède par itération en commençant par le début de la liste. C'est la seule différence avec :nth-last-child qui commence par la fin de la liste.
  • le sélecteur :nth-child est très proche de :nth-of-type mais avec une différence essentielle : il est moins spécifique. Dans notre premier exemple, il donnerait le même résultat parce que nous ne faisons d'itérations que sur les éléments .module, mais si nous avions un groupe plus complexe, :nth-child essaierait de cibler tous les éléments frères (siblings) et non pas les éléments frères limités au même type. C'est un point important à retenir concernant la puissance de :nth-child : il sélectionne tous les éléments frères et non pas seulement ceux qui sont spécifiés avant les deux-points :. Vous pouvez consulter l'article :nth-of-type pour plus de détails sur la différence entre les deux.

Allons plus loin sur la différence entre les deux

Prenons le HTML suivant :

//HTML
<section>
   <p>Petit</p>
   <p>Cochon</p>    <!-- Celui que je veux -->
</section>

Les deux CSS qui suivent parviendraient au même résultat :

//CSS
p:nth-child(2) { color: red; }

p:nth-of-type(2) { color: red; }

Et pourtant il y a une différence. En bon français, le sélecteur :nth-child nous dit de sélectionner un élément si :

  1. c'est un élément paragraphe
  2. c'est le second enfant d'un parent (quel qu'il soit)

Le sélecteur :nth-of-type, lui, dit ceci :

  1. sélectionner le second paragraphe enfant d'un parent (quel qu'il soit)

:nth-of-type est… comment dire… moins conditionnel.

Admettons que notre balisage soit maintenant :

//HTML
<section>
   <h1>Mots</h1>
   <p>Petit</p>
   <p>Cochon</p>    <!-- Celui que je veux -->
</section>

Ce CSS ne fonctionne plus :

//CSS
p:nth-child(2) { color: red; }

Celui-ci fonctionne encore :

//CSS
p:nth-of-type(2) { color: red; }

Quand je dis qu'il ne fonctionne plus, je veux dire que le sélecteur :nth-child sélectionne maintenant Petit au lieu de Cochon, parce que cet élément répond à la fois à la condition (1) être le deuxième enfant (de <section>) et (2) être un élément paragraphe.

Et quand je dis que le deuxième fonctionne encore, je veux dire que c'est bien Cochon qui est sélectionné, parce que c'est le deuxième paragraphe à l'intérieur de cet élément parent <section>.

Si nous ajoutions un <h2> après le <h1>, le sélecteur :nth-child ne sélectionnerait plus rien du tout parce que maintenant le deuxième enfant n'est plus un paragraphe. Le sélecteur :nth-of-type quant à lui fonctionnerait toujours.

Mon sentiment est que le sélecteur :nth-of-type est moins fragile et plus utile en règle générale, même si :nth-child est plus courant apparemment. Vous vous dites sans doute parfois “je veux sélectionner le second enfant d'un parent si c'est un paragraphe”, mais il y a des chances que vous vouliez plutôt “sélectionner le deuxième paragraphe” ou “sélectionner une ligne sur trois dans le tableau”, et ce sont là des cas où :nth-of-type (à mon avis) est un meilleur choix.

Dernière chose : je me suis rendu compte que la plupart de mes moments de “mais pourquoi ce #@/$!!! de :nth-child ne marche pas ??” venaient du fait que j'avais qualifié le sélecteur avec la balise. Donc lorsque j'utilise :nth-child je préfère en général spécifier le parent et ne pas qualifier :nth-child :

//CSS
dl :nth-child(2) {  } /* est préférable à */
dd:nth-child(2) {  } /* ceci */

Mais bien sûr, tout dépend de la situation exacte.

Quelques recettes

Il existe quelques "testeurs" de :nth-child que vous pouvez vous amuser à utiliser :

CSS-Tricks nth-child tester
Le testeur de Lea Verou
Nth-Test de Paul Maloney

Vous pouvez tester les recettes suivantes :

Sélectionner uniquement le cinquième élément :

//CSS
li:nth-child(5) {
    color: green;   
}

Sélectionner tous les éléments sauf les 5 premiers :

//CSS
li:nth-child(n+6) {
    color: green;   
}

Sélectionner seulement les 5 premiers éléments :

//CSS
li:nth-child(-n+5) {
    color: green;   
}

Sélectionner un élément sur quatre, en commençant par le premier :

//CSS
li:nth-child(4n-7) {  /* or 4n+1 */
    color: green;   
}

Exemples d’utilisation dans La Cascade :

Des sélecteurs virtuels en CSS, par Matt Mastracci
Quantity queries pour CSS, de Heydon Pickering


Autres ressources à consulter sur ce sujet :

Autres articles intéressants :

articles en français :

Le sélecteur :nth-child, vidéo par Grafikart

articles en anglais :

nthmaster, quelques exemples complexes d'utilisation des pseudo-classes structurelles :nth


Cet article est pour l'essentiel tiré de l'almanach de CSS-Tricks de Chris Coyier, avec son aimable autorisation.

Sur l'auteur : est designer, blogger, conférencier. Créateur de CSS-Tricks, de CodePen, animateur du Podcast Shop Talk, il est l'auteur avec Jeff Starr de "Digging into WordPress". Vous pouvez le retrouver sur Twitter, Google+.

NdT : CSS-Tricks est un site ressource d'une richesse exceptionnelle, axé sur CSS et le web design en général. Vous pouvez suivre son actualité sur Twitter, Facebook, YouTube, GitHub. Mélange d'articles, de vidéos, de forums, de ressources diverses (jetez un coup d'oeil à son "Almanac" ), il est très populaire sur le web anglophone.

CodePen est un site où vous pouvez tester votre code, faire des maquettes, proposer vos dernières créations et recueillir les observations de vos pairs. C'est aussi une source d'inspiration pour vos propres designs.