Element.classList は読み取り専用のプロパティで、要素の class 属性における生きた DOMTokenList コレクションを返します。

classList を使用することは、 element.className から取得した空白区切りの文字列として要素のクラスのリストにアクセスすることの便利な代替手段になります。

構文

const elementClasses = elementNodeReference.classList;

elementClassesDOMTokenList であり、 elementNodeReference の class 属性を表します。 class がない場合や空の場合は、 elementClasses.length は 0 を返します。 element.classList 自体は読取専用ですが、 add()remove() を用いてオブジェクトを変更することはできます。

メソッド

add( String [, String [, ...]] )
指定されたクラスの値を追加します。クラスがすでに要素の属性に存在した場合は、無視されます。
remove( String [, String [, ...]] )
指定されたクラスの値を除去します。
メモ: 存在しないクラスを削除してもエラーは発生しません。
item( Number )
コレクション内の序数で指定してクラスの値を返します。
toggle( String [, force] )
引数が一つだけの場合は、クラスの値を切り替えます。つまり、クラスが存在すればそれを除去して false を返し、存在しなければ追加して true を返します。
二番目の引数が存在する場合は、二番目の引数が true と評価される場合は、クラスの値を追加し、値が false と評価される場合は、除去します。
contains( String )
指定されたクラスの値が要素の class 属性に存在するかどうかを確認します。
replace( oldClass, newClass )
既存のクラスを新しいクラスで置き換えます。

const div = document.createElement('div');
div.className = 'foo';

// 最初の状態: <div class="foo"></div>
console.log(div.outerHTML);

// classList API を用いてクラスを除去、追加
div.classList.remove("foo");
div.classList.add("anotherclass");

// <div class="anotherclass"></div>
console.log(div.outerHTML);

// visible が設定されていれば除去し、なければ追加
div.classList.toggle("visible");

// i が 10 未満であるかどうかの条件によって visible を追加または除去
div.classList.toggle("visible", i < 10 );

console.log(div.classList.contains("foo"));

// 複数のクラスを追加または除去
div.classList.add("foo", "bar", "baz");
div.classList.remove("foo", "bar", "baz");

// spread syntax を使用したクラスの追加または除去
const cls = ["foo", "bar"];
div.classList.add(...cls); 
div.classList.remove(...cls);

// "foo" クラスを "bar" クラスで置き換え
div.classList.replace("foo", "bar");

Firefox 26 以前のバージョンでは、 add/remove/toggle メソッドでいくつかの引数の使用方法を実装していません。詳しくは https://bugzilla.mozilla.org/show_bug.cgi?id=814014 を参照してください。

ポリフィル

以前の onpropertychange イベントは、変更されたときにこのイベントを発生させる Element.prototype.className プロパティが存在することを考慮して、実際のクラスリストモックアップを作成するために使用することができます。以下のポリフィルは、 classList とその関連する DOMTokenList の両方を代替します。以下のポリフィルは、 IE10-IE11 の Element.prototype.classList と IE6-9 の「標準的な」 (ほとんどの一般的なアプリケーションの) 動作にアクセスする、すべての DOMTokenList メソッドの完全な標準準拠を保証します。

