【JavaScript】querySelector / querySelectorAll の使い方|CSS セレクタ・NodeList・ループ・パフォーマンスまで解説

【JavaScript】querySelector / querySelectorAll の使い方|CSS セレクタ・NodeList・ループ・パフォーマンスまで解説 JavaScript

querySelectorquerySelectorAll は、CSS セレクタを使って HTML 要素を取得する JavaScript のメソッドです。ID・クラス・属性・疑似クラスなど、CSS で書けるあらゆるセレクタで要素を検索できるため、DOM 操作の最も汎用的な方法として広く使われています。

この記事でわかること
・querySelector(1 要素)と querySelectorAll(全要素)の違い
・CSS セレクタの書き方一覧(ID / クラス / 属性 / 疑似クラス / 複合)
・NodeList の特性と forEach / for…of でのループ
・getElementById 等との比較と使い分け
・スコープ付き検索(親要素内から検索)
・closest() / matches() との組み合わせ
・パフォーマンスの注意点
スポンサーリンク

querySelector と querySelectorAll の基本

メソッド 戻り値 該当なし
querySelector(selector) 最初に一致した 1 要素(Element) null
querySelectorAll(selector) 一致した 全要素(NodeList) 空の NodeList(length=0)
JavaScript(基本の使い方)
// querySelector: 最初の 1 要素を取得
const header = document.querySelector("h1");
const firstCard = document.querySelector(".card");
const mainTitle = document.querySelector("#main-title");

// querySelectorAll: 一致する全要素を取得
const allCards = document.querySelectorAll(".card");
console.log(allCards.length); // 一致した要素数

// 見つからない場合
const notFound = document.querySelector(".nonexistent"); // null
const empty = document.querySelectorAll(".nonexistent");  // NodeList [] (length=0)

使える CSS セレクタの一覧

セレクタ 意味
#id ID querySelector(“#main-title”)
.class クラス querySelectorAll(“.card”)
tag タグ名 querySelectorAll(“p”)
.class1.class2 複数クラス AND querySelector(“.card.active”)
.class1, .class2 複数セレクタ OR querySelectorAll(“.card, .item”)
parent child 子孫 querySelectorAll(“.sidebar a”)
parent > child 直接の子 querySelectorAll(“ul > li”)
el + el 隣接兄弟 querySelector(“h2 + p”)
el ~ el 後続兄弟 querySelectorAll(“h2 ~ p”)
[attr] 属性あり querySelectorAll(“[data-id]”)
[attr=”val”] 属性値一致 querySelector(‘[type=”email”]’)
[attr^=”val”] 属性値が val で始まる querySelectorAll(‘[href^=”https”]’)
[attr$=”val”] 属性値が val で終わる querySelectorAll(‘[src$=”.png”]’)
[attr*=”val”] 属性値が val を含む querySelectorAll(‘[class*=”btn”]’)
:first-child 最初の子要素 querySelector(“li:first-child”)
:last-child 最後の子要素 querySelector(“li:last-child”)
:nth-child(n) N 番目の子要素 querySelector(“tr:nth-child(2)”)
:not(selector) 否定 querySelectorAll(“input:not([type=hidden])”)
:checked チェック済み querySelectorAll(“input:checked”)
:disabled 無効化 querySelectorAll(“input:disabled”)
CSS で書けるセレクタはすべて使える
querySelector / querySelectorAll は CSS のセレクタ仕様に準拠しています。CSS で要素を指定できるなら JavaScript でもそのまま使えます。疑似要素(::before / ::after)は DOM に存在しないため取得できません。
JavaScript(実践的なセレクタ例)
// data 属性で取得
const user = document.querySelector('[data-user-id="42"]');

// フォームの特定 input
const emailInput = document.querySelector('input[type="email"]');

// チェック済みのラジオボタン
const checked = document.querySelector('input[name="plan"]:checked');

// hidden 以外の全 input
const visibleInputs = document.querySelectorAll('input:not([type="hidden"])');

// テーブルの偶数行
const evenRows = document.querySelectorAll("tr:nth-child(even)");

