• JavaScriptのclassListはclass名を文字列でつながずDOMTokenListとして操作する

JavaScriptのclassListはclass名を文字列でつながずDOMTokenListとして操作する

公開日: 執筆:佐藤

要素へclass名を一つ追加または削除するなら、classNameの文字列を組み立てず、classListを使います。classListは空白で区切られたclass名をDOMTokenListとして扱い、contains()、add()、remove()、toggle()で操作できます。

既存のclass名を全部置き換えたい場合はclassName、一つのclass名だけを残したまま追加または削除したい場合はclassListと、変更する範囲で分けます。

classListはclass属性の各class名を一件ずつ扱う

W3C DOM4は、要素のclassListがDOMTokenListを返し、その基になる文字列がclassNameの値であると定めています。

たとえば、次のHTMLには三つのclass名があります。

<div class="notice is-important is-hidden">お知らせ</div>

classNameで取得すると、値はnotice is-important is-hiddenという一つの文字列です。classListでは、notice、is-important、is-hiddenを三つのトークンとして扱えます。

操作 戻り値または結果
contains('is-hidden') class名があればtrue、なければfalse
add('is-open') class名がなければ追加する
remove('is-hidden') class名があれば削除する
toggle('is-open') あれば削除し、なければ追加する

同じclass名をadd()しても重複しません。存在しないclass名をremove()しても、ほかのclass名は変わりません。

contains()で状態を確かめてから処理を分ける

架空のお知らせ欄を選び、非表示のclass名を外す例は、次の形です。

var notice = document.querySelector('.notice');

if (notice !== null && notice.classList.contains('is-hidden')) {
  notice.classList.remove('is-hidden');
  notice.classList.add('is-visible');
}

これは説明用の仮例です。querySelector()は要素がなければnullを返すため、classListへ進む前に要素の存在を確認します。

contains()は、class名の有無を判定するだけで変更しません。何を条件にし、どのclass名へ変えるかをコード上で分けられます。

表示を切り替える条件が明確なら、状態を調べたうえでadd()またはremove()を使います。実行するたびに必ず反転させたい操作だけ、toggle()を使います。

toggle()は実行するたびに有無を反転する

ボタンを押すたびにclass名を付け外しする例は、次の形です。

var panel = document.querySelector('.panel');

if (panel !== null) {
  var isOpen = panel.classList.toggle('is-open');
}

toggle()は、指定したclass名がなければ追加し、あれば削除します。操作後にclass名があればtrue、なければfalseを返します。

通信完了後は必ず開く、エラー時は必ず閉じる、という処理でtoggle()を使うと、呼び出す前の状態によって結果が逆になります。その場合はadd()またはremove()で目的の状態を明示します。

空文字と空白を含むclass名は一つのトークンにならない

classListへ渡すclass名は、一つの空白なしトークンです。空文字を渡すとSyntaxError、空白を含む文字列を渡すとInvalidCharacterErrorになります。

element.classList.add('is-open');      // 一つのclass名
element.classList.add('is open');      // 空白を含むため一つのclass名ではない

複数のclass名を一つの文字列へ詰め込まず、変更するclass名を分けます。class名の照合は大文字と小文字を区別するため、HTMLとJavaScriptの表記もそろえます。

classNameはclass属性全体を置き換えるときに使う

className = 'notice'と代入すると、class属性全体がnoticeへ置き換わります。元からあったis-importantやis-hiddenも消えます。

一つのclass名だけを追加するために、次のような文字列連結を続けると、空白の不足や同じclass名の重複を管理しなければなりません。

element.className += ' is-open';

class属性全体を意図して作り直すならclassNameを使えます。既存のclass名を保ったまま一件だけ変えるなら、classListの操作と目的が一致します。

DOM4は仕様書であり、対象とするブラウザーが各操作へ対応していることまで保証しません。公開前には、必要なブラウザーで追加、削除、切替、例外時の処理を確認します。

まず、className +=でclass名を追加している処理を一か所選んでください。残すclass名と変えるclass名を分け、contains()、add()、remove()、toggle()のどれが目的に合うかを決めます。

戻る