CSSのmarginが相殺する条件を兄弟、親子、空ブロックで分ける
公開日: 執筆:佐藤
CSSでは、通常フローにあるブロックの上下marginが隣り合うと、一つのmarginへ相殺されることがあります。margin-bottom: 30pxとmargin-top: 20pxを指定しても、要素間が50pxになるとは限りません。正の値だけなら、大きいほうの30pxが残ります。
調べる順序は、横方向ではなく上下方向か、同じブロック整形コンテキストに属するか、境界の間にpadding、border、行ボックス、clearanceがあるか、です。その後で、兄弟、親子、空ブロックのどの組み合わせかを確認します。
隣接する兄弟の上下marginは大きい正の値が残る
次のHTMLとCSSは、相殺の計算を説明するための仮例です。実在するサイトのコードではありません。
<section class="first">一つ目の内容</section>
<section class="second">二つ目の内容</section>
.first {
margin-bottom: 30px;
}
.second {
margin-top: 20px;
}
二つのsectionが通常フローのブロックであり、同じブロック整形コンテキストに属するなら、一つ目の下marginと二つ目の上marginは隣接します。間隔は足し算の50pxではなく、二つが相殺した30pxです。
W3CのCSS 2.1仕様は、同じブロック整形コンテキストにある通常フローのブロックで、間に行ボックス、clearance、padding、borderがない上下marginを隣接と定義しています。左右のmarginは相殺しません。
後の兄弟にclearanceがある場合は、前の兄弟の下marginとの相殺条件が変わります。float、絶対配置、inline-blockのmarginも通常の兄弟と同じようには相殺しません。値を増減する前に、その要素が通常フローのブロックかを確認します。
親と最初の子はpaddingとborderがなければ上marginが相殺する
相殺は兄弟だけでなく、親子でも起きます。
<div class="panel">
<h2 class="panel-title">見出し</h2>
</div>
.panel {
margin-top: 20px;
}
.panel-title {
margin-top: 30px;
}
panelに上borderと上paddingがなく、panel-titleが最初の通常フローのブロックでclearanceを持たない場合、二つの上marginは相殺します。正の値だけなら30pxが残り、子の上marginが親の外側へ出たように見えます。
親の内側に必ず間隔が必要なら、marginを増やす前に境界を決めます。たとえば、親へ0より大きいpadding-topを指定すると、親の上marginと子の上marginは隣接しません。幅が0ではない上borderも同じく境界になります。見えないborderを相殺対策だけのために加えると、寸法計算まで変わるため、デザイン上必要なpaddingまたはborderを選びます。
最後の通常フローの子の下marginも、親のheightがautoで、下paddingと下borderがない場合には親の下marginと相殺することがあります。上側だけを直して終わらず、最初の子と最後の子を分けて確認します。
空ブロックは自身の上marginと下marginが相殺する
内容のないブロックでは、自分の上marginと下marginが隣接する場合があります。
<div class="spacer"></div>
.spacer {
margin-top: 20px;
margin-bottom: 30px;
}
この仮例で、spacerのmin-heightが0、heightが0またはautoであり、上下のpaddingとborder、行ボックス、通常フローの子がないなら、上下marginは相殺します。正の値だけなので結果は30pxで、50pxの空白にはなりません。
空ブロックの上下marginは、その前後にあるブロックのmarginまで一組として相殺する場合があります。複数のmarginを二つずつ足すのではなく、どこまで隣接しているかを先に追います。空白だけを作る要素へ上下marginを持たせるより、間隔を所有する要素を一つ決め、その要素のmarginまたは親のpaddingで指定すると判断箇所を減らせます。
負のmarginは正の最大値から負の絶対値を引く
相殺するmarginがすべて正なら、最も大きい値が結果です。負の値が混ざる場合は、正の最大値から、負のmarginで絶対値が最も大きい値を引きます。すべて負なら、絶対値が最も大きい負の値が残ります。
| 相殺する値 | 計算 | 結果 |
|---|---|---|
30pxと20px |
正の最大値 | 30px |
30pxと-10px |
30px - 10px |
20px |
-20pxと-10px |
0 - 20px |
-20px |
負のmarginはCSS 2.1で認められていますが、相殺の原因を見えにくくします。位置を詰める目的が明確で、前後の要素を含む計算を説明できる場合に限って使います。
BFCは親子の相殺を止めても兄弟間を一律には止めない
ブロック整形コンテキストは、英語のBlock Formatting Contextを略してBFCと呼びます。CSS 2.1の視覚整形モデルでは、float、絶対配置、inline-block、table-cell、overflowがvisible以外のブロックなどが、内容のための新しいBFCを作ります。
新しいBFCを作る要素のmarginは、その通常フローの子のmarginとは相殺しません。たとえば親へoverflow: hiddenを指定すると、親子のmargin相殺を止められます。ただし、はみ出した内容も隠れるため、marginだけを直す指定として機械的に使えません。
BFCを作るブロック自身が、外側の通常フローから外れるとは限りません。overflow: hiddenを持つブロックでも、前後の通常フローの兄弟との上下marginは相殺する場合があります。「BFCならすべてのmargin相殺がなくなる」と覚えず、親子の境界と兄弟の境界を別々に見ます。
まず、開発者ツールで問題の要素と前後の要素を確認してください。上下marginを持つ二つの境界を選び、兄弟、親子、空ブロックのどれかを決めます。次にpadding、border、行ボックス、clearance、通常フロー、BFCの条件を照合し、最後に正負の値を計算します。
関連記事

