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の値が最優先で処理されるため、

  1. element.runtimeStyle.left に elementcurrentStyle.leftの値を設定する
  2. element.style.left に値を代入する
  3. element.runtimeStyle.left が設定されているので画面の再描画が発生しない
  4. その隙にpixelLeftからpx単位に変換された値を読み出す
  5. element.style.leftを元に戻す
  6. element.runtimeStyle.leftを元に戻す

という手順で、再描画せずに単位の変換が行えるというトリックです。


テストコードを実行すると次のように表示されます。leftとwidthの値は実行する環境で変わりますよ。

left=[10% -> 33], top=[3em -> 48], width=[auto -> 314], height=[3cm -> 113]