IEの getBoundingClientRect() が2pxずれる現象への対策

けっこう前に2pxずれる現象への対策を書くって言ったまま放置してた件の回答。ちなみに以前書いたエントリーはこれ。getClientRects()とgetBoundingClientRect()の違いとその動作のまとめ - DenkiYagi

結論/対策

getBoundingClientRect() で取得できる値の座標から以下の値を減算する。

document.body.scrollLeft || document.documentElement.scrollLeft;
document.body.scrollTop  || document.documentElement.scrollTop;

※解説はしないけど、値を取得する順番を逆にすると正しい値が取得できない事があるので注意。
IE6でもIE7でもこの方法でOK。

実装サンプル
function getRect(elem) {
    var rect = elem.getBoundingClientRect();

    var pageBorderLeft = document.body.scrollLeft
                      || document.documentElement.scrollLeft;
    var pageBorderTop  = document.body.scrollTop
                      || document.documentElement.scrollTop;

    return {
        left  : rect.left   - pageBorderLeft,
        top   : rect.top    - pageBorderTop,
        right : rect.right  - pageBorderLeft,
        bottom: rect.bottom - pageBorderTop
    }
}

原因

だいたいこんな感じ。

  • getBoundingClientRect() はブラウザの表示領域の左上から値を取得している訳ではない
    • html要素 or body要素のborderの内側領域の左上から取得している
  • IEはhtml要素 or body要素にデフォルトで2pxのborderが存在している
    • 標準モードだと document.documentElement.scrollLeft / scrollTop
    • 互換モードだと document.body.scrollLeft / scrollTop
    • border-widthはCSSで変更可能

疑いを持つ人は適当なHTMLに以下のようなCSSを読み込ませてみるといいよ。

html {
    boder: 10px solid red;
}
body {
    boder: 10px solid blue;
}