【JavaScript】n番目以外の子要素を取得する方法|filter・:not(:nth-child)・children・複数除外・実務パターンまで解説

リストの特定アイテムだけスキップして残りを操作する、テーブルのヘッダー行を除いてデータ行だけ処理する、タブの選択中パネル以外を非表示にするなど、n 番目以外の子要素を取得する操作は DOM 操作でよく使います。この記事では JavaScript と CSS セレクタの両方のアプローチを解説します。

この記事でわかること
・Array.from + filter でインデックスを除外する方法
・CSS の :not(:nth-child(n)) で除外する方法
・children プロパティと for ループによる方法
・複数のインデックスをまとめて除外する方法
・先頭・末尾・特定クラス以外の要素を取得する方法
・nth-child と nth-of-type の違い
・テーブル行フィルタリング・タブ切り替えの実務パターン
スポンサーリンク

方法の比較

方法 特徴 推奨場面
Array.from + filter 柔軟・複雑な条件に対応 動的なインデックス指定・複数除外
:not(:nth-child(n)) CSS セレクタのみで完結 固定のインデックス除外
children + for ループ ライブコレクション・高速 シンプルなループ処理

Array.from + filter で除外する(推奨)

最も柔軟な方法です。children を配列に変換し、filter でインデックスを条件にして除外します。

HTML
<ul id="list">
  <li>アイテム 1</li>
  <li>アイテム 2</li>
  <li>アイテム 3</li>
  <li>アイテム 4</li>
  <li>アイテム 5</li>
</ul>
JavaScript
const list = document.getElementById("list");
const n = 2; // 除外したいインデックス(0始まり → 3番目の要素)

// children を配列に変換してフィルタリング
const filtered = Array.from(list.children).filter((_, index) => index !== n);

console.log(filtered.length); // 4(5要素中1つ除外)
filtered.forEach(el => console.log(el.textContent));
// "アイテム 1", "アイテム 2", "アイテム 4", "アイテム 5"

スプレッド構文でも同様に配列変換できます。

スプレッド構文版
const filtered = [...list.children].filter((_, i) => i !== n);
Array.from(list.children)[...list.children] は同じ結果です。好みで使い分けてください。

CSS セレクタ :not(:nth-child(n)) で除外する

CSS の :not(:nth-child(n))querySelectorAll に渡すことで、特定の位置の要素を除外して取得できます。

JavaScript
const list = document.getElementById("list");

// 3番目(:nth-childは1始まり)以外の子要素を取得
const filtered = list.querySelectorAll(":scope > li:not(:nth-child(3))");

filtered.forEach(el => console.log(el.textContent));
// "アイテム 1", "アイテム 2", "アイテム 4", "アイテム 5"
:nth-child1 始まりです。JavaScript のインデックス(0 始まり)とは 1 ずれるため、0 始まりのインデックス n を使う場合は :nth-child(${n + 1}) で変換してください。

先頭・末尾を除外する CSS セレクタ

セレクタ 除外される要素
:not(:first-child) 先頭の要素
:not(:last-child) 末尾の要素
:not(:nth-child(3)) 3 番目の要素
:not(:nth-child(odd)) 奇数番目の要素
:not(:nth-child(even)) 偶数番目の要素
先頭以外を取得
// 先頭の li 以外を取得
const withoutFirst = list.querySelectorAll(":scope > li:not(:first-child)");

// 末尾の li 以外を取得
const withoutLast = list.querySelectorAll(":scope > li:not(:last-child)");
:scope を付けることで、list の直接の子要素のみが対象になります。省略すると孫要素以降も含まれてしまいます。

children プロパティと for ループで除外する

JavaScript
const list = document.getElementById("list");
const n = 2;

for (let i = 0; i < list.children.length; i++) {
  if (i === n) continue; // n番目をスキップ
  console.log(list.children[i].textContent);
}

childrenライブコレクション(DOM の変更がリアルタイムに反映される)です。ループ中に要素を追加・削除すると挙動が変わるため注意してください。

複数のインデックスをまとめて除外する

JavaScript
const list = document.getElementById("list");

// 除外したいインデックスのセット
const excludeIndexes = new Set([0, 2, 4]);

const filtered = [...list.children].filter((_, i) => !excludeIndexes.has(i));

filtered.forEach(el => console.log(el.textContent));
// "アイテム 2", "アイテム 4"

特定のクラスを持つ要素以外を取得

JavaScript
// .active クラスを持つ要素以外を取得
const inactive = [...list.children].filter(el => !el.classList.contains("active"));

// CSS セレクタでも可能
const inactive2 = list.querySelectorAll(":scope > li:not(.active)");

特定の要素ノード以外を取得

JavaScript
const targetEl = list.children[2]; // 除外したい要素の参照

