jQuery / Sélecteur / :nth-child() - Sélectionner les positions an+b

Dans jQuery, :nth-child(an+b) sélectionne les éléments frères dont la position correspond à une formule, en comptant depuis un pour chaque parent. p:nth-child(2) signifie un p qui est le deuxième enfant élément, et non le deuxième p. Utilisez :nth-of-type(2) pour le deuxième frère p, ou .eq(1) pour le deuxième élément d'un ensemble déjà sélectionné.

Compter depuis un, toutes balises comprises

La documentation de :nth-child() suit les règles CSS de position parmi les frères. Le comptage recommence pour chaque parent et inclut les autres balises. Les espaces textuels et commentaires ne sont pas des éléments. Un élément masqué conserve sa position tant qu'il reste dans le document : l'ordre visible ne suffit pas.

Avec h2, p, p dans cet ordre, p:nth-child(1) est vide et p:nth-child(2) retient le premier p. Les p ne sont pas rassemblés avant d'être numérotés. Limitez la portée aux enfants directs avec >, comme dans l'exemple.

Lire an+b et les formules courantes

Dans la définition CSS de an+b, a et b sont des entiers, et n prend les valeurs entières non négatives 0, 1, 2, etc. Seules les positions positives obtenues correspondent. Zéro et les positions négatives ne sélectionnent rien. -n+3 donne 3, 2, 1, soit les trois premières positions ; ce n'est pas un comptage depuis la fin.

Condition Positions Sens
2 2 Deuxième élément de chaque parent
2n ou even 2, 4, 6, … Positions paires
2n+1 ou odd 1, 3, 5, … Positions impaires
3n+1 1, 4, 7, … Une position sur trois depuis un
-n+3 1, 2, 3 Trois premières positions

Placer p devant la condition ne conserve que les p à ces positions. Si le quatrième enfant est span, p:nth-child(2n) l'exclut, sans le sauter pour renuméroter un p ultérieur comme quatrième.

Exemple complet avec des balises mélangées

Enregistrez tout le code en UTF-8 dans nth-child-demo.html et ouvrez-le dans un navigateur. Aucune installation n'est nécessaire, mais le chargement du fichier officiel jQuery par son réseau de diffusion de contenu, ou CDN, exige internet. Le code utilise 4.0.0 ; formules, insertion, réinitialisation et comparaison ont été exécutées avec 3.7.1 et 4.0.0.

A contient h2, p, p, span, p ; B contient h2, p, p, p. Le résultat affiche les identifiants des p pour les comparer aux positions des balises.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Sibling positions and formulas</title>
  <style>
    body { font: 16px/1.6 sans-serif; margin: 24px; }
    .group { border: 1px solid #aaa; padding: 12px; margin: 12px 0; }
    .group > * { display: block; margin: 6px 0; padding: 6px; }
    .group > .marked { background: #fff0b3; outline: 2px solid #b56b00; }
    button, select { padding: 8px; margin: 4px; }
  </style>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
</head>
<body>
  <h1>Sibling positions and formulas</h1>
  <div id="groups">
    <section class="group" id="group-a">
      <h2>A heading</h2>
      <p id="a1">A paragraph 1</p>
      <p id="a2">A paragraph 2</p>
      <span>A note</span>
      <p id="a3">A paragraph 3</p>
    </section>
    <section class="group" id="group-b">
      <h2>B heading</h2>
      <p id="b1">B paragraph 1</p>
      <p id="b2">B paragraph 2</p>
      <p id="b3">B paragraph 3</p>
    </section>
  </div>
  <label for="rule">Formula:</label>
  <select id="rule">
    <option value="2">2</option>
    <option value="2n">2n (even)</option>
    <option value="2n+1">2n+1 (odd)</option>
    <option value="3n+1">3n+1</option>
    <option value="-n+3">-n+3</option>
  </select>
  <button type="button" id="prepend">Prepend notice to A</button>
  <button type="button" id="reset">Reset</button>
  <output id="result" aria-live="polite"></output>
  <script>
    $(function () {
      function refresh() {
        $("#groups > .group > p").removeClass("marked");
        const rule = $("#rule").val();
        const $chosen = $("#groups > .group > p:nth-child(" + rule + ")");
        $chosen.addClass("marked");
        const ids = $chosen.map((_, item) => item.id).get().join(", ");
        $("#result").text(`${ids || "none"} | ${$chosen.length}`);
      }
      $("#rule").on("change", refresh);
      $("#prepend").on("click", function () {
        if (!$("#extra").length) {
          $("#group-a").prepend('<div id="extra">Notice</div>');
        }
        refresh();
      });
      $("#reset").on("click", function () {
        $("#extra").remove();
        $("#rule").val("2");
        refresh();
      });
      refresh();
    });
  </script>
</body>
</html>

La formule initiale est 2. Le deuxième élément de chaque groupe est son premier p : a1 et b1 sont surlignés.

a1, b1 | 2
  1. 2n donne a1, b1, b3 | 3. Le quatrième élément de A est span et ne satisfait pas p.
  2. 2n+1 donne a2, a3, b2 | 3. Le h2 en première position est exclu.
  3. 3n+1 donne b3 | 1. Les positions 1 et 4 de A sont h2 et span ; seule la quatrième de B est p.
  4. -n+3 donne a1, a2, b1, b2 | 4 : les p parmi les trois premiers éléments de chaque parent.
  5. Appuyez sur Reset, puis Prepend notice to A. Un div ajouté au début fait passer h2 à la deuxième place dans A. La formule 2 ne laisse que b1 | 1. Les clics répétés ne créent pas de doublons.
  6. Reset enlève seulement le div ajouté, rétablit la formule 2 et refait la sélection. Le contenu original et a1, b1 | 2 reviennent.

Comparer :nth-of-type() et .eq()

Après Reset, exécutez ce fragment dans la console de développement. :nth-of-type() compte les frères de même balise, tandis que .eq() compte l'ensemble sélectionné depuis zéro.

const ids = $set => $set.map((_, item) => item.id).get().join(", ");
console.log(ids($("#groups > .group > p:nth-child(2)")));
console.log(ids($("#groups > .group > p:nth-of-type(2)")));
console.log(ids($("#groups > .group > p").eq(1)));
a1, b1
a2, b2
a2

La première ligne renvoie a1 et b1, deuxièmes enfants éléments qui sont des p. La deuxième renvoie a2 et b2, deuxièmes p de chaque parent. La dernière ne renvoie que a2, à l'indice 1 de l'ensemble des p. Un indice négatif dans .eq() compte depuis la fin de cet ensemble et diffère de -n+3.

Document dynamique et résultats inattendus

Une sélection ne reflète pas automatiquement les modifications du document. Un ensemble contenant a1 et b1 avant l'insertion garde ces éléments après celle-ci. Refaites la requête comme refresh et effacez les anciennes marques pour suivre les positions actuelles.

Si le résultat est vide, vérifiez les positions nulles ou inexistantes, la balise réelle et les titres, notices ou éléments masqués intercalés. Pour un tableau, inspectez aussi les parents intermédiaires tels que tbody dans le modèle objet du document, DOM. Sans réaction, vérifiez d'abord le chargement jQuery dans Network et les erreurs dans Console.