ホーム > HTMLに役立つヒント>
CSS Tips > CSSによるページレイアウトの考察
CSSでページ構成/レイアウトを決める際の問題点と手法について、考察してみました。CSS初心者なので間違いがあるかも。
CSSを使ってページのレイアウト構成をする場合、よくでてくる要望には次のようなものがあります。
これらの要望をすべて満たすのは実は結構難しいです。原因の大半はCSSのwidth指定の解釈がブラウザによって異なること。
CSSでサイドバーやら何やらあるBLOGっぽいページで苦労するのが、ブラウザによるwidth指定の解釈の違いです。ページレイアウトはボックスを積み重ねたり、ボックスの中にボックスを入れたりして積み木のように作ります。
で、ボックスは内容、パディング、ボーダー、マージンの4つのパートでできてます。ボックスモデルを図にするとこんな感じ。
|
margin
|
古いブラウザではボーダー幅(■■)までをwidthの幅と解釈します。width(内容部分+パディング+ボーダー幅)+マージンがボックスの大きさになります。
モダンブラウザでは内容部分(■■)だけがwidthの幅です。width(内容部分)+パディング+ボーダー幅+マージンがボックスの大きさです。
単にブラウザが違うOSが違うというだけでなく、同じブラウザでもバージョンによって解釈が違うのでやっかいっす。
結果、サイドバーとコンテンツ部分がかぶったり、両者の間の隙間が思った通り開いてくれなかったり……。
ポイント1:width指定は表示が崩れる元となる。
以下で示す各ボックスは、それぞれIDとclassの二重構造を取ります。こんな感じ。
<div id="side-a">
<div class="side-a">
ここに内容を書く。
</div>
</div>
二重構造をとったうえで、ID(以下、#ID名で示す)でwidth、classでmargin、padding、borderを指定するのが原則です。こうすると、一度外側のIDでwidthを決めてしまえば、内側のclassで各指定を変更しても、IDをはみ出さないのでwidthのずれを最小限に抑えることができます。最小というだけでずれは残りますが。
次に、よく使われるページレイアウト構成について、説明します。
float指定は簡単にボックスを左右に寄せて表示させることができます。下図のように、floatを使って、入れ子構造で3段組にするのが古典的な手法。一見面倒そうですが、よく見るとそうでもないです。
上下にタイトルとフッタがあり、真ん中が内容部分(#pagebody)です。#pagebodyの中は、さらに二つのfloat(#leftunitと#サイドB)で構成されています。#leftunitは#サイドAと#コンテンツがfloatで左右に配置されています。
<body>
|
この手法では、幅は必ず固定されてしまいます。floatにはwidth指定が必須だからなんですね(widthを指定しないとfloatは無視されます)。よって、float指定ではwidthが固定されるので、ウインドウ幅に合わせて可変にすることはできないというわけ。
サイドバーの領域をフッタまで延ばすのも、この手法ではできないようです。#pagebody部に背景画像を敷くことで「延びたように見せる」手法が使われます。
HTML上ではこんな感じになります。
|
<body>
</body> |
HTML上で、両サイド部よりコンテンツ部を前に持ってこられるため、音声読み上げソフトによる音読など、ユーザビリティが高い利点があります。CSSの特徴をもっとも引きだせる構成といえます。
こちらに見本を置きました。float.html
表示の乱れをなくすには、width指定を無くすのがよい、というわけで、よく使われるのがtableでページレイアウトを指定する手法です。
下の図で、黄色で示した部分はCSSで指定し、白で示した部分はtableで組みます。すると、両サイド部は固定、コンテンツは可変など、かなり自由度が高くなります。ページ全体をtable組みにするのもありです。
これなら、フッタの直前までサイドの領域を延ばすことも簡単に実現できます。見た目の点ではほぼ完ぺき。
<body>
|
しかし、この手法はHTML上でサイドAがコンテンツ部より前に来てしまいます。つまり、ユーザビリティが悪くなるという欠点を持っています。
tableでなんとかコンテンツ部を先に持ってくるため、こんな風にテーブルで組むという方法を無理やり考えてみました。
<body>
|
上と同様、黄色はCSSの構造部、白はtable組の構造部分です。このような構造にすると、HTML上、サイドAは#rightpageの後ろに持ってくることができ、ユーザビリティはよくなります。
が、#pagebody全体としてはやはり横幅が決まってしまいます(#サイドAと#rightpageでfloatを使っているので)。加えてサイドAをフッタまで延ばせず、tableを使う利点が大きくそがれてしまうんですね。大失敗でした(^^;
tableを使わず、width指定を最小限にすることができれば、それがもっとも良さそうです。position指定を使うと、それが可能になります。
この方式は構造もシンプル。複雑な入れ子にする必要はありません。
<body>
|
HTML上の構造もシンプル。コンテンツが前に来るのでユーザビリティも確保できます。
|
<body>
</body> |
positionの指定が理解できるまでちょっとややこしいですが、そこを越えるとラクチンです。positionの指定には次のような値があります。
| static | デフォルト。上位のブックの終わりが起点。top/leftの指定は無効になる。 |
| relative | 相対的な位置指定。staticで表示される位置が起点となる。このブロックに含まれる下位のブロックにabsoluteが指定されると、その起点はこのブロックが始まる位置となる。 |
| absolute | 絶対配置。上位のブロックの始点が起点。裸で書けばbodyが上位ブロックとなるのでページの左上が起点となる。上位のブロックにrelativeが指定されていると、上位のブロックが位置指定の起点となる。 |
| fixed | ブラウザの左上が起点。スクロールさせても位置が動かない。 |
一番のポイントは、「position:relative;」と「position:absolute;」を組み合わせて使うことです。
具体的に考えるとわかりやすいので、上図の#pagebodyとその下位の#コンテンツで考えてみます。
「position:absolute;」は位置指定を絶対位置にします。#サイドAに「position:absolute; top:0px;」という指定をすると、位置指定の起点はページの左上ですから、#サイドAはページの一番上に表示されます。
ところが、ここで#サイドAの上位にある#pagebodyに、位置指定の起点を変更する「position:absolute;」を指定すると、起点は#pagebodyが始まる位置に移動します。すると、#サイドAは#pagebodyが始まる位置に表示されます。
このことだけわかれば後は簡単。簡単にまとめると次のように指定すればよいだけ。
| #pagebody | position:relative; |
| #コンテンツ | marginで左右に#サイドA/B文の空きを指定 |
| #サイドA/B | width:必要な幅; position:absolute; top:0px; left:0px; サイドA right:0px; サイドB |
この方法、コンテンツ部にwidth指定が必要ないため、#containerで幅指定をしなければウインドウの大きさによってコンテンツ部が可変になります。ID/classの二重構造にすると、widthのズレもなく、きちんと表示されます。
しかし、サイドバーを下まで伸ばすことはできません。これは幅を固定にして、背景に画像を敷くしかありません。
「position:absolute;」した両サイドは、言うなれば「独立した存在」になります。フッタを自動的に避けてくれたりしません。コンテンツ部よりもサイドの方が長くなると、(フッタはコンテンツの下に表示されるので)フッタにサイドが被さってしまいます。この点にも注意が必要でしょう。
また、ユーザーが文字の大きさを大きくした場合、ボックスが重なりあってしまうという弱点も持ちます。この点はfloat方式の方が安心。
こちらに見本を置きました。abso.html
見た目とユーザビリティを両立させるのはなかなか難しいことがわかってもらえたと思います。それぞれの特徴を簡単にまとめました。
| 方式 | ユーザビリティ | 可変 | サイドバーを下まで | widthのずれ | ページ構成 |
| float入れ子方式 | ○ | × | △(背景画像) | △ | △やや複雑 |
| table方式 | × | ○ | ○ | ○ | ○単純 |
| ハイブリッドtable |
○ |
× |
△(サイドAが延びない) |
△ |
△やや複雑 |
| 絶対位置指定方式 |
○ |
△ |
△(幅固定の場合は背景画像) |
○ |
○単純 |
それぞれ一長一短あり、どれがいいかは難しいところ。float入れ子方式か絶対位置指定方式をまず検討し、どうしてもという場合だけtableを使うといいでしょう。その場合はユーザビリティが落ちることは覚悟の上、っちゅうことですね。ハイブリッドtable方式はダメダメ君です。