【JavaScript】classList の使い方完全ガイド|add・remove・toggle・contains・replace・className との違いまで解説

classList は HTML 要素のクラスを安全に操作するための API です。add / remove / toggle / contains / replace のメソッドで、他のクラスに影響を与えずに特定のクラスだけを追加・削除・切り替えできます。

この記事でわかること
・classList.add() でクラスを追加する方法
・classList.remove() でクラスを削除する方法
・classList.toggle() でクラスを切り替える方法
・classList.contains() でクラスの存在をチェックする方法
・classList.replace() でクラスを置換する方法
・複数クラスの同時操作
・className との違いと使い分け
・ダークモード・タブ・モーダルの実務パターン
スポンサーリンク

classList の全メソッド一覧

メソッド 動作 戻り値
add(cls1, cls2, …) クラスを追加(既にあれば何もしない) undefined
remove(cls1, cls2, …) クラスを削除(なければ何もしない) undefined
toggle(cls) あれば削除、なければ追加 boolean(追加=true / 削除=false)
toggle(cls, force) force=true で追加、false で削除 boolean
contains(cls) クラスがあれば true boolean
replace(old, new) old クラスを new に置換 boolean(置換できたか)
item(index) N 番目のクラス名を取得 文字列 / null
length クラスの数 数値
value 全クラスのスペース区切り文字列 文字列(= className と同等)

add(): クラスを追加する

JavaScript(add)
const el = document.querySelector(".card");

// 1 つ追加
el.classList.add("active");

// 複数同時に追加
el.classList.add("active", "highlight", "animate");

// 既に存在するクラスを追加しても重複しない(エラーにもならない)
el.classList.add("active"); // 2 回目でも問題なし
add は冪等(何回実行しても同じ結果)
既にクラスがある状態で add しても重複せず、エラーにもなりません。条件チェックなしで安全に呼び出せます。

remove(): クラスを削除する

JavaScript(remove)
// 1 つ削除
el.classList.remove("active");

// 複数同時に削除
el.classList.remove("active", "highlight", "animate");

// 存在しないクラスを削除してもエラーにならない
el.classList.remove("nonexistent"); // 何も起きない

toggle(): クラスを切り替える

JavaScript(toggle: 基本)
// あれば削除、なければ追加
el.classList.toggle("active");
// 1 回目: active がなければ追加 → true を返す
// 2 回目: active があるので削除 → false を返す

// 戻り値で追加/削除を判定
const isNowActive = el.classList.toggle("active");
console.log(isNowActive ? "追加された" : "削除された");
JavaScript(toggle + force: 条件付き切り替え)
// 第 2 引数(force)で追加/削除を制御
// force=true → 必ず追加(add と同じ)
// force=false → 必ず削除(remove と同じ)

const isLoggedIn = checkLogin();
el.classList.toggle("logged-in", isLoggedIn);    // ログイン中なら追加、そうでなければ削除
el.classList.toggle("guest", !isLoggedIn);       // ゲストなら追加

// スクロール位置に応じて切り替え
window.addEventListener("scroll", () => {
  header.classList.toggle("scrolled", window.scrollY > 100);
});
toggle(cls, force) は if + add/remove の代替
el.classList.toggle("active", condition) は以下と同じです。
if (condition) { el.classList.add("active"); } else { el.classList.remove("active"); }
toggle の方が 1 行で書けてシンプルです。

contains(): クラスの存在をチェックする

JavaScript(contains)
// クラスがあるか判定
if (el.classList.contains("active")) {
  console.log("active クラスがある");
}

// 条件分岐に使う
const isOpen = modal.classList.contains("is-open");
if (isOpen) {
  closeModal();
} else {
  openModal();
}

replace(): クラスを置換する

JavaScript(replace)
// old クラスを new クラスに置換
el.classList.replace("btn-primary", "btn-secondary");

