jQuery / Selector / :nth-child() - an+b 番目の兄弟要素を選択するセレクター
jQueryの :nth-child(an+b) は、各親の要素の兄弟を1から数え、式に合う位置を選びます。p:nth-child(2) は「2番目のp」ではなく「2番目の要素の子であり、かつp」を意味します。同じ親の2番目のpなら:nth-of-type(2)、選択集合全体の2番目なら.eq(1)と使い分けます。
1から数え、別のタグも含める
:nth-child() の公式文書はCSSの兄弟位置の規則に従います。親ごとに数え直し、異なるタグの要素も含めます。空白テキストとコメントは要素ではないため数えません。非表示でも文書構造に残る要素は位置を占めるので、見た目の順番だけでは判断できません。
h2、p、pの順ならp:nth-child(1)は空で、p:nth-child(2)が最初のpを選びます。pだけを集めてから番号を付ける処理ではありません。例のように > で直接の子に限定すると範囲が明確になります。
an+b とよく使う式
CSSの an+b の定義ではaとbは整数で、nには0、1、2などの非負整数を入れます。得られる正の位置だけが対象で、0や負の位置は選択しません。-n+3は3、2、1を作るため最初の3要素位置を意味し、末尾から数える負のインデックスではありません。
| 条件 | 要素位置 | 意味 |
|---|---|---|
| 2 | 2 | 各親の2番目の要素 |
| 2n または even | 2, 4, 6, … | 偶数位置 |
| 2n+1 または odd | 1, 3, 5, … | 奇数位置 |
| 3n+1 | 1, 4, 7, … | 1から3つおき |
| -n+3 | 1, 2, 3 | 最初の3要素位置 |
前にpを付けると、その位置にあるpだけが残ります。4番目がspanならp:nth-child(2n)には含みませんが、spanを飛ばして後のpを4番目に数え直すこともしません。
タグが混在する完全な実行例
全コードをUTF-8の nth-child-demo.html に保存し、ブラウザーで開きます。インストールは不要ですが、CDN(Content Delivery Network、コンテンツ配信ネットワーク)から公式jQueryファイルを読む接続が必要です。コードは4.0.0を使い、式・追加・リセットと比較コードは3.7.1と4.0.0で実行確認しました。
Aの要素の子はh2、p、p、span、p、Bはh2、p、p、pです。結果にpのIDを表示するので、タグ位置と照合できます。
<!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>
初期の式は2です。両方の2番目の要素は最初のpなので、a1とb1が強調されます。
a1, b1 | 2
- 2n は
a1, b1, b3 | 3です。Aの4番目はspanなのでp条件から外れます。 - 2n+1 は
a2, a3, b2 | 3です。先頭のh2はpではありません。 - 3n+1 は
b3 | 1です。Aの1・4番目はh2とspanで、Bの4番目だけがpです。 - -n+3 は
a1, a2, b1, b2 | 4です。各親の最初の3要素にあるpを選びます。 - Reset の後 Prepend notice to A を押すと、Aの先頭にdivが入ります。式2ではAの2番目がh2になり、
b1 | 1だけになります。繰り返し押しても重複しません。 - Reset は追加divだけを除去し、式を2に戻して再検索します。元の内容と
a1, b1 | 2が戻ります。
:nth-of-type() と .eq() を比較する
Reset後、開発者ツールのConsoleで次の部分コードを実行します。:nth-of-type()は同じタグの兄弟だけを数え、.eq()は選択済み集合を0から数えます。
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
1行目は各親の2番目の要素でpでもあるa1・b1、2行目は各親の2番目のpであるa2・b2です。最後はp集合全体のインデックス1にあるa2だけです。.eq()の負数は集合末尾から数える指定で、-n+3とは異なります。
動的な文書と想定外の結果を調べる
選択結果は文書変更を自動反映しません。追加前のa1・b1を保存した集合は、追加後もその要素を保持します。現在の兄弟位置が必要ならrefreshのように再検索し、以前の強調も外します。
空の結果なら0や存在しない位置を指定していないか、その位置のタグがpか、間に見出し・案内・非表示要素がないかを確認します。表ではDOM(Document Object Model、文書オブジェクトモデル)のtbodyなど中間の親も確認します。反応しない場合は、まずNetworkのjQuery読み込みとConsoleのエラーを調べます。




