marginの相殺について

「CSS3のbox-sizingがいい!」でレイアウトに影響を与えるpaddingとborderの考え方を確認しましたが、 ここではボックスモデルのもっとも外側にあるmarginの動作について確認していきます。

margin

marginで特に注意する必要があるのは、ボックスの上下(top,bottom)に当たるmarginです。

2つのボックスが上下に並ぶ場合、topとbottomのmarginは大きいサイズのmarginを残した形で 表示される仕様となっています。これをマージンの相殺といいます。

マージンの相殺は、必ず発生するわけではなく条件があるので順に確認していきます。

隣接兄弟要素

上下に並ぶ同一階層のマージンは相殺されます。

<div class="box1"></div>
<div class="box2"></div>
.box1 {
    margin: 100px 100px;
}
.box2 {
    margin: 50px 100px;
}

隣接兄弟要素マージン相殺のイメージ

上側のボックス(box1)には100pxのmarginを指定し、下側のボックス(box2)にはmargin-top及び margin-bottomに50pxのマージンを指定しています。ブラウザでの表示は、下側の50px(小さい方)が相殺され2つの ボックスの余白は100pxとなります。

親要素と先頭の子要素

親子関係にある要素同士も次の条件を満たした場合、マージンが相殺されます。

ブロックが、その margin-top とその先頭の子要素の margin-top を分けられるような、ボーダー、パディング、インラインコンテンツ、フロートの解除 (clear) のいずれも持たない場合
<div class="box1">
    <p class="child">子要素</p>
</div>
.box1 {
    margin: 50px 50px;
}
.child {
    margin-top: 100px;
    margin-bottom: 100px;
}

隣接兄弟要素マージン相殺のイメージ

親のボックス(box1)には50pxのmarginを指定し、子のボックス(child)にはmargin-top及び margin-bottomに100pxのマージンを指定しています。ブラウザでの表示は、親の50px(小さい方)が相殺され2つの ボックスの余白は100pxとなります。

親要素と末尾の子要素

親子関係にある要素でもう一つの条件が親要素と子要素の末尾によるマージンの相殺になります。

末尾の要素の場合、「高さ (height)、高さの最小値 (min-height) のいずれも持たない場合」という 条件が少し増え、次のような条件を満たした場合、マージンが相殺されます。

ブロックがその margin-bottom とその末尾の子要素の margin-bottom を分けられるような、ボーダー、パディング、インラインコンテンツ、高さ (height)、高さの最小値 (min-height) のいずれも持たない場合
<div class="box1">
    <p class="child1">子要素</p>
    <p class="child2">子要素</p>
</div>
<div class="box2">
</div>
.box1 {
    margin: 50px 50px;
}
.child1 {
    margin: 0px;
}
.child2 {
    margin-bottom: 100px;
}

親要素と末尾の子要素マージン相殺のイメージ

親のボックス(box1)には50pxのmarginを指定し、子のボックス(child2)にはmargin-bottomに100pxのマージンを指定しています。 ブラウザでの表示は、親の50px(小さい方)が相殺され最終的なボックスの余白は100pxとなります。

空のブロック

文書構造として考えると無いんじゃないかな?と思われる、空のブロックという条件でも マージンが相殺されます。

ブロックが、その margin-top と margin-bottom を分けられるような、ボーダー、パディング、インラインコンテンツ、高さ (height)、高さの最小値 (min-height) のどれをも持たない場合、top と bottom のマージンは相殺されます。
<p>p要素1</p>
<div class="blank_el"></div>
<p>p要素2</p>
p{
  background-color: #CCFFFF;
  margin: 0;
}
.blank_el {
  margin-top: 50px;
  margin-bottom: 10px;
}

空のブロックによるマージン相殺のイメージ

空のボックス(blank_el)には、何もない状態でmargin-topを50px・margin-bottomを10px指定定しています。 ブラウザでの表示は、空のボックス(blank_el)の10px(小さい方)が相殺され最終的なボックスの余白は50pxとなりp要素の 間隔も50pxとなります。

おまけ

ネガティブマージンが指定された場合、マージンの相殺はどうなるのでしょう?

ネガティブマージン(マイナスのマージン)が絡む場合、相殺されたマージンの大きさは、 一番大きなプラスのマージンともっともマイナスのマージンの合計値がマージンとして確保されます。

あと、例外としてfloatしている要素や絶対位置で指定された要素(position:absoluteやposition:fixed)では、 マージンの相殺は起きません。

まとめ

マージンの相殺意識しながらレイアウトしていくことは、なかなか大変なため margin-topを原則0にして、margin-bottomで縦方向のマージンを制御することで考える要素を少なくすることが できそうです。

p, ul, ol, dl, table, pre, blockquote {
  margin: 0 0 1.5rem;
}
h1 {
  font-size: 32px;
  font-size: 2rem;
  margin-top: 0;
  margin-bottom: 1.5rem;
}
・・・