NodeList の特性とループ

JavaScript(NodeList のループ方法)
const cards = document.querySelectorAll(".card");

// forEach(最もシンプル)
cards.forEach(card => {
  card.classList.add("active");
});

// for...of
for (const card of cards) {
  card.classList.add("active");
}

// インデックス付きアクセス
console.log(cards[0]);        // 最初の要素
console.log(cards.length);    // 要素数

// 配列メソッド(filter / map 等)を使いたい場合
const activeCards = [...cards].filter(c => c.classList.contains("active"));
// または Array.from(cards).filter(...)
NodeList の特性 内容
静的(スナップショット) 取得時点の要素。DOM の変更は反映されない
forEach 対応 IE 11 以外は直接使える
インデックスアクセス cards[0] / cards[1] で個別アクセス可能
length 要素数を取得可能
filter / map 等 直接は使えない。スプレッド構文 […cards] で配列に変換して使う
querySelectorAll の NodeList は「静的」
querySelectorAll が返す NodeList は取得時点のスナップショットです。後から DOM に要素を追加・削除しても NodeList の中身は変わりません。これは getElementsByClassName(ライブ)とは異なる動作です。

スコープ付き検索(親要素内から検索)

JavaScript(親要素を起点に検索)
// document 全体ではなく、特定の親要素内から検索
const sidebar = document.querySelector(".sidebar");
const sidebarLinks = sidebar.querySelectorAll("a");
// .sidebar 内の a 要素だけ取得

// CSS の子孫セレクタでも同じ結果
const sidebarLinks2 = document.querySelectorAll(".sidebar a");

// 注意: sidebar が null の場合 → エラー
// sidebar?.querySelectorAll("a") で安全に
element.querySelector はその要素内だけを検索
document.querySelector はページ全体を検索しますが、element.querySelector はその要素の子孫だけを検索します。検索範囲を絞ることでパフォーマンスも向上します。

getElementById 等との比較

メソッド セレクタ 戻り値 速度 推奨
querySelector CSS セレクタ全般 Element / null 普通 推奨(汎用)
querySelectorAll CSS セレクタ全般 NodeList(静的) 普通 推奨(汎用)
getElementById ID のみ Element / null 最速 ID のみなら可
getElementsByClassName クラスのみ HTMLCollection(ライブ) 速い 非推奨(ライブの罠)
getElementsByTagName タグのみ HTMLCollection(ライブ) 速い 非推奨
querySelector 系に統一するのが最もシンプル
getElementById は僅かに速いですが、実測で体感できる差はありません。querySelector 系は CSS セレクタの知識がそのまま使え、ID / クラス / 属性 / 複合条件をすべて 1 つの API で扱えます。チーム内で統一するなら querySelector 系に統一するのが合理的です。

closest() / matches() との組み合わせ

JavaScript(closest: 最も近い祖先を検索)
// クリックされた要素から最も近い .card を探す
document.addEventListener("click", (e) => {
  const card = e.target.closest(".card");
  if (card) {
    console.log("カードがクリックされた");
  }
});
JavaScript(matches: セレクタに一致するか判定)
// 要素が特定のセレクタに一致するか
const el = document.querySelector(".card");
console.log(el.matches(".card.active")); // true / false

// イベントデリゲーションで活用
document.addEventListener("click", (e) => {
  if (e.target.matches(".delete-btn")) {
    e.target.closest(".card").remove();
  }
});
メソッド 方向 用途
querySelector 下方向(子孫を検索) 子要素の中から条件に合う要素を取得
closest 上方向(祖先を検索) クリックされた要素の親を辿って特定の要素を見つける
matches 自分自身 要素がセレクタに一致するか判定(boolean)

実務パターン集

パターン(1): フォームの全入力値を取得

JavaScript
const form = document.querySelector("#myForm");
const inputs = form.querySelectorAll("input, select, textarea");

const formData = {};
inputs.forEach(input => {
  if (input.name) {
    formData[input.name] = input.value;
  }
});
console.log(formData);