// 戻り値で置換できたか確認
const replaced = el.classList.replace("old", "new");
console.log(replaced); // true(old があれば)/ false(old がなければ)

// テーマの切り替え
function toggleTheme() {
  const html = document.documentElement;
  if (!html.classList.replace("theme-light", "theme-dark")) {
    html.classList.replace("theme-dark", "theme-light");
  }
}

classList と className の違い

JavaScript(className の問題点)
// className は全クラスを 1 つの文字列として扱う
const el = document.querySelector(".card");
console.log(el.className); // "card active highlight"

// NG: className への代入は全クラスを上書きする
el.className = "new-class";
// → "card" と "active" と "highlight" が全て消えて "new-class" だけになる

// NG: 文字列操作でクラスを追加するのは危険
el.className += " active"; // スペースを忘れると "cardactive" になる
項目 classList className
DOMTokenList(メソッドで操作) 文字列
1 つのクラスを追加 add(“cls”)(他に影響なし) += ” cls”(スペース忘れのリスク)
1 つのクラスを削除 remove(“cls”) 正規表現で置換が必要
クラスの存在チェック contains(“cls”) includes(“cls”)(部分一致で誤判定の可能性)
全クラスの上書き classList.value = “a b c” className = “a b c”
推奨 推奨 非推奨(上書きリスク)
className は他のクラスを消してしまう
el.className = "active" は元のクラス(card / highlight 等)を全て消して “active” だけにします。classList.add("active") なら他のクラスに影響しません。常に classList を使ってください

複数要素に一括でクラスを操作する

JavaScript(querySelectorAll + classList)
// 全 .card に active を追加
document.querySelectorAll(".card").forEach(card => {
  card.classList.add("active");
});

// 全 .tab-btn から active を削除
document.querySelectorAll(".tab-btn").forEach(btn => {
  btn.classList.remove("active");
});

// 条件に応じて一括切り替え
const isDark = document.documentElement.classList.contains("dark");
document.querySelectorAll(".icon").forEach(icon => {
  icon.classList.toggle("icon-light", isDark);
  icon.classList.toggle("icon-dark", !isDark);
});

CSS アニメーションとの連携

CSS
.fade-in {
  animation: fadeIn 0.3s ease forwards;
}
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
JavaScript(クラス追加でアニメーション発火)
// クラスを追加するだけでアニメーションが発火
el.classList.add("fade-in");

// アニメーション終了後にクラスを削除(再利用のため)
el.addEventListener("animationend", () => {
  el.classList.remove("fade-in");
}, { once: true });
classList + CSS がアニメーションの基本パターン
JavaScript でスタイルを直接操作するのではなく、CSS でアニメーションを定義し、JavaScript ではクラスの追加/削除だけを行います。CSS と JS の責務が分離され、メンテナブルなコードになります。

要素のクラス一覧を取得・ループする

JavaScript(クラス一覧の取得)
const el = document.querySelector(".card");

// 全クラスをスペース区切り文字列で取得
console.log(el.classList.value); // "card active highlight"
// className と同じ
console.log(el.className);       // "card active highlight"

// クラスの数
console.log(el.classList.length); // 3

// N 番目のクラス
console.log(el.classList.item(0)); // "card"
console.log(el.classList[1]);      // "active"(ブラケットでもアクセス可能)

// for...of でループ
for (const cls of el.classList) {
  console.log(cls); // "card", "active", "highlight"
}

// 配列に変換
const classArray = [...el.classList];
console.log(classArray); // ["card", "active", "highlight"]

実務パターン集

パターン(1): ダークモードの切り替え

JavaScript
document.querySelector("#theme-toggle").addEventListener("click", () => {
  document.documentElement.classList.toggle("dark");
  // <html class="dark"> が追加/削除される
  // CSS: .dark { --bg: #1a1a2e; --text: #e0e0e0; }

  // 設定を保存
  const isDark = document.documentElement.classList.contains("dark");
  localStorage.setItem("theme", isDark ? "dark" : "light");
});

