CSSはレイアウトと装飾を記述し、HTMLで組んだ文書構造を見栄え良く反映させるもの。
というのはみなさんご存知だと思うんですが、初心者がCSSを使おうとする時ってレイアウトより装飾の方に意識が寄りがちですよね。というか自分がそうだっただけなんですけど。それであとあと苦労したのでレイアウトの基礎とか大事ですよーってことをこれからCSSをイジる方に知っていただきたいと思いまして、ボックスモデルをはじめとしたCSSレイアウトの基礎をまとめました。
この記事では要素のボックスモデルをベースに配置の基本ルールを説明しています。今回出てくるプロパティはborder, padding, marginのみです。絶対・相対配置、z-index、フロートなどについては説明していません。(用語として出てくる時はあります。)
ゴリ押してめちゃくちゃな設計を積み重ねていくと、いざ直そっかって時にものすごーく面倒なことになります。(ホンマめんどかった。)「思った通りのレイアウトになってない。でもどこをどう直したらいいのかわからんんん〜。」という状況にならないために、今のうちに理解しておきましょう。
基本のボックスモデル
HTML上のすべての要素はボックスモデルと呼ばれる箱型の領域で区分されてます。CSSでレイアウトを組む際に基本中の基本となるものなので、最初にここをしっかりおさえておきましょう。
ボックスモデルを構成する領域は4つあります。デフォルトでは目に見えるのはコンテンツ部分だけですが、仮に姿が見えなくても(設定していなくても)、存在はしています。
- コンテンツ:内容
- border:ボーダー
- padding:ボーダー内側の領域
- margin:ボーダーから他のボックスまでの余白
ボックスモデルを可視化するとこんな感じです。左のモデル寸法に合わせて例を1つ作ってみました。それぞれ文字の部分がコンテンツ(HTMLに直接記述する部分)、背景が入っている部分がpadding、グレーの枠がborderにあたります。marginは目には見えません。
説明しやすくするために、本記事ではmarginを省いたコンテンツからborderまでの領域をボックス領域と呼ぶことにします。
さて、以上が要素単体のボックスモデルの基本。ここまでは楽勝です。
他の要素と隣接するときmarginの扱いがちょっと厄介だとされていますが、marginの定義を明確にしておけば例外は少なくて済みます。margin=“ボーダーの外側の余白”とだけ書かれていることが多いのですが、これが初心者を誤解させたり混乱させたりする原因の1つになってる気がします。結局どこからどこまでやねん!!っていう。今はボーダーの外側の余白っつってんだから、相手側もボーダーの外側でしょって思えますけど最初はわからんて〜〜。
最初はmargin=“自分のボックスから直近のボックス領域までの余白”としておいてください。borderがあればそこまで、borderもpaddingもなければコンテンツまでです。以降この定義を使用していくつかのケースを見ていきます。
配置の基本〜上下に隣接しあう要素〜
まず段落pと見出しh2をそれぞれさっきのボックスモデルに当てはめて、こんな風にpaddingとmarginを設定してみます。わかりやすくするためにボーダーは設定せず要素内の余白は上下のみとしています。
で、例えばこんなコードを打ってみたとします。反映結果は出ちゃってますが、ボックスモデルの領域区分がどのようになっているか考えてみてください。marginは直近のボックス領域までの距離ですよ〜。
この左右2つの構図の違いがわかりますでしょうか。コンテンツとpadding領域はどちらも同じですね。左の方はボックスモデルを単純に上から並べていったものでmarginを上下の要素で足し合わせてしまってます。そして右の方は上下の要素のmarginが一部重なり合い、margin=“ボックス領域までの距離”の大きい方の値が有効になっています。これがmarginの相殺と呼ばれるものです。
ここまで理解できれば他のケースもさほど難しく感じることもないかと思います。1つずつ例を見ていきましょう。
入れ子状態での要素の配置(1)
まずdiv要素同士のボックス領域間の余白はmarginの相殺により値の大きい方(div要素-2のmargin-top: 20px;)が有効となります。次にdiv要素-2との入れ子関係にあるh2要素から見て、直近のボックス領域はdiv要素-2のpadding-topです。両者のボックス領域間には他に干渉してくる要素がないので相殺は起こりません。
見かけ上はdiv要素-2とh2要素のmargin-topを足し合わせた値とdiv要素-1のmargin-bottomの間で相殺が起こったようになりますが、paddingに背景などを入れたり、ボーダーを作ってみるとわかりやすいかと思います。
じゃあボーダーもpaddingも指定しない場合はどうなるの?というケースを次に説明します。
入れ子状態での要素の配置(2)
先ほどと同様にdiv要素同士の余白は相殺により20px。div要素-2にpadding-topやborder-topが指定されていない場合、h2要素から見た直近のボックス領域はdiv要素-1のpadding-bottom領域となります。div要素-1のmargin-bottomとh2要素のmargin-bottomで相殺が起こり、div要素-1とh2要素のボックス間の距離は値の大きいh2要素の30pxが有効になります。
仮にdiv要素-2のmargin-topが40pxだった場合は、h2要素のmargin-topは相殺されて、div要素-1とh2要素のボックスの距離は40pxになります。
(文章が用語で埋め尽くされると難しそうに感じますね。)
相殺が起こらない場合
これまではmarginは自分と直近の可視ボックス領域間の距離を示し、値が重なる場合は相殺が起こる。というルールに従ってきましたが、これはブロックボックスがとにかく上から下に配置されていく通常フローでのルールです。floatやflexboxを使用して(通常フローから要素を取り出して)要素を横並びさせた場合については異なります。
図を見る前にポイントを言っておきます。
- 通常フローから外れると上下のmarginの相殺は起こらない。
- 左右に隣接する要素のmarginは相殺されない
こんな感じでflexboxなどを使ってdiv要素-2の中に横並びの要素を配置した場合、(※margin以外のプロパティは割愛してます。)まずdiv要素-1と-2の関係は今まで通りです。これまでのルールだとdiv要素-3,-4のmargin-topは、div要素-1のpadding-bottomまでの距離を示しているはずですが、横並び要素の場合は間に親のmarginが入ってきてしまいます。
これはdiv要素-3,4が通常フローから外れて別フローに乗っちゃってるからとかなんとかなんですけど。いくつも横並びにされたボックスそれぞれをこっちは相殺であっちは〜ってやってるとゴチャゴチャしてワケわからんくなるから頭揃えるルールにしましょっていう認識でいいと思います。
あと隣り合う要素のmarginは相殺せず常に足し合わせます。横並びだと相殺させるメリットないですもんね。
おさらい
以上、ボックスモデルを基礎にした配置ルールでした。ちゃんと図解になってたでしょかね。大事なポイントをまとめておきます。
- コンテンツ、padding、borderまでを1つのボックスと捉える
- marginはそのボックス間の距離を指定し、自分の位置を決めるもの
- ボックス間で互いに指定する距離が異なる場合は大きい方の値が有効となる
- 横並びの時は左右のmarginを互いに重ねない(ボックスモデルを重複なく並べる感じ)
- 例外は感覚的に覚える(部分もある)
細かい部分や応用は使ってるうちに感覚的にわかってくる部分もあるので、まだ必要ないなら無理に覚えなくていいと思います。理論だけ覚えようとすると「何でこんなに例外あんの?ややこしい」って思ったりするんですが、実際に使ってみるとその背景がわかって納得できます。そんな感じで使うようになったらそーいえばこういうのあったな〜と思い出してくれれば幸いでございやす。
コメント