#はじめに
JavaScriprで要素のスタイルを普通に変更しようとしても、元々のCSSで !important
指定されている場合変更できないという問題があります。
!important
を使うこと自体ナンセンスな部分がありますが、仕事で使う機会があったのでいろいろな方法を挙げてみました。
それぞれの方法を見てみます。
#いろいろな方法
それぞれのメリット・デメリットも含めて。
以下のようなHTMLがあるとします。(いろいろ省略してます)
<style>
#target {
background-color: #f00 !important;
}
</style>
<div id="target" style="width: 100px; height: 100px;"></div>
この #target
に対して背景色を変えてみます。
##element.style.*
よく使う書き方ですが、この方法では !important
を指定することはできません。
var target = document.getElementById('target');
target.style.backgroundColor = '#00f';
// styleとして適用されるがこれでは優先的に下
target.style.backgroundColor = '#00f !important';
// エラーにはならないが変わらない
そもそも不可能なのでメリットもデメリットもないですね。
##jQueryの .css()
万能なjQueryですが、この方法も同じように !important
を指定することはできません。
var $target = $('#target');
$target.css('background-color', '#00f');
// styleとして適用されるがこれでは優先的に下
$target.css('background-color', '#00f !important');
// エラーにはならないが変わらない
これも不可能なのでメリットもデメリットもありません。
##element.style.cssText
element.style.cssText
は、要素のstyle属性で指定されているスタイルが文字列として取得でき、更に変更できるプロパティです。
これに代入して変更する方法です。
var
target = document.getElementById('target'),
cssText = target.style.cssText;
console.log(cssText); // "width: 100px; height: 100px;"
target.style.cssText = cssText + 'background-color: #00f !important;';
// 適用された!
// これでもいい
// target.style.cssText += 'background-color: #00f !important;';
もし既に cssText
に background-color
がある場合はスタイルが上書きされます。
###メリット
- CSSそのままの書式で書くことができる
- 複数のスタイルを一度に書くことができる
###デメリット
- 既にstyle属性で指定されている場合、それらが上書きされないようにしなければならない
- プロパティ名や値を変数で持ちたい場合などに文字列結合が面倒くさい
##element.setAttribute()
element.setAttribute()
は、要素の属性の値をセットするメソッドですが、これをstyle属性に対して使用する方法です。
var
target = document.getElementById('target'),
style = target.getAttribute('style');
console.log(style); // "width: 100px; height: 100px;"
target.setAttribute('style', style + 'background-color: #00f !important;');
// 適用された!
もし既にstyle属性に background-color
がある場合はスタイルが上書きされます。
###メリット
- CSSそのままの書式で書くことができる
- 複数のスタイルを一度に書くことができる
###デメリット
- 既にstyle属性で指定されている場合、それらが上書きされないようにしなければならない
- プロパティ名や値を変数で持ちたい場合などに文字列結合が面倒くさい
- 書式が間違っていてもそのままstyle属性の値として保持してしまう
##element.style.setProperty()
element.style.setProperty()
はチェインケースでスタイルを指定できるメソッドです。
var target = document.getElementById('target');
target.style.setProperty('background-color', '#00f', 'important');
// 適用された!
第3引数を 'important'
とすることで、!important
が適用されます。(頭の感嘆符 !
は不要です)
もし、必要でない場合は第3引数を省略したり空文字や null
を指定します。
###メリット
- 見た目がすっきりしている
- キャメルケースではなくチェインケースで書けるので、書き間違いが起こらない
- 引数ごとに分かれているので、プロパティ名や値を変数で持っている場合も扱いやすい
###デメリット
- まとめて指定できないので、適用したい分だけメソッドを書く必要がある
##style要素を生成する
もう面倒だからstyle要素を作ってしまえという方法です。
var style = document.createElement('style');
document.head.appendChild(style);
style.textContent = '#target {background-color: #00f !important;}';
// 適用された!
###メリット
- 要素を直接いじらずにスタイルの操作ができる
- CSSそのままの書式で書くことができる
- 複数のスタイルを一度に書くことができる
- JavaScriptでは取得できない擬似要素に対してスタイルを指定することができる
###デメリット
- 無駄なstyle要素が増えてしまう
- プロパティ名や値を変数で持ちたい場合などに文字列結合が面倒くさい
- ECMAScript 2015 のテンプレートリテラルが使用できない場合、複数行にわたる書き方が面倒くさい
##CSSStyleSheet.insertRule()
style要素の CSSStyleSheet
オブジェクトの CSSStyleSheet.insertRule()
というメソッドを使う方法です。
// style属性が存在する場合はそれを利用する
var
doc = document,
style = doc.getElementsByTagName('style')[0] || doc.head.appendChild(doc.createElement('style')),
styleSheet = style.sheet;
styleSheet.insertRule('#target {background-color: #00f !important;}', styleSheet.cssRules.length);
// 適用された!
// ちなみに、ひとつのルール毎に使うメソッドなので、複数のルールを一度に指定できない
// styleSheet.insertRule('#foo {prop: value;} #bar {prop: value;}', styleSheet.cssRules.length);
CSSStyleSheet
オブジェクトとは、style要素が内部で持っているCSSのルールをまとめたオブジェクトです。
###メリット
- 要素を直接いじらずにスタイルの操作ができる
- CSSそのままの書式で書くことができる
- ひとつのルールに複数のスタイルを一度に書くことができる
- JavaScriptでは取得できない擬似要素に対してスタイルを指定することができる
###デメリット
- 書き方が少し複雑
- 無駄なstyle要素が増えてしまう
- プロパティ名や値を変数で持ちたい場合などに文字列結合が面倒くさい
- ECMAScript 2015 のテンプレートリテラルが使用できない場合、複数行にわたる書き方が面倒くさい
#おわりに
メリット・デメリットは他にもこんなのがあるよという場合は遠慮なく言ってください。