こんにちは,太田です。前々回と前回はHTMLの操作について解説しました。今回は,CSSの操作を中心に解説していきます。
CSSとJavaScript
JavaScriptからCSSを扱うとは,JavaScriptから要素に適用されているスタイルを変更して見た目を変化させる,ということを意味します。その具体的な方法にはいくつかの種類があります。
- styleプロパティの操作
- class名の操作
- CSS自体の操作
では,styleプロパティの操作から順番に見ていきます。
styleプロパティの操作
要素のstyleプロパティを直接操作する方法は,その要素だけに影響するので1回あたりの処理コストは低く済むというメリットはあります。しかし,複数のプロパティの操作に加え,多くの要素のスタイルを変更する場合には,スタイルを変更するたびに描画への影響の計算が行われる(この計算をreflowと呼びます)ので,ボトルネックになりかねないという問題もあります。
styleプロパティの操作
var div = document.getElementById('css-sample1');
div.style.fontSize = '20px';
div.style.color = 'white';
div.style.backgroundColor = '#444';
div.style.width = '100px';
div.style.padding = '10px';
なお,ここで次のようにstyleプロパティを変数に入れることで,少しだけコードを短くし,処理時間もほんの僅かだけ速くすることもできます。
styleプロパティの操作#2
var div = document.getElementById('css-sample1');
var style = div.style;
style.fontSize = '20px';
style.color = 'white';
style.backgroundColor = '#444';
style.width = '100px';
style.padding = '10px';
なお,CSSではfont-sizeですが,上記のようにJavaScriptではfontSizeと表記します。これはJavaScriptではハイフンがマイナスとして解釈されてしまうため,プロパティ名に使えないからです。もっとも,objest['xx-プロパティ'] の形であればハイフンがマイナスとして解釈されないので,(ハイフンに限らず)自由にプロパティ名を作ることができます。
なお,この違いはハイフンの次の文字を大文字にするという簡単なルールなので変換が可能です。この処理はCamelize,もしくはCapitalizeと呼ばれることが多いようです。
Camel Caseへの変換#1
function camelize(prop){
return prop.replace(/-([a-z])/g, function(m, m1){
return m1.toUpperCase();
});
}
camelize('font-size'); // fontSize
camelize('-moz-border-radius'); // MozBorderRadius
正規表現でハイフンの次の文字をキャプチャしておき,その文字をtoUpperCaseで大文字に変換しています。もしくは次のようにcharAtで2文字目を大文字化してもよいでしょう。
Camel Caseへの変換#2
function camelize(prop){
return prop.replace(/-[a-z]/g, function(m){
return m.charAt(1).toUpperCase();
});
}
camelize('font-size'); // fontSize
camelize('-moz-border-radius'); // MozBorderRadius
-moz-border-radiusのように,先頭にベンダー接頭辞が付く場合も同様です。なお,ベンダー接頭辞付きのスタイルはベンダー接頭辞なしのスタイルをサポートしたときに使えなくなる場合があるので,なるべくベンダー接頭辞ありのスタイルとベンダー接頭辞なしのスタイルの両方を指定するようにしましょう。
ベンダー接頭辞付きのスタイルのサポートが切られたケースとして,Mozillaはopacityとそのベンダー接頭辞版である-moz-opacityの両方をFirefox0.9の頃からFirefox3.0までサポートし続けていましたが,Firefox 3.5からは-moz-opacityをサポートしなくなっています。Mozillaは今後もベンダー接頭辞は積極的にサポートを打ち切りしていく方針を示しています。
あくまで,ベンダー接頭辞付きのスタイルは仕様が確定するまでの間に仕方なく試用されるものであり,将来的には無効になるものです。そのことは忘れないようにしましょう。
styleプロパティが存在するか確認する方法
上記でFirefox 3.5が-moz-opacityをサポートしなくなったと書きましたが,そういったサポート状況をJavaScriptから知る方法を紹介します。
CSSのサポート状況の確認と処理の振り分け
if('opacity' in style){
style.opacity = 0.5;
} else/* if('filter' in style) */{
style.filter = 'alpha(opacity=50)';
}
このように,styleプロパティに対して,対象のスタイルが存在するかどうかをin演算子でチェックします。in演算子はオブジェクトにプロパティが存在するかをチェックすることができる,ECMA-262で定義された演算子です。この方法が最もスマートで間違いがありません。もちろん,要はundefinedかどうかのチェックをしているだけなので,style.opacity !== undefinedや,typeof style.opacity !== 'undefined'のような形でも問題はありません。ただし,ECMA-262 3rdでは undefined が予約語ではない(書き換え可能)ので,前者はundefinedの代わりに void 0(void演算子)を使用したほうが確実です。
なお,このような分岐処理を何度も行うのは非効率なので,次のようにsetOpacity関数を定義しておくというのも良いかもしれません。
CSSのサポート状況の確認と処理の振り分け
var setOpacity = function(elem, value){
elem.style.opacity = value;
};
if(!('opacity' in document.documentElement.style)){
setOpacity = function(elem, value){
elem.style.filter = 'alpha(opacity='+value*100+')';
};
}
setOpacity(document.body, 0.5);
特に,だんだんと透明にするようなアニメーション処理を行う場合はこういった最適化が効いてきます(ただ,関数呼び出しをしてしまう時点で最速ではありません……)。
なお,こういった関数の定義方法はいくつかありますが,第4回 JavaScriptの基礎知識#1のJavaScriptの関数でも説明していますので,未読の方は是非,既読の方はよろしければ復習してみてください。
複数のスタイルを一度に適用する方法
ひとつの要素に対して,一度に複数のスタイルを適用する方法もあります。1つはシンプルにsetAttributeで要素のstyle属性を設定する方法です。
styleプロパティの操作#3
var div = document.getElementById('css-sample2');
div.setAttribute('style','font-size:20px;color:white;background-color:#444;width:100px;padding:10px;');
ただし,この方法はIE 6, IE 7で動作しません。その代わりとして,styleプロパティのcssTextを使う方法があります。
styleプロパティの操作#4
var div = document.getElementById('css-sample2');
div.style.cssText='font-size:20px;color:white;background-color:#444;width:100px;padding:10px;';
cssTextを使う方法はIE 6やSafari 3などを含めてクロスブラウザで動作しますし,速度もsetAttributeと変わらず,このサンプルのように複数のスタイルを変更するケースでは個別に操作するより高速に動作します。