パターン(2): 外部リンクに target=”_blank” を自動付与

JavaScript
document.querySelectorAll('a[href^="http"]').forEach(link => {
  if (!link.hostname.includes(location.hostname)) {
    link.setAttribute("target", "_blank");
    link.setAttribute("rel", "noopener noreferrer");
  }
});

パターン(3): テーブルの偶数行にクラスを付与

JavaScript
document.querySelectorAll("table.striped tr:nth-child(even)").forEach(row => {
  row.classList.add("bg-gray");
});

パターン(4): チェック済みチェックボックスの値を取得

JavaScript
const checked = document.querySelectorAll('input[name="categories"]:checked');
const values = [...checked].map(cb => cb.value);
console.log(values); // ["food", "drink"]

パターン(5): イベントデリゲーション

JavaScript
// 親要素 1 つにイベントを登録し、子要素をセレクタで判定
document.querySelector(".todo-list").addEventListener("click", (e) => {
  const deleteBtn = e.target.closest(".delete-btn");
  if (deleteBtn) {
    deleteBtn.closest(".todo-item").remove();
  }
});

パフォーマンスの注意点

注意点 対策
ループ内で毎回 querySelector を呼ぶ 変数にキャッシュしてループ外で 1 回だけ取得
document 全体を検索する 親要素を起点に検索範囲を絞る
複雑すぎるセレクタ セレクタを分割して段階的に検索
JavaScript(キャッシュの例)
// NG: ループ内で毎回検索
// for (...) { document.querySelector(".header").style.color = "red"; }

// OK: 変数にキャッシュ
const header = document.querySelector(".header");
if (header) header.style.color = "red";

よくある質問

QquerySelector と querySelectorAll の違いは?
AquerySelector は最初に一致した 1 要素を返します(見つからなければ null)。querySelectorAll は一致した全要素の NodeList を返します(見つからなければ空の NodeList)。
QquerySelector は getElementById より遅いですか?
A技術的にはわずかに遅いですが、実測で体感できる差はありません。getElementById は内部でハッシュマップを使うため最速ですが、querySelector の汎用性の方がメリットが大きいです。
QquerySelectorAll の結果に filter や map を使いたいです
ANodeList には filter / map がないため、スプレッド構文で配列に変換してください。
const arr = [...document.querySelectorAll(".card")];
const active = arr.filter(c => c.classList.contains("active"));
Q疑似要素(::before / ::after)を取得できますか?
Aできません。疑似要素は DOM に実体がないため、querySelector では取得できません。疑似要素のスタイルを取得するには getComputedStyle(el, "::before") を使います。
Qセレクタに特殊文字(: / .)を含む ID がある場合は?
ACSS セレクタの特殊文字はバックスラッシュでエスケープします。
querySelector("#my\\:id")(JS の文字列でバックスラッシュ 2 つ)
または CSS.escape() を使います: querySelector("#" + CSS.escape("my:id"))
QquerySelector は Shadow DOM 内の要素を取得できますか?
Aデフォルトでは取得できません。Shadow DOM 内の要素を取得するには、Shadow Root を経由してアクセスします。
el.shadowRoot.querySelector(".inner-element")

まとめ

querySelector / querySelectorAll の要点をまとめます。

やりたいこと 方法
最初の 1 要素を取得 document.querySelector(“selector”)
全要素を取得 document.querySelectorAll(“selector”)
ID で取得 querySelector(“#myId”)
クラスで取得 querySelectorAll(“.myClass”)
属性で取得 querySelector(‘[data-id=”42″]’)
複合条件(AND) querySelector(“.card.active”)
複合条件(OR) querySelectorAll(“.card, .item”)
親要素内から検索 parent.querySelectorAll(“selector”)
祖先要素を検索 element.closest(“selector”)
セレクタ一致判定 element.matches(“selector”)
NodeList をループ forEach / for…of / […nodeList].filter()

ID での取得は「ID で要素を取得する方法」、クラスでの取得は「クラス名で要素を取得する方法」も併せて参照してください。