2014/02/25更新

[JS] ブラウザの実装状況に合わせて、ベンダプレフィックスを使い分けてCSSを設定する

このエントリーをはてなブックマークに追加            

こんにちは、@yoheiMuneです。
今日は、JSからDOM要素にCSSを設定する場合に、ブラウザのサポート状況に合わせて、いい感じにCSSを指定する方法をブログに書きたいと思います。

画像

Special Thanks to http://flic.kr/p/kpTpJ6



1、UserAgentを利用して、ベンダープレフィックスを使い分ける

まず1つ目の方法として、UserAgentから利用してベンダープレフィックスを使い分ける方法があります。 実装方法は、事前にUserAgentを調べてベンダープレフィックスを把握しておき、実際にCSSを設定する時にそれを使うという方法です。
例えば以、transitionを設定する場合には、以下のような実装となります。
// UAを元に必要なベンダープレフィックスを見分ける。
var venderPrefix = (/webkit/i).test(navigator.appVersion) ? 'webkit' :
                        (/firefox/i).test(navigator.userAgent) ? 'moz' :
                        (/trident/i).test(navigator.userAgent) ? 'ms' :
                        'opera' in window ? 'O' : '';

// ベンダープレフィックスを使って、CSSを設定する。
var elm = document.querySelector('#foo');
elm.style[venderPrefix + 'Transition'] = 'opacity 1s ease-in-out';
数行程度の簡単な実装ですね。
これを用いる場合には、以下のようなことを考慮する必要があります。
「指定するCSSはベンダープレフィックス付きで動作することが確約されている」

外に公開せず自前で使う場合や、transitionやtransformなどを限定で扱う場合には、このような簡単な実装が良いですね。



定義されているCSSから調べる

次に、定義済みのCSSを調べて、それに合わせてCSS名を判定する方法です。 定義済みのCSSは、以下のように取得する事ができます。

(IE8は対象外、Android2系/3系は一部サポートです。詳細はこちら

// 実装されているCSSを一覧で表示する
var dec = getComputedStyle(document.head, '');
for (p in dec) {
    if (dec.hasOwnProperty(p)) {
        console.log(p + ' : ' + dec[p]);
    }
}

// 実行例(抜粋)
// webkitAnimation : none 0s ease 0s 1 normal none running VM142:6
// webkitAnimationDelay : 0s VM142:6
// webkitAnimationDirection : normal VM142:6
// webkitAnimationDuration : 0s VM142:6
// webkitAnimationFillMode : none VM142:6
// webkitAnimationIterationCount : 1 VM142:6
// webkitAnimationName : none 
この情報を利用して、与えられたCSS名に対して、利用可能なCSS名を返す関数を定義することができます。
/*
* 注意:すごく簡易的な実装です。Webkitのみです。
*/
var dec = getComputedStyle(document.head, '');
var getCssName = function (cssName) {


    // 与えられたCSS名からハイフンを取り除く
    cssName = cssName.replace(/-/g, '');

    // 定義済みのCSS名を探す
    var reg1 = new RegExp('^' + cssName + '$', 'i');
    var reg2 = new RegExp('^(webkit|moz|ms)' + cssName + '$', 'i');
    var nameWithPrefix;
    for (prop in dec) {
        if (dec.hasOwnProperty(prop)) {
            if (reg1.test(prop)) {
                // ずばりそのものを発見!
                return prop;
            } else if (reg2.test(prop)) {
                // ベンダープレフィックス付きを発見!
                return prop;
            }
        }
    }

    // 残念、見つからず。
    return null;
}
例えばChrome(v.33)の場合、以下のように動作します。
getCssName('transition'); // => transition
getCssName('text-stroke-color'); // => webkitTextStrokeColor
ベンダープレフィックスが必要なCSSプロパティには、ベンダープレフィックス付きの名前が返却されます。

getComputedStyleは、(上記の使い方ではありませんが)jQueryやzeptoでもCSSの実装確認に使われているようです。
上の実装はwebkit限定で、例えばfirefoxの場合には動作しません。firefoxでは、getComputedStyleで保持するCSS名は、ハイフン記法で保持しているようです。本当に実験的な実装です。

jQueryでgetComputedStyleが利用されている例):
/*
    jquery / src / css / var / getStyles.js
    http://git.io/8aByoA
*/
define(function() {
    return function( elem ) {
        return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
    };
});


/*
    jquery / src / css / support.js
    http://git.io/6z7FZA
*/
function computePixelPositionAndBoxSizingReliable() {
    div.style.cssText =
        // Support: Firefox<29, Android 2.3
        // Vendor-prefix box-sizing
        "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
        "box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
        "border:1px;padding:1px;width:4px;position:absolute";
    div.innerHTML = "";
    docElem.appendChild( container );

    var divStyle = window.getComputedStyle( div, null );
    pixelPositionVal = divStyle.top !== "1%";
    boxSizingReliableVal = divStyle.width === "4px";

    docElem.removeChild( container );
}
zepto.jsで利用されている例):
/*
    zepto / src / ie.js
    http://git.io/njJPSg
*/
// getComputedStyle shouldn't freak out when called
// without a valid element as argument
try {
  getComputedStyle(undefined)
} catch(e) {
  var nativeGetComputedStyle = getComputedStyle;
  window.getComputedStyle = function(element){
    try {
      return nativeGetComputedStyle(element)
    } catch(e) {
      return null
    }
  }
}



最後に

jqueryとかzeptoとかjquery.transitとか、JSからCSSを指定する際に、ブラウザ別にどうやって処理を分けているんだろうなぁと思い、調べました。 調べてみるとgetComputedStyleというメソッドがあることを知り、使ってみたいと思い、試しに使ってみた次第でした。 自分のコードでは実線に投入できるほど、安定とパフォーマンスを発揮しませんが、getComputedStyleの雰囲気を伝えられていれば幸いです。

最後までご覧頂きましてありがとうございました。





こんな記事もいかがですか?

RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。