classList.contains とは何か
classList.contains は、要素に指定した「CSS クラスが付いているか」を真偽値で判定するメソッドです。返り値は true/false のみで、クラス名の完全一致で判断します。ここが重要です:部分一致ではなく“正確なクラス名”に対して安全にチェックできるため、状態分岐やクリック処理の条件判定に最適です。
基本の使い方(状態判定の最短ルート)
付いているかどうかをチェックする
<div id="box" class="card is-active"></div>
<script>
const box = document.getElementById("box");
console.log(box.classList.contains("is-active")); // true
console.log(box.classList.contains("active")); // false(完全一致ではないため)
</script>
HTMLここが重要です:contains は「完全一致」だけに反応します。似た名前(active/activated)や部分文字列(light が highlight に含まれる等)では誤判定しません。
判定結果で安全に分岐する
<button id="save" class="btn is-disabled">保存</button>
<script>
const save = document.getElementById("save");
if (save.classList.contains("is-disabled")) {
console.warn("無効なのでクリックを無視");
} else {
console.log("保存を実行");
}
</script>
HTMLここが重要です:UI の“今の状態”をクラスで表しておけば、contains で直感的に分岐できます。クラスが単一情報源になります。
className.includes との違い(安全性・正確さの深掘り)
文字列検索は危険、contains は厳密
<div id="box" class="card highlight"></div>
<script>
const box = document.getElementById("box");
// 悪い例:部分一致の誤判定
console.log(box.className.includes("light")); // true(highlight に含まれるため誤判定)
// 正しい例:完全一致
console.log(box.classList.contains("light")); // false(別クラスとして存在しない)
</script>
HTMLここが重要です:className.includes は“生の文字列”検索のため、部分一致の罠があります。状態判定には必ず classList.contains を使い、クラス名ははっきり区別できる命名にします。
実践パターン(クリック処理、排他制御、ARIA 連動)
クリックの発生源に応じて処理を分ける
<ul id="menu">
<li><button class="item">A</button></li>
<li><button class="item is-disabled">B</button></li>
</ul>
<script>
const menu = document.getElementById("menu");
menu.addEventListener("click", (e) => {
const t = e.target;
if (!(t instanceof Element)) return;
const btn = t.closest("button.item");
if (!btn) return;
if (btn.classList.contains("is-disabled")) return; // 無効は無視
console.log("クリック処理を実行");
});
</script>
HTMLここが重要です:contains で「対象の状態」を一瞬で判定し、誤動作を防ぎます。イベント委譲と組み合わせて、後から追加された要素にも効きます。
排他的なクラス集合の安全な更新
<div id="toast" class="toast type-info is-hidden"></div>
<script>
const toast = document.getElementById("toast");
function show(type) {
const visible = !toast.classList.contains("is-hidden"); // 今の表示状態
if (!visible) toast.classList.remove("is-hidden");
["type-info", "type-success", "type-error"].forEach(c => {
if (toast.classList.contains(c)) toast.classList.remove(c);
});
toast.classList.add(`type-${type}`);
}
show("success");
</script>
HTMLここが重要です:contains → remove の順で「今付いているものだけを掃除」すれば、不要な操作を減らしつつ、常に正しい集合へ整えられます。
ARIA と連動してアクセシビリティを保つ
<button id="toggle" aria-pressed="false" class="btn"></button>
<script>
const btn = document.getElementById("toggle");
btn.addEventListener("click", () => {
const nowOn = btn.classList.toggle("is-on");
btn.setAttribute("aria-pressed", String(nowOn));
// 確認:状態の真偽はクラスで常に取得できる
if (btn.classList.contains("is-on")) {
btn.textContent = "ON";
} else {
btn.textContent = "OFF";
}
});
</script>
HTMLここが重要です:視覚の状態(クラス)と ARIA の状態を contains の判定で同期すると、見た目とアクセシビリティが噛み合います。
設計のコツ(命名、単一情報源、ヘルパー化)
状態クラスは is-* に統一する
is-active、is-open、is-hidden のような“状態”を示す接頭辞に統一すると、contains の対象が明確になります。ここが重要です:JS は is-* クラスだけを触る契約にすると、テーマ(theme-)や種類(type-)と衝突しません。
単一情報源としてのクラス
表示・挙動・ARIA の判定を同じクラス(例:is-open)に揃えると、contains で一貫して分岐できます。ここが重要です:状態は一箇所で持つ。条件が多いほどこのメリットが効きます。
ヘルパー関数で判定を標準化する
const ACTIVE = "is-active";
function isActive(el) {
return el.classList.contains(ACTIVE);
}
JavaScriptここが重要です:クラス名を定数化し、判定を関数に寄せると誤字・曖昧な比較を防げます。大きなコードベースほど効果的です。
よくある落とし穴と回避策(存在・タイミング・曖昧名)
要素が無いときの判定
const el = document.querySelector("#target");
if (!el) return; // null ガード
const on = el.classList.contains("is-on");
JavaScriptここが重要です:DOM 構築前は null。defer で読み込むか、DOMContentLoaded 後に実行し、常に存在チェックを入れます。
似た名前・部分一致の混乱
active と activated、light と highlight のような似た名前は混乱の元です。ここが重要です:完全一致で判定する前提で、クラス命名をはっきり区別(is-active / is-activated)します。
取得と更新の整合性
contains で見た状態と、次の操作(add/remove/toggle)が一致しないとバグになります。ここが重要です:判定と更新を“同じフレーム”内で行い、外部非同期に影響されないように設計します。
実践例:選択リストのトグルと正確な判定
<ul id="list">
<li class="item">A</li>
<li class="item">B</li>
<li class="item">C</li>
</ul>
<script>
const list = document.getElementById("list");
list.addEventListener("click", (e) => {
const t = e.target;
if (!(t instanceof Element)) return;
const li = t.closest(".item");
if (!li) return;
const selected = li.classList.contains("is-selected");
if (selected) {
li.classList.remove("is-selected"); // 既に選択 → 解除
} else {
li.classList.add("is-selected"); // 未選択 → 付与
}
});
</script>
HTMLここが重要です:contains で現状を判定し、add/remove を分ける最も分かりやすい形です。toggle を使ってもよいですが、業務要件で“選択解除時に追加処理をしたい”などの分岐がある場合、contains ベースの明示分岐は読みやすさが勝ります。
まとめ
classList.contains は、要素にクラスが付いているかを「完全一致」で安全に判定するための基本メソッドです。文字列検索の罠(部分一致)を避け、状態分岐・クリック処理・排他制御・ARIA 連動の判断軸として使えます。命名は is-* に統一して単一情報源を作り、定数やヘルパーで判定を標準化する。存在チェックと実行タイミングを守れば、初心者でも意図通りで壊れにくい UI 状態管理が書けます。
