Site icon Tips Note by TAM

marginの相殺の考察

ニマタです。こんにちは。

cssのプロパティ、margin。
要素間に余白をもたせるときとかに使うあれです。

マークアップエンジニアの方はもれなくご存知だと思います。当たり前のように使っていると思います。
しかし、「marginの相殺」についてもしっかり理解していますか?

しっかりと理解せず使っている方、この記事で今一度しっかり確認しましょう!
しっかりと理解して使っている方、この記事は大丈夫なので関連記事をどうぞ!!!

marginの相殺とは

そもそもmarginの相殺とはなんぞやと。困ったら調べる。Hey Siri!!

https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing

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

なるほど。よくわからない。

ものすごーく平たーく言ってしまえば・・・
「マージンの上下はくっつくことがあるよ!」
くらいになりますかね。語弊は恐れません。

ただちょっと曲者で、
「くっつくことがあるよ」=「くっつかないこともあるよ」(=相殺が起きないこともある)
なんですね。

(主に自分が)しっかり理解できない理由はおそらくここです。あるとき突然相殺されて困る。
なので、marginの相殺のされ方、相殺が起きる条件をコードを書きながら確認していきます。

百聞は一見に如かず。

ということで、まずは簡単な例から確認してみます。

相殺条件A:隣接兄弟要素

上下にならんだ要素の margin は相殺されるよ

ってことです。コードで確認します。

See the Pen QKwbLm by nimata (@nimata) on CodePen.

赤い要素(上)は margin-bottom に 30px 指定しました。
青い要素(下)は margin-top に 100px を指定しました。

相殺が起きて、要素間は大きい方の 100px になっているのがわかります。

これくらいは簡単だぜ。はい次。

相殺条件B:親要素と先頭の子要素

親要素の margin-top と子要素の1つ目の margin-top で相殺がおきるよ

1つ目の、とか複雑に感じますが、要は要素の上辺ってことですね。

See the Pen JRoJJy by nimata (@nimata) on CodePen.

赤い要素(上)は margin 指定なしです。
青い要素(親要素)は margin-top に 10px を指定しました。
緑の要素(子要素)は margin-top に 100px を指定しました。

相殺が起きて、赤い要素と青い要素の間は 100px になっているのがわかります。

簡単だぜ・・・といいたいところですが、実はちょっと条件があって

ブロックが、その margin-top とその先頭の子要素の margin-top を分けられるような、ボーダー、パディング、インラインコンテンツ、フロートの解除 (clear) のいずれも持たない場合

に限ります。
文章の難易度跳ね上がりますが、コード見ればわかりやすいかと。

See the Pen ORPgbA by nimata (@nimata) on CodePen.

青い要素(親要素)に border-top を追加しました。

相殺が起こらず、緑の要素(子要素)の margin-top に 100px、
青い要素(親要素)と赤い要素の間は 10px になっているのがわかります。

「マージンはくっつくことがあるよ!」
なのですが、border があるので、そもそもくっつきようがないってことですね。
境界線はっきり存在しているので、margin はちゃんと分けられますよ的な。

仕組みがわかれば簡単だぜ。はい次。

相殺条件B':親要素と末尾の子要素

さきほどの条件の margin-bottom のパターンなのでだいたい大丈夫なんですが、条件がちょっと変わります。

ブロックがその margin-bottom とその末尾の子要素の margin-bottom を分けられるような、ボーダー、パディング、インラインコンテンツ、高さ (height)、高さの最小値 (min-height) のいずれも持たない場合

margin をわける border などがあると相殺されない、までは同じです。そのあとの

高さ (height)、高さの最小値 (min-height) のいずれも持たない場合

ここが margin-top と違います。

参考:相殺おこる

See the Pen ORPgRa by nimata (@nimata) on CodePen.

参考:相殺おきない

See the Pen EgajPq by nimata (@nimata) on CodePen.

親要素の height を auto に設定したものと、30px に設定したものです。

赤い要素との間が変わっているのがわかります。
margin-top のときは height の指定は関係ありませんでした。ここ注意です。テストには出ませんが、ハマるポイントになりそうです。

簡単ではないが、理解できたぜ。はい次。

相殺条件C:空のブロック

ブロックが、その margin-top と margin-bottom を分けられるような、ボーダー、パディング、インラインコンテンツ、高さ (height)、高さの最小値 (min-height) のどれをも持たない場合

そんなんありえる?と思いつつ、とりあえずコード書きました。

See the Pen ORPVjz by nimata (@nimata) on CodePen.

pタグには margin はありません。
divタグに margin-top を 10px、margin-bottom を 20px 設定しています。

divタグの上下の margin が相殺されて、(そしてdiv自体にはなにもないので、)pタグの距離が 20px になっています。
あれですね。動的なサイトやページだと、こんな感じのコードになることがあるのかもしれませんね。

例外なく例外は存在する

セール期間にセール除外品があるように、
ジャンプが土曜日に発売することがあるように、
物事には例外がつきものです。

marginの相殺にも、例外があります。

確認しておきます。

float

floatしている要素は、相殺が起きません。

See the Pen qaEjrx by nimata (@nimata) on CodePen.

赤い要素(上)は margin-bottom に 10px 指定しました。
青い要素(下)は margin-top に 10px を指定しました。

本来であれば、相殺されて要素間は 10px のはずですが、ここでは20pxになっています。

floatした要素を「浮動する要素」「浮いている」なんていうけど、相殺ルールからも浮いている。

position

absolute と fixed を指定された要素は相殺されません。
というか、相殺うんぬん以前に、絶対位置で指定してますからね。自分中心ですから。たぶんB型。

ちょっと注意ですが、absolute などを指定した要素同士は相殺おきませんが
その要素の子要素同士では相殺おきます。

See the Pen QKwAdG by nimata (@nimata) on CodePen.

まとめ

marginの相殺について確認してきました。

1つずつ確認する分には、そこまで難しいことではなかったですね。
が、実際には親同士の相殺、親子の相殺、floatなどの影響されない要素、さらにはネガティブマージンなんかもあって複雑になっていくと思います。
CSS設計の段階から、ちょっと意識しておくといいかもしれませんね。

長くなってしまいました。最後まで読んでいただいてありがとうございました。よき相殺ライフを!