JavaScript で特定のクラス名を持つ HTML 要素を取得するには、querySelectorAll または getElementsByClassName を使います。取得した要素に対してスタイルの変更、イベントの登録、表示の切り替えなど様々な操作が可能です。
本記事では、2 つの取得方法の違い、複数クラスでの絞り込み、ループ処理、classList でのクラス操作まで解説します。
この記事でわかること
・querySelectorAll / querySelector でクラス名から要素を取得する方法
・getElementsByClassName との違い(静的 vs ライブコレクション)
・複数クラスの AND / OR 条件で絞り込む方法
・取得した要素をループで処理する方法
・classList で要素のクラスを追加・削除・切り替え
・closest() で最も近い親要素を検索する方法
・タブ切り替え・アコーディオン等の実務パターン
・querySelectorAll / querySelector でクラス名から要素を取得する方法
・getElementsByClassName との違い(静的 vs ライブコレクション)
・複数クラスの AND / OR 条件で絞り込む方法
・取得した要素をループで処理する方法
・classList で要素のクラスを追加・削除・切り替え
・closest() で最も近い親要素を検索する方法
・タブ切り替え・アコーディオン等の実務パターン
querySelectorAll / querySelector(推奨)
HTML(サンプル)
<div class="card active">カード1</div> <div class="card">カード2</div> <div class="card active">カード3</div> <div class="item">アイテム</div>
JavaScript(querySelectorAll: 全要素を取得)
// .card クラスを持つ全要素を取得
const cards = document.querySelectorAll(".card");
console.log(cards.length); // 3
// .card.active の両方を持つ要素(AND 条件)
const activeCards = document.querySelectorAll(".card.active");
console.log(activeCards.length); // 2
// .card または .item(OR 条件: カンマ区切り)
const mixed = document.querySelectorAll(".card, .item");
console.log(mixed.length); // 4
JavaScript(querySelector: 最初の 1 要素だけ取得)
// 最初の .card 要素だけ取得
const firstCard = document.querySelector(".card");
console.log(firstCard.textContent); // "カード1"
// 見つからない場合は null
const notFound = document.querySelector(".nonexistent");
console.log(notFound); // null
querySelector / querySelectorAll が推奨
CSS セレクタ構文をそのまま使えるため、クラス名・ID・属性・疑似クラスなどあらゆる条件で検索できます。getElementsByClassName より柔軟で統一的に使えるため、現在の開発では querySelector 系を標準的に使います。
CSS セレクタ構文をそのまま使えるため、クラス名・ID・属性・疑似クラスなどあらゆる条件で検索できます。getElementsByClassName より柔軟で統一的に使えるため、現在の開発では querySelector 系を標準的に使います。
getElementsByClassName
JavaScript(getElementsByClassName)
// クラス名で要素を取得(ドット不要)
const cards = document.getElementsByClassName("card");
console.log(cards.length); // 3
// 複数クラスの AND 条件(スペース区切り)
const activeCards = document.getElementsByClassName("card active");
console.log(activeCards.length); // 2
querySelectorAll と getElementsByClassName の違い
| 項目 | querySelectorAll | getElementsByClassName |
|---|---|---|
| セレクタ構文 | CSS セレクタ(.class / #id / [attr] 等) | クラス名のみ |
| クラス名の指定 | ドットが必要(”.card”) | ドット不要(”card”) |
| 戻り値 | NodeList(静的: 取得時点のスナップショット) | HTMLCollection(ライブ: DOM の変化が反映) |
| forEach | 使える | 使えない(Array.from で変換が必要) |
| OR 条件 | “.card, .item”(カンマ区切り) | 不可 |
| 推奨 | 推奨 | 後方互換。新規コードでは querySelector を推奨 |
ライブコレクション(HTMLCollection)の罠
getElementsByClassName が返す HTMLCollection はライブです。ループ中に要素のクラスを変更すると、コレクションの中身がリアルタイムで変わり、意図しないスキップや無限ループの原因になります。querySelectorAll(静的 NodeList)を使えばこの問題は起きません。JavaScript(ライブコレクションの罠)
// NG: ライブコレクションでループ中にクラスを変更
const items = document.getElementsByClassName("old");
for (let i = 0; i < items.length; i++) {
items[i].classList.replace("old", "new");
// クラスが変わると items から消える → 次の要素がスキップされる!
}
// OK: querySelectorAll なら安全
const items2 = document.querySelectorAll(".old");
items2.forEach(el => {
el.classList.replace("old", "new"); // 安全(静的コレクション)
});
取得した要素をループで処理する
JavaScript(ループの書き方)
// forEach(最もシンプル: NodeList で使用可能)
document.querySelectorAll(".card").forEach(card => {
card.style.border = "1px solid blue";
});
// for...of
for (const card of document.querySelectorAll(".card")) {
card.style.border = "1px solid blue";
}
// 通常の for ループ(インデックスが必要な場合)
const cards = document.querySelectorAll(".card");
for (let i = 0; i < cards.length; i++) {
cards[i].style.border = "1px solid blue";
}
// getElementsByClassName を forEach で使う場合
const collection = document.getElementsByClassName("card");
Array.from(collection).forEach(card => {
card.style.border = "1px solid blue";
});
| ループ方法 | NodeList | HTMLCollection | 推奨度 |
|---|---|---|---|
| forEach | 直接使用可 | Array.from() が必要 | 高(シンプル) |
| for…of | 使用可 | 使用可 | 高 |
| for (i) | 使用可 | 使用可 | 中(インデックスが必要な場合) |
| […spread] | 使用可 | 使用可 | 高(配列メソッドと組み合わせ) |
classList でクラスを操作する
JavaScript(classList のメソッド)
const el = document.querySelector(".card");
// クラスの追加
el.classList.add("active");
el.classList.add("highlight", "animate"); // 複数同時追加
// クラスの削除
el.classList.remove("active");
// クラスの切り替え(あれば削除、なければ追加)
el.classList.toggle("active");
// 条件付き切り替え(true=追加 / false=削除)
el.classList.toggle("active", isLoggedIn);
// クラスの存在チェック
if (el.classList.contains("active")) {
console.log("active クラスがある");
}
// クラスの置換
el.classList.replace("old-class", "new-class");
| メソッド | 動作 |
|---|---|
| add(cls) | クラスを追加(既にあれば何もしない) |
| remove(cls) | クラスを削除(なければ何もしない) |
| toggle(cls) | あれば削除、なければ追加 |
| toggle(cls, force) | force=true で追加、false で削除 |
| contains(cls) | クラスがあれば true |
| replace(old, new) | クラスを置換 |
className の直接代入は避ける
el.className = "new-class" は既存のクラスを全て上書きします。classList.add() / classList.remove() なら他のクラスに影響せず安全にクラスを操作できます。特定の親要素内から検索する
JavaScript(スコープを絞った検索)
// 特定の親要素内からのみ検索
const sidebar = document.querySelector(".sidebar");
const sidebarLinks = sidebar.querySelectorAll(".nav-link");
// .sidebar 内の .nav-link だけ取得(ページ全体は検索しない)
// CSS 子孫セレクタと同等
const headerLinks = document.querySelectorAll(".header .nav-link");
closest() で最も近い祖先要素を検索する
JavaScript(closest: 自分自身を含む最も近い祖先)
// クリックされた要素から最も近い .card を探す
document.addEventListener("click", (e) => {
const card = e.target.closest(".card");
if (card) {
console.log("カードがクリックされた:", card.textContent);
}
});
// イベントデリゲーションとの組み合わせ
document.querySelector(".card-list").addEventListener("click", (e) => {
const deleteBtn = e.target.closest(".delete-btn");
if (deleteBtn) {
const card = deleteBtn.closest(".card");
card.remove();
}
});
closest() はイベントデリゲーションの必須テクニック
子要素がクリックされたときに親要素(.card)を特定するのに使います。
子要素がクリックされたときに親要素(.card)を特定するのに使います。
closest() は自分自身を含む祖先を上方向に検索し、一致する最初の要素を返します。見つからない場合は null を返します。matches() で要素がセレクタに一致するかチェック
JavaScript(matches)
const el = document.querySelector(".card");
// 要素が特定のセレクタに一致するか
console.log(el.matches(".card")); // true
console.log(el.matches(".card.active")); // true / false
console.log(el.matches(".item")); // false
// イベントハンドラ内で使う
document.addEventListener("click", (e) => {
if (e.target.matches(".delete-btn")) {
handleDelete(e.target);
}
});
実務パターン集
パターン(1): タブ切り替え
JavaScript
document.querySelectorAll(".tab-btn").forEach(btn => {
btn.addEventListener("click", () => {
// 全タブの active を解除
document.querySelectorAll(".tab-btn").forEach(b => b.classList.remove("active"));
document.querySelectorAll(".tab-content").forEach(c => c.classList.remove("active"));
// クリックされたタブと対応コンテンツに active を付与
btn.classList.add("active");
const target = document.querySelector(btn.dataset.target);
if (target) target.classList.add("active");
});
});
パターン(2): 全要素の表示/非表示切り替え
JavaScript
// .notification クラスの全要素を非表示にする
function hideAll(className) {
document.querySelectorAll(`.${className}`).forEach(el => {
el.style.display = "none";
});
}
// .notification クラスの全要素を表示する
function showAll(className) {
document.querySelectorAll(`.${className}`).forEach(el => {
el.style.display = "";
});
}
パターン(3): 条件に合う要素だけフィルタ
JavaScript
// data-category 属性で絞り込み
function filterByCategory(category) {
document.querySelectorAll(".product").forEach(product => {
if (category === "all" || product.dataset.category === category) {
product.style.display = "";
} else {
product.style.display = "none";
}
});
}
パターン(4): 配列メソッドとの組み合わせ
JavaScript
// NodeList を配列に変換して filter / map を使う
const activeItems = [...document.querySelectorAll(".item")]
.filter(el => el.classList.contains("active"))
.map(el => el.textContent);
console.log(activeItems); // ["アイテム1", "アイテム3"]
よくある質問
QquerySelectorAll と getElementsByClassName はどちらを使うべきですか?
AquerySelectorAll を推奨します。CSS セレクタをそのまま使えて柔軟性が高く、返される NodeList が静的なのでループ中のクラス変更も安全です。getElementsByClassName は後方互換のためにまだ使えますが、新規コードでは querySelector 系に統一するのがベストです。
QquerySelectorAll の戻り値に forEach が使えません
A
querySelectorAll の NodeList は forEach に対応しています(IE 11 以外)。getElementsByClassName の HTMLCollection は forEach に対応していないため、Array.from(collection).forEach(...) で変換してください。Qクラス名の先頭のドット(.)を忘れてエラーになります
A
querySelectorAll は CSS セレクタ構文なのでドット(.)が必須です。getElementsByClassName はクラス名だけを渡すのでドット不要です。querySelectorAll(".card") / getElementsByClassName("card")Q要素が見つからない場合はどうなりますか?
A
querySelector は null を返します。querySelectorAll は空の NodeList(length=0)を返します。null チェックを忘れると TypeError: Cannot read properties of null が発生するため、if (el) { ... } で確認してください。Qclosest() は IE で使えますか?
AIE 11 では
closest() は使えません。ポリフィルを使うか、ループで parentElement を辿る方法で代替できます。ただし IE は 2022 年にサポート終了しているため、現在の開発では考慮不要なケースがほとんどです。Q動的に追加された要素にもイベントを付けたいです
A
querySelectorAll は実行時点の要素しか取得できません。後から追加される要素にも対応するにはイベントデリゲーションを使います。親要素にイベントを登録し、e.target.closest(".target-class") で対象を判定してください。まとめ
クラス名による要素取得の要点をまとめます。
| やりたいこと | 方法 |
|---|---|
| クラスで全要素を取得(推奨) | document.querySelectorAll(“.class-name”) |
| クラスで最初の 1 要素を取得 | document.querySelector(“.class-name”) |
| 複数クラスの AND 条件 | querySelectorAll(“.class1.class2”) |
| 複数クラスの OR 条件 | querySelectorAll(“.class1, .class2”) |
| 親要素内から検索 | parent.querySelectorAll(“.class-name”) |
| 最も近い祖先要素を検索 | element.closest(“.class-name”) |
| クラスの追加 | element.classList.add(“class-name”) |
| クラスの削除 | element.classList.remove(“class-name”) |
| クラスの切り替え | element.classList.toggle(“class-name”) |
| クラスの存在チェック | element.classList.contains(“class-name”) |

