• CSSのmarginが相殺する条件を兄弟、親子、空ブロックで分ける

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の条件を照合し、最後に正負の値を計算します。

戻る