IEで width: "3em", width: "auto" から px単位の値を取得する
document.defaultView.getComputedStyle() は、計算済みのスタイル(最終的に描画で使用されるスタイル値)を取得するメソッドです。
いつものことですが、IEにはgetComputedStyle()が実装されていないため、element.currentStyle から同様の情報を取得します。
getComputedStyle() は width: "3em" を width: "48px" に変換してくれるのですが、
currentStyle は、(残念ながら)pxに単位を変換してくれないので、style="width: 3em, top: 3%, height: auto" が、 "3em", "3%", "auto" と、そのまま返ってきます。
そこで、currentStyle から取得した単位付の文字列から、pixel単位の数値を取得するには以下のようにします。
toPixel = function(elm, val) { if (!isNaN(val) || val.lastIndexOf("px") !== -1) { return val; } // 3 or "3" or "3px" ならそのまま !impotant var rv = 0, s = elm.style, r = elm.runtimeStyle, sx = s.left; r.left = elm.currentStyle.left; s.left = val; rv = s.pixelLeft; // restore s.left = sx; r.left = ""; return rv; };
この関数を使うと、style要素で指定したスタイルと、インライン属性で指定したスタイルの両方で、px単位の値を取得可能になります。
さらにwidthやheightの"auto"に対応したテストコードが以下となります。
<html><head><title>pixel</title><style> #hoge { /* position: absolute; */ left: 10%; top: 3em; width: auto; height: 3cm; background-color: gray; } </style></head><body><div id="hoge">hoge</div> <script> function toPixel(elm, val, cssProp /* = "" */) { if (!isNaN(val) || val.lastIndexOf("px") !== -1) { return val; } if (val === "auto") { switch (cssProp || "") { case "width": return elm.clientWidth; case "height": return elm.clientHeight; } } var rv = 0, s = elm.style, r = elm.runtimeStyle, sx = s.left; r.left = elm.currentStyle.left; s.left = val; rv = s.pixelLeft; // restore s.left = sx; r.left = ""; return rv; } window.onload = function() { var elm = document.getElementById("hoge"), cs = elm.currentStyle; alert( "left=[" + cs.left + " -> " + toPixel(elm, cs.left) + "], " + "top=[" + cs.top + " -> " + toPixel(elm, cs.top) + "], " + "width=[" + cs.width + " -> " + toPixel(elm, elm.clientWidth, "width") + "], " + "height=[" + cs.height + " -> " + toPixel(elm, elm.clientHeight, "height") + "]" ); } </script></body></html>
runtimeStyleは CSSでいうところの!importantと考えることができます。
runtimeStyleの値が最優先で処理されるため、
- element.runtimeStyle.left に elementcurrentStyle.leftの値を設定する
- element.style.left に値を代入する
- element.runtimeStyle.left が設定されているので画面の再描画が発生しない
- その隙にpixelLeftからpx単位に変換された値を読み出す
- element.style.leftを元に戻す
- element.runtimeStyle.leftを元に戻す
という手順で、再描画せずに単位の変換が行えるというトリックです。
テストコードを実行すると次のように表示されます。leftとwidthの値は実行する環境で変わりますよ。
left=[10% -> 33], top=[3em -> 48], width=[auto -> 314], height=[3cm -> 113]