IE8以下でレスポンシブWebデザインを実現するRespond.js
レスポンシブWebデザインはディスプレイサイズ(特に横幅)に合わせてデザインを最適化する事で、1URLで全てのデバイスに対応できることが強み。
導入することで最も威力を発揮するデバイスはスマートフォンですが、マーケティング的にIEでもレスポンシブWebデザインが機能(閲覧可能)した方が良いケースもあるでしょう。
そういった状況下でお勧めするのがRespond.js。
Respond.jsとは
IE6~8でCSS3 Media Queries(max-widthとmin-width)を解釈可能にするpolyfill(※)。
ネイティブで非対応の機能をpolyfillで実現すると、大半が処理が重くなったり動作が不安定など実用的ではないですが、Respond.jsは高速かつ安定しています。
※非対応のブラウザに相応のインターフェースを実装
Respond.jsデモ
当社オフィシャルサイトへRespond.jsを導入していますのでIE7or8でご覧ください。
意図的にIE6には対応しておりませんので、予めご了承ください。
Respond.jsの仕組み
ソースを斜め読みしただけですが、大まかには以下の処理を行なっている。
間違い・勘違いがあればご指摘ください!
- media属性付きのstyle要素を挿入してMedia Queries対応チェック
- 対応していなければCSS(link要素のみ。style要素はNG)を解析してMedia Queries(max-width or min-width限定。@mediaから始まるブロック)を読み取る
- window.onresizeイベントで横幅を監視して、上記2の条件と一致するstyle要素を生成・挿入する
利用方法
link要素以降でRespond.jsを読み込むだけで利用可能。
// 従来通り読み込み。@media~ブロックを解析 <link href="style.css" rel="stylesheet"> // media属性で指定もOK <link href="smartphone.css" media="screen and (max-width: 320px)" rel="stylesheet"> // Respond.js読込 <script src="respond.min.js"></script>
上記以降でスタイルシートを動的に追加した場合はAPIで対応可能。
<script> // スタイルシート追加 var link = document.createElement( 'link' ), head = document.head || document.getElementsByTagName( 'head' )[0]; link.src = 'tablet.css'; link.rel = 'stylesheet'; head.appendChild( link ); // パーサを再実行 respond.update(); </script>
ハマりどころ
仕様通りの動作ですが、知らないとハマるポイントをご紹介。
- style要素は対象外
- link要素かつrel属性がstylesheetに設定されたもののみ解析。
- CSSファイル内の@importは無効
- HTMLファイルから直接link要素で読み込まれたCSSファイルのみ対象。
最後に
ソースを読んでいてIEでstyle要素を動的に生成するには下記方法が有効だと知りました。
他にもJSのノウハウが詰まっているので自身でソースを読まれることをお勧めします。
// モダンブラウザはこっちでOK var style = document.createElement( 'style' ); style.innerHTML = 'body { background: #000; }'; document.getElementsByTagName( 'head' )[0].appendChild( style ); // 上記方法だとIEはNG。下記コードならOK var div = document.createElement( 'div' ); // ­は削除不可。最初にstyle以外のノードが必要 div.innerHTML = '­<style> body { background: #000; } </style>' document.body.appendChild( div );
コメント(2)
IEにおけるstyle要素の動的生成に関して、style要素はHTML5のscoped属性がない場合はhead要素内にしか存在できない、つまりdocument.bodyへの追加はInvalidなので、もし本当に動的生成が必要であれば下記URLに記述したようなコードが良いのではと思いました。
https://gist.github.com/2574404
>安倍 英樹さん
コメントありがとうございます。
仰る通り、本当に動的生成が必要ならば紹介頂いた方法の方が良さそうです。
(後日修正して記事に追記させていただきます)
ご指摘頂いて、Respond.jsのソースを読み直したのですが、
最初のMedia Queries対応チェックではbody要素の中にstyle要素を追加しているのですが、直後に削除しているようです。
一時的な挿入のため手軽な方法を選択しているのかもしれません。
ただ、その後のstyle要素の動的生成は阿部さんと同様の実装がされていました。
・Respond.jsソース(255~272行目辺り)
https://github.com/scottjehl/Respond/blob/master/respond.src.js#LC255
appendChildはIEで不都合が起きることがあると聞いたことがありますが、
Respond.jsではinsertBeforeを利用しているみたいです。
私もappendChildは頻繁に利用するので一度原因を調べてみたいですね。
余談ですが、IE9+及びモダンブラウザはdocument.headでhead要素が取得できるので
var head = document.head || document.getElementsByTagName( 'head' )[0];
とする事で僅かながらパフォーマンスアップできるかもしれません。
既にご存知だったらすいません。