私も最近はレスポンシブ案件を受けることも多くなってきていまして、レガシーIEに対応する際は個人的な経験からRespond.jsを使用しています。(masonry.jsを実験した時にcss3-mediaqueries.jsは問題があった)

PCサイズの時だけにjQueryのプラグインを適用したい、といった状況で、ブレークポイントに合わせてJavaScriptを発火する必要があったのですが、どうもIE8だけブレークポイントが違っているので調べてみました。

ブラウザのさまざまなサイズを取得する

これまでサイズ取得には、もはや何のためのハックなのかわからない

document.clientWidth || document.documentElement.clientWidth

といったコードを使っていたのですが、ここで一度、ブラウザのサイズを取得する方法を整理したいと思い、ちょっとしたツールを組んでみました。

Screen size checker

Macではブラウザに枠がなく、スクロールバーも浮いているためほとんどのプロパティが同じ数値になります。問題になるのはWindows、特にIEのバージョン間での違いですね。

最近の環境では以下のようなプロパティが有効な模様です

(1)ブラウザ枠の外側の幅と高さ

  • window.outerWidth / window.outerHeight ※IEはバージョン9以上

(2)ブラウザ枠の内側の幅と高さ

  • window.innerWidth / window.innerHeight ※IEはバージョン9以上
  • document.documentElement.offsetWidth / document.documentElement.offsetHeight

(3)表示領域の幅と高さ(スクロールバーを含まない)

  • document.documentElement.clientWidth / document.documentElement.clientHeight ※html要素
  • document.body.clientWidth / document.body.clientHeight ※body要素
  • document.clientWidth / document.clientHeight

※検索するとdocument.width/document.heightというプロパティをちらほら見かけますが非推奨です(Gecko6.0よりサポート外)。

スクロールバーがない場合、(2)と(3)は同じになるはずですが、IE8では上下左右に2pxの謎の枠があるため微妙に値が異なっています。IE7にも謎の枠があります。こちらはスクロールバーがあろうがなかろうが同じ値になっています(爆

これらを踏まえてRespond.jsにおけるIE8のブレークポイントについて見てみます。

ブレークポイントの違い

見た感じモダンブラウザでは

window.innerWidth / window.innerHeight

が基準になっているようです。 IE8ではこのプロパティは存在しないですが

document.documentElement.offsetWidth / document.documentElement.offsetHeight

で代用することができます。

なので、これを使えばいいかというと、そうはいかない我らがIEです。 Respond.jsはIE8においては

document.documentElement.clientWidth / document.documentElement.clientHeight

を見て切り替えているようです。(まあ、これはIEのせいではないですけど)

Respond.jsのソースを見るとの98行目で

var name = "clientWidth", docElemProp = docElem[name]...

となっているのは見えるのですが、ソース内にwindow.innerWidthdocument.documentElement.offsetWidthは見当たりません。内部で<body>タグをcreateElementして使っているようなので、そのフェイク<body>のサイズがIE8だと違っちゃうってことなんでしょうか。

結論として、IE8も含めてRespond.jsのブレークポイントと同期するには

window.innerWidth || document.documentElement.clientWidth

を監視すればよい、ということになります。

IE8ではブレークポイントが若干違ったままになりますが、今回の目的はメディアクエリーと同期してJavaScriptを発火することなのでそこのタイミングが同じでありさえすれば良いのです。

ブレークポイント自体を一致させるとなると、ソースをいじる必要がありそうです。

※互換モードとかは知りません