const others = [...list.children].filter(el => el !== targetEl);

:nth-child と :nth-of-type の違い

セレクタ 基準 注意点
:nth-child(n) 親要素の中で n 番目の子要素 要素の種類に関係なくカウント
:nth-of-type(n) 同じタグ種類の中で n 番目 タグ種類ごとにカウント
HTML
<div id="mixed">
  <h2>見出し</h2>
  <p>段落1</p>
  <p>段落2</p>
  <p>段落3</p>
</div>
JavaScript
// :nth-child(2) → 2番目の子要素 = <p>段落1</p>
document.querySelector("#mixed :nth-child(2)");

// :nth-of-type(2) → 2番目の <p> = <p>段落2</p>
document.querySelector("#mixed p:nth-of-type(2)");
子要素が同じタグ種類だけなら :nth-child:nth-of-type の結果は同じです。異なるタグが混在する場合に結果が変わります。

実務でよく使うパターン

テーブルのヘッダー行以外(データ行のみ)を取得する

JavaScript
const table = document.getElementById("myTable");

// tbody の全行を取得(ヘッダーは thead にあるため自然に除外)
const dataRows = table.querySelectorAll("tbody tr");

// thead がなく tr が直接並んでいる場合: 先頭以外を取得
const rows = [...table.querySelectorAll("tr")].filter((_, i) => i !== 0);

// CSS セレクタ版
const rows2 = table.querySelectorAll("tr:not(:first-child)");

タブ切り替え: 選択されたパネル以外を非表示にする

JavaScript
function switchTab(selectedIndex) {
  const panels = document.querySelectorAll(".tab-panel");

  panels.forEach((panel, i) => {
    if (i === selectedIndex) {
      panel.style.display = "block";
    } else {
      panel.style.display = "none";
    }
  });
}

switchTab(0); // 最初のパネルだけ表示

リストから選択中の要素以外のスタイルをリセットする

JavaScript
const items = document.querySelectorAll(".nav-item");

items.forEach(item => {
  item.addEventListener("click", () => {
    // 全アイテムから active を削除
    items.forEach(el => el.classList.remove("active"));
    // クリックされたアイテムだけ active を付与
    item.classList.add("active");
  });
});

ドラッグ&ドロップ: 移動中の要素以外にドロップ先を表示する

JavaScript
let draggedItem = null;

document.querySelectorAll(".sortable-item").forEach(item => {
  item.addEventListener("dragstart", () => { draggedItem = item; });

  item.addEventListener("dragover", (e) => {
    e.preventDefault();
    // 自分以外のアイテムにドロップ先スタイルを適用
    if (item !== draggedItem) {
      item.classList.add("drop-target");
    }
  });

  item.addEventListener("dragleave", () => {
    item.classList.remove("drop-target");
  });
});

関連記事

よくある質問

Q:nth-child のインデックスは 0 始まりですか?
Aいいえ、:nth-child1 始まりです。JavaScript のインデックス(0 始まり)とは 1 ずれます。JavaScript のインデックス n を CSS セレクタに変換するには :nth-child(${n + 1}) としてください。
Qchildren と childNodes の違いは?
Achildren要素ノード(HTML タグ)のみを返します。childNodes はテキストノードやコメントノードも含むすべてのノードを返します。通常は children を使います。
Q複数のインデックスをまとめて除外するには?
A除外するインデックスを Set に入れ、filter((_, i) => !set.has(i)) で一括除外できます。CSS セレクタでは :not(:nth-child(2)):not(:nth-child(4)) のように複数の :not を連結します。
Q:not(:nth-child(n)) のブラウザ対応は?
Aモダンブラウザ(Chrome・Firefox・Safari・Edge)すべてで対応しています。IE は :not のセレクタリスト(:not(:nth-child(2), :nth-child(4)))に非対応ですが、個別に :not(:nth-child(2)):not(:nth-child(4)) と連結すれば IE11 でも動作します。
QquerySelectorAll の :scope は何ですか?
A:scope は querySelectorAll の基準要素自体を指します。el.querySelectorAll(":scope > li") で el の直接の子要素の liだけを取得できます。:scope がないと孫要素以降の li も含まれます。

まとめ

n 番目以外の子要素を取得する方法を整理しました。

  • Array.from + filter: 最も柔軟。複雑な条件・複数除外・動的インデックスに対応
  • :not(:nth-child(n)): CSS セレクタで完結。固定インデックスの除外に最適
  • children + for ループ: ライブコレクション。continue でスキップ

テーブルのヘッダー除外、タブ切り替え、ナビゲーションのアクティブ管理など、「特定の要素以外を操作する」パターンは実務で頻出します。filter と :not の両方を使いこなして、効率的な DOM 操作を実現しましょう。