JavaScript で要素の見た目を切り替えたいとき、よく使うのが「クラスの付け外し」です。この記事では、要素のクラスを安全かつ手軽に操作できる element.classList の使い方を、add() / remove() / toggle() / contains() / replace() の各メソッドに沿って解説します。従来の className への文字列代入との違いや、メニューの開閉・テーマ切替といった実践例、クラスがうまく切り替わらないときの確認ポイントまで取り上げるので、初めて DOM 操作に触れる方でも迷わず使えるようになります。
目次
classList とは
element.classList は、HTML 要素が持つ class 属性を「クラス名の集まり」として扱うためのプロパティです。返ってくるのは DOMTokenList というオブジェクトで、ここに用意された専用メソッドを呼ぶだけで、クラスの追加・削除・切り替え・存在確認などをまとめて行えます。
CSS であらかじめ .is-active のようなクラスにスタイルを定義しておき、JavaScript ではそのクラスを付けたり外したりするだけ、という形にすると、見た目の制御と処理の役割をきれいに分けられます。要素ごとに style を直接書き換えるよりも管理しやすく、現在の DOM 操作では基本となる考え方です。
className との違い
クラスを操作する古い方法として、element.className に文字列を代入するやり方があります。ただし className は class 属性の「文字列まるごと」を表すため、代入すると既存のクラスがすべて上書きされてしまいます。
// 例: <div class="card is-active"> という要素があるとする
const card = document.querySelector(".card");
// className への代入は「全部の置き換え」になる
card.className = "highlight";
// → class="highlight" になり、card も is-active も消えてしまう
一方 classList は、他のクラスはそのままに、指定したクラスだけを足したり外したりします。既存のクラスを壊さずにピンポイントで操作できるのが最大の違いです。両者の特徴を次の表にまとめました。
| 項目 | className | classList |
|---|---|---|
| 扱う対象 | class 属性の文字列全体 | クラス名の集まり(DOMTokenList) |
| 追加・削除 | 文字列を自分で組み立てる必要がある | add() / remove() で1つだけ操作 |
| 既存クラスへの影響 | 代入すると丸ごと上書きされる | 他のクラスは保持される |
| 存在確認 | 文字列を自分で探す | contains() で判定できる |
classList の主なメソッド
classList には、クラスを操作するためのメソッドが一通りそろっています。まずはどんなメソッドがあるかを把握しておきましょう。
| メソッド | 説明 |
|---|---|
add(class1, class2, ...) | クラスを追加する。すでにある場合は何もしない |
remove(class1, class2, ...) | クラスを削除する。ない場合はエラーにならず無視される |
toggle(class) | クラスがあれば外し、なければ付ける。付けた場合は true、外した場合は false を返す |
toggle(class, force) | 第2引数が true なら必ず付け、false なら必ず外す |
contains(class) | そのクラスを持っているかを true / false で返す |
replace(old, new) | 指定したクラスを別のクラスに置き換える |
add と remove はまとめて渡せる
add() と remove() は、複数のクラス名をカンマ区切りで一度に渡せます。同じ要素に複数のクラスを付けたいときも、1回の呼び出しで済みます。
const box = document.querySelector(".box");
// 複数のクラスをまとめて追加できる
box.classList.add("is-active", "is-visible");
// 複数のクラスをまとめて削除できる
box.classList.remove("is-active", "is-visible");
// すでに付いているクラスを add しても二重にはならない(無視される)
box.classList.add("is-active");
box.classList.add("is-active"); // 何も起きない
contains で状態を確認する
contains() は、要素が特定のクラスを持っているかどうかを判定します。現在の状態に応じて処理を分けたいときに使います。
const menu = document.querySelector(".menu");
if (menu.classList.contains("is-active")) {
console.log("メニューは開いています");
} else {
console.log("メニューは閉じています");
}
replace でクラスを置き換える
replace() は、指定したクラスを別のクラスに入れ替えます。remove() と add() を続けて呼ぶのと同じことを1行で書けます。たとえばテーマを「ライト」から「ダーク」へ切り替える、といった用途に向いています。
const body = document.querySelector("body");
// theme-light を theme-dark に置き換える
body.classList.replace("theme-light", "theme-dark");
toggle の第2引数で付け外しを固定する
もっとも出番が多いのが toggle() です。引数を1つだけ渡すと、クラスが付いていれば外し、付いていなければ付ける、という切り替え動作になります。クリックのたびに状態が反転するため、開閉やオン・オフの実装にぴったりです。
さらに toggle() には第2引数(force)があり、ここに true / false を渡すと「必ず付ける」「必ず外す」と動作を固定できます。状態に関係なく結果をそろえたいときに便利です。
const panel = document.querySelector(".panel");
// 引数1つ: 付いていれば外す/なければ付ける
panel.classList.toggle("is-open");
// 第2引数 true: 状態に関わらず必ず付ける
panel.classList.toggle("is-open", true);
// 第2引数 false: 状態に関わらず必ず外す
panel.classList.toggle("is-open", false);
// 条件式を渡せば、その結果で付け外しが決まる
const isLarge = window.innerWidth > 768;
panel.classList.toggle("is-wide", isLarge);
引数1つの toggle() は、クラスを付けたときに true、外したときに false を返します。この戻り値を使えば、切り替え後の状態に応じてボタンの文言を変えるといった処理も簡単に書けます。
ボタンクリックでクラスを切り替えてみる
ここまでの内容を、実際の動きで確認してみましょう。次のデモは、querySelector() でボタンとメニューを取得し、ボタンがクリックされるたびにメニューへ is-active クラスを toggle() する例です。CSS では .menu.is-active のときだけ表示されるように指定してあり、クラスの付け外しだけで開閉が切り替わります。タブを切り替えてコードを確認し、プレビューのボタンを押して動きを試してみてください。
<div class="demo">
<button id="toggle" type="button">メニューを開閉する</button>
<nav id="menu" class="menu">
<a href="#">ホーム</a>
<a href="#">記事一覧</a>
<a href="#">お問い合わせ</a>
</nav>
</div>
body {
margin: 0;
font-family: sans-serif;
color: #333;
}
.demo {
padding: 24px;
}
button {
padding: 8px 16px;
border: none;
border-radius: 6px;
background: #4f46e5;
color: #fff;
font-weight: bold;
cursor: pointer;
}
.menu {
/* 初期状態は隠しておく */
display: none;
flex-direction: column;
gap: 4px;
margin-top: 12px;
padding: 12px;
border: 1px solid #ddd;
border-radius: 6px;
}
/* is-active クラスが付いたときだけ表示する */
.menu.is-active {
display: flex;
}
.menu a {
color: #4f46e5;
text-decoration: none;
}
// 操作する要素を取得する
const button = document.querySelector("#toggle");
const menu = document.querySelector("#menu");
button.addEventListener("click", () => {
// is-active クラスを付けたり外したりする
const isOpen = menu.classList.toggle("is-active");
// 戻り値(true / false)でボタンの文言を切り替える
button.textContent = isOpen ? "メニューを閉じる" : "メニューを開閉する";
});
このように、querySelector() で操作したい要素を取得し、addEventListener() の中で classList.toggle() を呼ぶ、という流れが基本のパターンです。同じ仕組みで、body に theme-dark クラスを付け外しすればテーマのライト・ダーク切替も実装できます。
クラスが付かない・切り替わらないときの確認ポイント
「クラスを操作しているはずなのに見た目が変わらない」というのは、つまずきやすいポイントです。原因はいくつかのパターンに分かれるので、順番に確認していきましょう。
要素が取得できておらず null になっている
もっとも多いのがこれです。querySelector() はマッチする要素がないと null を返し、その null に対して classList を使おうとすると「Cannot read properties of null」というエラーで処理が止まります。セレクタの綴りや記号が正しいか、対象の要素が本当に存在するかを、ブラウザの開発者ツールのコンソールで確認すると原因を切り分けやすくなります。
クラス名に . を付けてしまっている
querySelector() に渡すのは CSS セレクタなので .is-active のように . が必要ですが、classList のメソッドに渡すのは「クラス名そのもの」です。ここで . を付けてしまうのはよくある間違いです。先頭にドットを付けるとクラス名として不正な文字とみなされ、思った動作になりません。
const box = document.querySelector(".box"); // ここは . が必要
box.classList.add(".is-active"); // ✗ ドットは付けない
box.classList.add("is-active"); // ◯ クラス名だけを渡す
DOM の読み込み前にスクリプトが実行されている
<head> の中で読み込んだ JavaScript は、HTML 本文より先に実行されることがあります。その時点では対象の要素がまだ存在しないため querySelector() が null を返し、結果としてクラスを操作できません。script タグに defer 属性を付けるか、DOMContentLoaded イベントの中で処理を行えば、要素が揃ったタイミングで安全に操作できます。
// DOM の構築が終わってから実行する
document.addEventListener("DOMContentLoaded", () => {
const menu = document.querySelector("#menu");
menu.classList.add("is-active");
});
CSS 側でスタイルが当たっていない
JavaScript では正しくクラスが付いているのに見た目が変わらない場合は、CSS 側を疑います。クラスは付いていても、そのクラスに対するスタイルが定義されていなければ、当然見た目は変化しません。開発者ツールの要素検査でクラスが付与されているかを確認し、付いているなら CSS のセレクタや詳細度(より強い別のスタイルに上書きされていないか)を見直しましょう。
まとめ
element.classList を使えば、既存のクラスを壊さずに、クラスの追加・削除・切り替えを安全に行えます。add() と remove() は複数のクラスをまとめて渡せ、toggle() はクリックのたびに状態を反転させる開閉・オンオフの実装に最適です。toggle() の第2引数を使えば「必ず付ける/外す」と動作を固定でき、contains() で状態確認、replace() でクラスの置き換えもできます。
うまく動かないときは、要素が取得できているか(null ではないか)、メソッドに渡すクラス名に余計な . を付けていないか、スクリプトの実行タイミング、そして CSS 側のスタイル定義を順に確認すれば、たいていの原因にたどり着けます。querySelector() で要素を取得し、classList でクラスを切り替える流れを押さえておけば、見た目の制御は十分にこなせるようになります。