// 1. String.prototype.trim polyfill
if (!"".trim) String.prototype.trim = function(){ return this.replace(/^[\s]+|[\s]+$/g, ''); };
(function(window){"use strict"; // prevent global namespace pollution
function checkIfValidClassListEntry(O, V){
if (V === "") throw new DOMException(
  "Failed to execute '" + O + "' on 'DOMTokenList': The token provided must not be empty." );
if((wsI=V.search(wsRE))!==-1)throw new DOMException("Failed to execute '"+O+"' on 'DOMTokenList': "+
"The token provided ('"+V[wsI]+"') contains HTML space characters, which are not valid in tokens.");
  }
// 2. Implement the barebones DOMTokenList livelyness polyfill
if (typeof DOMTokenList !== "function") (function(window){
    var document = window.document, Object = window.Object, hasOwnProp = Object.prototype.hasOwnProperty;
    var defineProperty = Object.defineProperty, allowTokenListConstruction = 0, skipPropChange = 0;
    var Element = window.Element, wsI = 0, wsRE = /[\11\12\14\15\40]/; // WhiteSpace Regular Expression
    function DOMTokenList(){
        if (!allowTokenListConstruction) throw TypeError("Illegal constructor"); // internally let it through
    }
    DOMTokenList.prototype.toString = DOMTokenList.prototype.toLocaleString = function(){return this.value};
    DOMTokenList.prototype.add = function(){
        a: for(var v=0, argLen=arguments.length,val="",ele=this["uCL"],proto=ele[" uCLp"]; v!==argLen; ++v) {
            val = arguments[v] + "", checkIfValidClassListEntry("add", val);
            for (var i=0, Len=proto.length, resStr=val; i !== Len; ++i)
                if (this[i] === val) continue a; else resStr += " " + this[i];
            this[Len] = val, proto.length += 1, proto.value = resStr;
        }
        skipPropChange = 1, ele.className = proto.value, skipPropChange = 0;
    };
    DOMTokenList.prototype.remove = function(){
        for (var v=0, argLen=arguments.length,val="",ele=this["uCL"],proto=ele[" uCLp"]; v !== argLen; ++v) {
            val = arguments[v] + "", checkIfValidClassListEntry("remove", val);
            for (var i=0, Len=proto.length, resStr="", is=0; i !== Len; ++i)
                if(is){ this[i-1]=this[i] }else{ if(this[i] !== val){ resStr+=this[i]+" "; }else{ is=1; } }
            if (!is) continue;
            delete this[Len], proto.length -= 1, proto.value = resStr;
        }
        skipPropChange = 1, ele.className = proto.value, skipPropChange = 0;
    };
    window.DOMTokenList = DOMTokenList;
    function whenPropChanges(){
        var evt = window.event, prop = evt.propertyName;
        if ( !skipPropChange && (prop==="className" || (prop==="classList" && !defineProperty)) ) {
            var target = evt.srcElement, protoObjProto = target[" uCLp"], strval = "" + target[prop];
            var tokens=strval.trim().split(wsRE), resTokenList=target[prop==="classList"?" uCL":"classList"];
            var oldLen = protoObjProto.length;
            a: for(var cI = 0, cLen = protoObjProto.length = tokens.length, sub = 0; cI !== cLen; ++cI){
                for(var innerI=0; innerI!==cI; ++innerI) if(tokens[innerI]===tokens[cI]) {sub++; continue a;}
                resTokenList[cI-sub] = tokens[cI];
            }
            for (var i=cLen-sub; i < oldLen; ++i) delete resTokenList[i]; //remove trailing indexs
            if(prop !== "classList") return;
            skipPropChange = 1, target.classList = resTokenList, target.className = strval;
            skipPropChange = 0, resTokenList.length = tokens.length - sub;
        }
    }
    function polyfillClassList(ele){
        if (!ele || !("innerHTML" in ele)) throw TypeError("Illegal invocation");
        srcEle.detachEvent( "onpropertychange", whenPropChanges ); // prevent duplicate handler infinite loop
        allowTokenListConstruction = 1;
        try{ function protoObj(){} protoObj.prototype = new DOMTokenList(); }
        finally { allowTokenListConstruction = 0 }
        var protoObjProto = protoObj.prototype, resTokenList = new protoObj();
        a: for(var toks=ele.className.trim().split(wsRE), cI=0, cLen=toks.length, sub=0; cI !== cLen; ++cI){
            for (var innerI=0; innerI !== cI; ++innerI) if (toks[innerI] === toks[cI]) { sub++; continue a; }
            this[cI-sub] = toks[cI];
        }
        protoObjProto.length = Len-sub, protoObjProto.value = ele.className, protoObjProto[" uCL"] = ele;
        if (defineProperty) { defineProperty(ele, "classList", { // IE8 & IE9 allow defineProperty on the DOM
            enumerable:   1, get: function(){return resTokenList},
            configurable: 0, set: function(newVal){
                skipPropChange = 1, ele.className = protoObjProto.value = (newVal += ""), skipPropChange = 0;
                var toks = newVal.trim().split(wsRE), oldLen = protoObjProto.length;
                a: for(var cI = 0, cLen = protoObjProto.length = toks.length, sub = 0; cI !== cLen; ++cI){
                    for(var innerI=0; innerI!==cI; ++innerI) if(toks[innerI]===toks[cI]) {sub++; continue a;}
                    resTokenList[cI-sub] = toks[cI];
                }
                for (var i=cLen-sub; i < oldLen; ++i) delete resTokenList[i]; //remove trailing indexs
            }
        }); defineProperty(ele, " uCLp", { // for accessing the hidden prototype
            enumerable: 0, configurable: 0, writeable: 0, value: protoObj.prototype
        }); defineProperty(protoObjProto, " uCL", {
            enumerable: 0, configurable: 0, writeable: 0, value: ele
        }); } else { ele.classList=resTokenList, ele[" uCL"]=resTokenList, ele[" uCLp"]=protoObj.prototype; }
        srcEle.attachEvent( "onpropertychange", whenPropChanges );
    }
    try { // Much faster & cleaner version for IE8 & IE9:
        // Should work in IE8 because Element.prototype instanceof Node is true according to the specs
        window.Object.defineProperty(window.Element.prototype, "classList", {
            enumerable: 1,   get: function(val){
                                 if (!hasOwnProp.call(ele, "classList")) polyfillClassList(this);
                                 return this.classList;
                             },
            configurable: 0, set: function(val){this.className = val}
        });
    } catch(e) { // Less performant fallback for older browsers (IE 6-8):
        window[" uCL"] = polyfillClassList;
        // the below code ensures polyfillClassList is applied to all current and future elements in the doc.
        document.documentElement.firstChild.appendChild(document.createElement('style')).styleSheet.cssText=(
            '_*{x-uCLp:expression(!this.hasOwnProperty("classList")&&window[" uCL"](this))}' + //  IE6
            '[class]{x-uCLp/**/:expression(!this.hasOwnProperty("classList")&&window[" uCL"](this))}' //IE7-8
        );
    }
})();
// 3. Patch in unsupported methods in DOMTokenList
(function(DOMTokenListProto, testClass){
    if (!DOMTokenListProto.item) DOMTokenListProto.item = function(i){
        function NullCheck(n) {return n===void 0 ? null : n} return NullCheck(this[i]);
    };
    if (!DOMTokenListProto.toggle || testClass.toggle("a",0)!==false) DOMTokenListProto.toggle=function(val){
        if (arguments.length > 1) return (this[arguments[1] ? "add" : "remove"](val), !!arguments[1]);
        var oldValue = this.value;
        return (this.remove(oldToken), oldValue === this.value && (this.add(val), true) /*|| false*/);
    };
    if (!DOMTokenListProto.replace || typeof testClass.replace("a", "b") !== "boolean")
        DOMTokenListProto.replace = function(oldToken, newToken){
            checkIfValidClassListEntry("replace", oldToken), checkIfValidClassListEntry("replace", newToken);
            var oldValue = this.value;
            return (this.remove(oldToken), this.value !== oldValue && (this.add(newToken), true));
        };
    if (!DOMTokenListProto.contains) DOMTokenListProto.contains = function(value){
        for (var i=0,Len=this.length; i !== Len; ++i) if (this[i] === value) return true;
        return false;
    };
    if (!DOMTokenListProto.forEach) DOMTokenListProto.forEach = function(f){
        if (arguments.length === 1) for (var i = 0, Len = this.length; i !== Len; ++i) f( this[i], i, this);
        else for (var i=0,Len=this.length,tArg=arguments[1]; i !== Len; ++i) f.call(tArg, this[i], i, this);
    };
    if (!DOMTokenListProto.entries) DOMTokenListProto.entries = function(){
        var nextIndex = 0, that = this;
        return {next: function() {
            return nextIndex<that.length ? {value: [nextIndex, that[nextIndex]], done: false} : {done: true};
        }};
    };
    if (!DOMTokenListProto.values) DOMTokenListProto.values = function(){
        var nextIndex = 0, that = this;
        return {next: function() {
            return nextIndex<that.length ? {value: that[nextIndex], done: false} : {done: true};
        }};
    };
    if (!DOMTokenListProto.keys) DOMTokenListProto.keys = function(){
        var nextIndex = 0, that = this;
        return {next: function() {
            return nextIndex<that.length ? {value: nextIndex, done: false} : {done: true};
        }};
    };
})(window.DOMTokenList.prototype, window.document.createElement("div").classList);
})(window);

