夢は小さいほどいいと思っているんです。本気になれるから。

夢を持つことが大事なんじゃなく、本気になるのが大事。(糸井重里)

CSS | marginの相殺とは

http://magnusbenoni.com/content/images/2016/01/margin_collapsing.png

marginの相殺とは?

まず、marginの相殺とはなんなのか、(気取って)MDN の概要を見てみましょう。

ブロックの top と bottom のマージンは結合される(折り畳まれる (collapsed))ことがあり、結合されるマージンのうち大きなほうのサイズを持った一つのマージンになります。この動作は マージンの相殺 (margin collapsing) として知られています。

f:id:pbrsk:20160914151656j:plain

あんま、よくわかんないっすね。

では、噛み砕いて説明してみます。

marginには相殺(margin collapsing)と呼ばれる独特のルールがあり、
発生条件は

  • ブロックレベルの要素で、かつ
  • margin と margin の間に何も無い場合で、かつ
  • 上下のmargin同士が直接触れ合っている場合に

相殺が起きます。

この場合、どちらか幅の大きいmarginだけが残り、小さい方は相殺されます(反映されません)。
同じ幅なら片方だけのマージン幅になります。
繰り返しますが、相殺は「上下マージンだけ」「ブロックレベル要素だけ」の場合に起こります。

相殺が起こらないケース

いろいろな場合がありますので、主なものを見ていきましょう。

左右のマージンは相殺されません

https://gyazo.com/78a4f564ddac1930836c1231e03326af

上記を見てもわかるように、左右のマージンが相殺されるなら margin-left が10pxでも、margin-right が 20pxなので、margin-left 10pxは相殺されます。ですが、10pxにしたら横幅が増えるので、左右のマージンは相殺されないということがわかります。

親の要素に特定のCSSを適用することで、子の相殺が発生しません。

  • border (marginが指定されている方向)

https://gyazo.com/2dc700dc86c11900dbd086570b6c1dc3

  • padding (marginが指定されている方向)

https://gyazo.com/d48bb4b8307a06c00a0cbb95422b6291

  • overflow:hidden, scroll (auto, visibleは適用されない)

https://gyazo.com/81d764e868f06cd8f8ed419d30769c92
親要素に overflow: scroll を当てても同じ挙動をします。

  • position:absolute, fixed (relative, staticは適用されない)

https://gyazo.com/a4d81a1e75e5c52cd16b7727846a665f
(親要素に position:fixed を当てても同じ挙動をします。)

さらに上記以外にも、floatによって相殺が発生しない場合がたくさんあります。

margin と float の関係

marginとfloatは、密接な関係にありますので、合わせて見ていきましょう。

marginのかかっている要素に、floatを指定した場合

親、子に関わらずmarginを指定している要素に、floatを適用すると相殺をしなくなります。floatが指定されると、marginのautoは、必ず数値が0になります。

margin: auto;とfloatを指定した例
https://gyazo.com/44f0ebc42540b2883616bb59219d688e

  • 親か子のどちらかでもfloatを指定すると、親子での相殺が起こらない。
  • floatが指定されると、margin:auto; は絶対的に0になる。
  • 兄弟同士にfloatが指定されていると、相殺が起こらない。

floatを使用すると、その要素のmarginはpaddingのような挙動を行います。
https://gyazo.com/aa2814c3ac9f78256b5d5d3f28cfb8b5

marginのかかっている要素に、floatが隣接している場合

floatが親、子の要素にかかると相殺が発生しません。ただfloatが隣接しているだけなら、marginとfloatで相殺が発生します。以下はその基本的な条件です。

  • floatに隣接
  • 隣接している要素に、marginが指定されている
  • 隣接している要素に、floatが指定されていない

上の条件が全てではありません。様々な影響により、相殺が発生する場合としない場合があるので割愛します。

以下、marginとfloatの相殺の例です。

https://gyazo.com/d41cd8ccfa825faee383b5d0a3541d2e

float: left; にコメントアウトをすると、testクラスのmargin top: 96px;が効くようになります。

img のスタイルに float:left; をコメントアウトすると、floatが無くなるために、
testクラスのdivの margin-topの幅は、写真の底辺から、divまでの幅ということになります。

このfloatとmarginの相殺は、floatを解除するclearプロパティにも関係してきます。

clearは、floatを解除するものではない

「floatを解除する」とよく説明されるclearプロパティですが、clearは、marginの相殺を抑制し、floatの底辺に要素がつくように、margin-topの値を自動調整するような振る舞いを行います。
clear:none;の場合は、通常通りに振舞います。

以下、実例です。

https://gyazo.com/1653ffd61ecb9c43de7dc937b330836d

.clearにmargin-topに100pxも指定しています。本来なら、100pxの間隔が空くはずですが、float:leftを指定したimgの底辺にくっついてしまっています。

これはclearによる仕様です。clear:left;を指定したことによって、margin-topが自動調整されて、float:left;の指定された要素の後ろにつきます。
仮に、.clearにmargin-topに1000pxを指定しても、何も変わりません。

さらに、float:right;を指定したピンクの.rightの底辺(marginを含む)には、.clear-rightの上辺が重なっています。この場合、ピンクの.rightの上辺から底辺までのmargin-topを調整している訳ではなく、.clearから.rightの底辺までの距離で、margin-topを調整しています。

clearとmargin-topを同時に適用すると、clearプロパティが優先されるので気をつけて下さい。

相殺を見込んで シンプルな CSSを書けるようになれば、とっても便利ですので、ぜひいろんな事例を覚えましょう。