解 説

マージンの相殺について

上下のマージンは相殺される仕組みになっています。相殺によって、少ない方の数値が打ち消されます。

次のような例を考えてみましょう。

CSSの設定

  #first {
    margin:20px 0;
  }
  #second {
    margin:30px 0;
  }

HTMLの設定

<div id="first">ああああああ</div>
<div id="second">いいいいいい</div>

上の例では最初のdivのマージンは上下20px、次のdivのマージンは30pxです。「ああああああ」と「いいいいいい」の間には50pxのマージンが空きそうですが、実際は30pxしか空きません。相殺によって、少ない方の数値が打ち消されたのです。これがマージンの相殺です。

ブロック要素では通常フローしたブロック要素は必ずその下に次のブロック要素が来ます。その為通常フローしたブロック要素同士の場合は上下のマージン相殺しか起こりません。つまり横には並ばないので左右のマージン相殺はそもそも起こらないのです。
ではフロートして横並びにした場合は親、子に関わらずmarginを指定している要素に、floatを適用すると相殺をしなくなります。

ここまでは少し勉強した方はよくご存知のことですね。

入れ子状態のマージンの相殺について

悩ましいのは親子関係の入れ子状態にある場合のマージン相殺です。上下のマージンの相殺はちょっと複雑な挙動になります。ただし、横方向のマージン相殺はありません。

次の例をみてください

この部分がヘッダー

上のサンプルのソースは以下です。

CSS側

#first {
	background-color: #CFF;
	width: 300px;
	height: 300px;
}
 #sec {
	background-color: #FFC;
	border: 1px solid #F30;
	margin-top: 30px;
}

HTML側

<div id="first">
	<div div="sec">この部分がヘッダー</div>
</div>

ブロック要素を入れ子状態にして内側のブロック要素「この部分がヘッダー」に上マージンを設定して30pxだけ空間を空けたいと思うのだが、ブロック内でマージンがかかりません。本来なら30pxだけ空間が空いて水色の背景が30pxだけ見えるはずなのですが、「この部分がヘッダー」に変化は見られません。
そして、さらに外側のマージンよりも内側のマージンが大きければ内側のマージン分だけ、ここでは30pxだけ外側にマージンがついてしまうという変な挙動になってしましいます。

この入れ子状態のマージン相殺は制作の時の悩みの種になることが多いです。しっかり理解しておきましょう。

解決方法は外側のブロック要素にボーダーをつけるか、paddingをつけます。
先ほどの例で外側のdivにボーダーをつけてみましょう。以下のとおりです。

この部分がヘッダー

#first {
	background-color: #CFF;
        border:solid #000 1px;
	width: 300px;
	height: 300px;
}
 #sec {
	background-color: #FFC;
	border: 1px solid #F30;
	margin-top: 30px;
}