なお、上記のポリフィルは機能が限定されています。現在、 IE 6-7 では、文書要素の外にある要素 (たとえば、 document.createElement によって作成された後、親ノードに appendChild される前の要素) を代替することができません。しかし、 IE9 では正常に動作するはずです。代替バージョンの classList と W3 の仕様書との主な違いは、 IE 6-8 においては不変オブジェクト (プロパティを直接変更できないオブジェクト) を生成する方法がないという点です。しかし IE9 では、プロトタイプを拡張し、可視オブえジェクトを凍結し、ネイティブのプロパティメソッドを上書きすることで可能です。しかし、このような操作は IE6-IE8 では機能せず、 IE9 ではウェブページ全体のパフォーマンスを大幅に低下させるため、これらの修正はこのポリフィルでは完全に実行できません。 IE6-7 の軽い注意事項ですが、このポリフィルは window オブジェクトの window[" uCL"] プロパティを使用して CSS の式とコミュニケーションを行い、 CSS の x-uCLp プロパティをすべての要素に付与し、 element[" uCL"] プロパティによってガーベジコレクションを行うことができるようにして性能を改善しています。すべてのポリフィルを使用したブラウザー (IE6-9) では、追加の element[" uCLp"] プロパティによって要素に標準に準拠したプロトタイピングを保証し、それぞれの element["classList"] オブジェクトに DOMTokenList[" uCL"] プロパティを追加することで、 DOMTokenList が自分自身の要素の範囲に収まることを保証します。

