css による疑似フレーム IE6 標準準拠モード完全対応版 (CSS ハック / JavaScript未使用)
css のみを使って、ヘッダ / メニュー / フッタをスクロールしないように固定して疑似フレームを表現する手法は position: fixed による方法が広く知られています。
この方法は、手軽に疑似フレームを表現できる一方で、IE6 が対応していないという非常に残念な現実があり、対象ブラウザから IE6 を完全に外してしまえるような状況ならともかく、(特に仕事の上などでは) IE6 を対象から外せない事も多いので頭痛の種でした。
IE 独自拡張の expression を使って、fixed に近い状況を作り出す技が色々と開発されているのですが、どうも自分にしっくり来るものがありませんでした。
そこで、下記の条件を満たすやり方を開発したので公開します。
- IE6 標準準拠モードで動作させる
IE 7 に関して、fixed を正しく動作させるために標準準拠に関しては重要な要件 - css ハックは使わない
将来のブラウザのバージョンで異変が起きる可能性を排除 - メニューもフッタも固定する
ヘッダだけの固定であればシンプルな実装が他にもある - 無駄な HTML マークアップを追加しない
HTML 自体は fixed 対応ブラウザのみの場合と同様 - 極力シンプルに記述できる
冗長なコードを書いて無理矢理つじつまを合わせるような事はしない - スクロール時に画面がちらつかない
expression の使い方によってはダサイ見た目になってしまうのでそれを回避 - IE6 以外のブラウザに影響を与えない
当然
論より証拠。まずはサンプルを見て下さい。
このページでは、ヘッダ / メニュー / フッタの 3 つがスクロールに対して固定されています。
fixed 対応ブラウザでは fixed で実現され、IE6 に関しては expression をちょっとだけ使っています。
まず、一般的な fixed 部分について簡単に解説します。
<div id="header">ヘッダ</div> <div id="menu">メニュー</div> <div id="contents"> START<br /> コンテンツ...<br /> END<br /> </div> <div id="footer">フッタ</div>
HTML については、非常にシンプルです。
各部位ごとに異なる id を指定した div があるだけです。
css のうち装飾に関わる部分を除くとこんな感じです。
* {
margin: 0;
padding: 0;
}
#header {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 24px;
z-index: 3;
}
#menu {
position: fixed;
left: 0;
top: 0;
width: 150px;
height: 100%;
padding-top: 24px;
z-index: 2;
}
#contents {
padding: 24px 0 24px 150px;
z-index: 1;
}
#footer {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 24px;
z-index: 3;
}
#header / #menu / #footer については、fixed で固定されています。
#menu / #contents では padding を指定する事で、重なってしまう部分が隠れないようにしてあります。
fixed 対応ブラウザであれば、これだけで疑似フレームの完成です。標準準拠モードになるよう、DOCTYPE を指定しているので、IE7 であっても同様に動作します。
続いて、IE6 向けの設定です。
<!--[if lt IE 7]>
<style>
#header, #footer, #menu {
position: absolute;
}
#contents {
overflow: auto;
height: expression((document.documentElement.clientHeight - 48) + 'px');
}
#menu {
height: expression((document.documentElement.clientHeight - 48) + 'px');
}
</style>
<![endif]-->
意外なほどシンプルではないでしょうか?これだけです。
<!–[if lt IE 7]> から始まる記述は IE 独自拡張の条件付きコメントで、IE 以外のブラウザでは完全に無視されます。
ここでは、IE 7 未満の IE を指定して専用の記述を読み込ませています。
どうせ IE に対してのみ動作を変えるのであれば、変に CSS ハックを使うよりよほどリスクが少なく確実な方法だと思います。
position: absolute; は、fixed に対応していない IE6 のために、設定を上書きしています。
css の設定は後勝ちなので、IE6 向けの設定は fixed 向けよりも後に書く必要があります。
#contens / #menu にある、expression がポイントです。
expression は、filter 関数などと同様の IE 独自拡張で、任意の JavaScript コードを使用して動的に css の値を指定する事が出来きるものです。
ここでは、#contents / #menu の高さを、ウィンドウ内部の高さからヘッダとフッタの分を引いた値に指定しています。
これにより「メニューとコンテンツ部分がウィンドウからはみ出ない」という状況が生まれ、実質的な疑似フレームになります。
また、expression 関数は、ウィンドウサイズが変更された際などにも自動的に再計算されます。
ヘッダとフッタの top や left を expression 関数で設定する手法も見かけたのですが、これだとスクロール時にちらつきが出るのでイマイチです。
この手法は、ウィンドウ自体がスクロールしないよう抑制し、コンテンツ部分のみを overflow: auto; でスクロールさせるという逆転の発想で実装されています。
ソースの全容はサンプルをダウンロードして確認して下さい。
また、実際に使用する時はもちろん、css を直接 HTML に書かず、外部ファイルに切り出した方がよいです。
4件のコメント »
RSS feed for comments on this post. TrackBack URL
※このコメントはメールによるお問合わせについて、ご本人の許可を得て転載しています。
「cssによる疑似フレーム~」利用させていただきました。とてもきれいにレイアウトできました、ありがとうございます。
ただひとつ。私はMac Userなので気にならないのですが、Win Userからの指摘があり質問させてください。
スクロールバーに色を付けたりデザインを変更したり、これがいつものように反映されません。
ちなみにこれが外部ファイルで落合さまの「cssによる疑似フレーム~」が直接 HTML に書いています。逆にもしましたがダメでした。一緒に外部、が正しいのでしょうか。
あまりよくわかっていなくてごめんなさい。よろしくご指導お願いいたします。
ご質問の件ですが、css が外部ファイルかどうかについては無関係です。
ソースを見ないと確定的な事は言えませんが、IE6 のみ異なる方法で疑似フレームを実現しているために発生していると思われます。
IE6 以外の position: fixed で実現している疑似フレームは、ヘッダ・フッタ・メニューを固定して、それ以外がスクロールする形です。
ですので、フレームで表示されるスクロールバーは、body に対するスクロールバーなので、body のスタイルを指定すれば反映されます。
一方 IE6 では、コンテンツ部分 (#contents) の height を伸縮させて、必ずウィンドウ内に収まる大きさにする事で、#contents 部分がスクロールする形です。
ですので、フレームで表示されるスクロールバーは、#contents に対するスクロールバーなので、body のスタイルを指定しても反映されません。
スタイルを指定する対象が IE6 の時だけ違うという点が恐らく原因ではないかと思います。
たいへんうまくいきました。
細かいことで恐縮ですが、menuが下に長い場合、menuにスクロールを表示させようと、
overflow: auto;
をセットしたのですが、スクロールバーの上下が切れます。
かんたんに回避できる方法があったら教えて頂けないでしょうか。
お手すきの時で結構ですので、よろしくお願いいたします。
#menu の padding-top の代わりに、margin-top を指定する事で、スクロールバーの上は、隠れないようにする事が出来ます。
ただそうすると、height: 100%; のせいで、#menu の下がウィンドウからはみ出る状態になってしまいます。(100% + margin-top 分の高さになる)
ですので、スクロールの下を隠れないようにしようと思った場合、#menu の高さは 100% よりも小さくする必要があるのですが、これはウィンドウサイズに合わせて伸縮させなければなりません。
そうするとどうしても JavaScript で操作しないといけなくなりますので、CSS だけで実現するという趣旨からは外れてしまいます。
この方法で対応する場合、別途 JavaScript の事を調べてみて下さい。
一方、フッターの固定が不要でも良ければ、#header のみ position:fixed で、#menu と #contents は float:left で横に並べて、#footer を clear:left: する事でも、綺麗な見た目にする事が出来るかと思います。
こちらの方法でしたら、CSS だけで実現できますし、類似の解説ページもたくさんあるので探してみて下さい。