// ページ読み込み時に保存済みテーマを適用
if (localStorage.getItem("theme") === "dark") {
  document.documentElement.classList.add("dark");
}

パターン(2): タブの切り替え

JavaScript
document.querySelectorAll(".tab-btn").forEach(btn => {
  btn.addEventListener("click", () => {
    // 全タブを非アクティブに
    document.querySelectorAll(".tab-btn").forEach(b => b.classList.remove("active"));
    document.querySelectorAll(".tab-panel").forEach(p => p.classList.remove("active"));
    // クリックされたタブをアクティブに
    btn.classList.add("active");
    document.querySelector(btn.dataset.target).classList.add("active");
  });
});

パターン(3): モーダルの開閉

JavaScript
// 開く
document.querySelector("#open-modal").addEventListener("click", () => {
  document.querySelector("#modal").classList.add("is-visible");
  document.body.classList.add("modal-open"); // スクロール無効化
});

// 閉じる
document.querySelector("#close-modal").addEventListener("click", () => {
  document.querySelector("#modal").classList.remove("is-visible");
  document.body.classList.remove("modal-open");
});

パターン(4): スクロール位置でヘッダーのスタイルを変更

JavaScript
window.addEventListener("scroll", () => {
  document.querySelector(".header").classList.toggle("scrolled", window.scrollY > 50);
});
// scrollY > 50 なら "scrolled" を追加、それ以下なら削除

パターン(5): 入力バリデーション結果の表示

JavaScript
function validateInput(input) {
  const isValid = input.value.length >= 3;
  input.classList.toggle("is-valid", isValid);
  input.classList.toggle("is-invalid", !isValid);
}

document.querySelector("#name").addEventListener("input", (e) => {
  validateInput(e.target);
});

よくある質問

QclassList.add で同じクラスを 2 回追加するとどうなりますか?
A重複しません。add は冪等(idempotent)で、既にクラスがある場合は何もしません。エラーにもなりません。安心して条件チェックなしで呼び出せます。
QclassList.remove で存在しないクラスを削除するとエラーになりますか?
Aエラーになりません。存在しないクラスを remove しても何も起きないだけです。contains で事前チェックする必要はありません。
Qtoggle の戻り値は何ですか?
Atoggle はクラスが追加されたら true削除されたら false を返します。この戻り値を使って追加/削除の結果を判定できます。
QclassList と className はどちらを使うべきですか?
A常に classList を使ってください。className への代入は既存のクラスを全て上書きするリスクがあります。classList の add / remove / toggle なら他のクラスに影響しません。
QclassList にスペースを含むクラス名を指定するとどうなりますか?
AclassList.add("my class")(スペース含む)はエラー(DOMException: InvalidCharacterError)になります。クラス名にスペースを含むことはできません。複数クラスを追加するには add("cls1", "cls2") とカンマ区切りで指定してください。
QIE 11 で classList は使えますか?
Aadd / remove / toggle / contains は IE 11 で使えます。ただし add("cls1", "cls2")(複数引数)と toggle(cls, force)(第 2 引数)は IE 11 では使えません。IE 対応が必要な場合は 1 つずつ add / remove してください。

まとめ

classList の全メソッドをまとめます。

やりたいこと 方法
クラスを追加 el.classList.add(“cls1”, “cls2”)
クラスを削除 el.classList.remove(“cls1”, “cls2”)
クラスを切り替え(トグル) el.classList.toggle(“cls”)
条件付きで追加/削除 el.classList.toggle(“cls”, condition)
クラスの存在チェック el.classList.contains(“cls”)
クラスを置換 el.classList.replace(“old”, “new”)
全クラスを文字列で取得 el.classList.value / el.className
クラス一覧をループ for (const cls of el.classList) { … }
クラスを配列で取得 […el.classList]

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