仕様書

仕様書 状態 備考
DOM
Element.classList の定義
現行の標準 初回定義
DOM4
Element.classList の定義
廃止された  

ブラウザーの対応

Update compatibility data on GitHub
デスクトップモバイル
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeEdge MobileAndroid 版 FirefoxAndroid 版 OperaiOS 版 SafariSamsung Internet
基本対応Chrome 完全対応 8Edge 完全対応 16
完全対応 16
部分対応 12
補足
補足 Not supported for SVG elements.
Firefox 完全対応 3.6IE 完全対応 10Opera 完全対応 ありSafari 完全対応 5.1WebView Android 完全対応 ありChrome Android 完全対応 ありEdge Mobile 完全対応 12Firefox Android 完全対応 ありOpera Android ? Safari iOS 完全対応 5Samsung Internet Android ?
toggle() method's second argumentChrome 完全対応 24Edge 完全対応 12Firefox 完全対応 24IE 未対応 なしOpera 完全対応 15Safari 完全対応 7WebView Android 完全対応 ありChrome Android 完全対応 ありEdge Mobile 完全対応 12Firefox Android 完全対応 24Opera Android ? Safari iOS 完全対応 7Samsung Internet Android ?
Multiple arguments for add() & remove()Chrome 完全対応 24Edge 完全対応 12Firefox 完全対応 26IE 未対応 なしOpera 完全対応 15Safari 完全対応 7WebView Android 完全対応 ありChrome Android 完全対応 ありEdge Mobile 完全対応 12Firefox Android 完全対応 26Opera Android ? Safari iOS 完全対応 7Samsung Internet Android ?
replace()Chrome 完全対応 61Edge ? Firefox 完全対応 49IE 未対応 なしOpera ? Safari 未対応 なしWebView Android ? Chrome Android 完全対応 61Edge Mobile ? Firefox Android 完全対応 49Opera Android ? Safari iOS 未対応 なしSamsung Internet Android ?

凡例

完全対応  
完全対応
未対応  
未対応
実装状況不明  
実装状況不明
実装ノートを参照してください。
実装ノートを参照してください。

関連情報

ドキュメントのタグと貢献者

このページの貢献者: mfuji09, fscholz, AshfaqHossain, pocotan001, ethertank, Marsf
最終更新者: mfuji09,