[CSS]marginの相殺を正しく理解しておこう!相殺はいつ起こるのか、相殺を回避するテクニック
Post on:2018年7月11日
marginの相殺について、まずはクイズ。
Aのdiv要素には「margin-bottom: 10px;」を、Bのdiv要素には「margin-top: 30px;」を指定した場合、それらを垂直に配置するとマージンはいくつでしょうか?
What's the Deal with Collapsible Margins?
これは「マージンの相殺(Collapsing Margins)」と呼ばれるものです。
このマージンの相殺とは何なのか? いつどういう条件の時に起こるのか? それぞれどのように回避できるのかを紹介します。
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- marginの相殺についてアンケート
- CSSのmarginがどのように機能するか
- marginの相殺(Collapsing Margins)とは
- marginの相殺はいつ起こるのか
- marginの相殺を回避するテクニック
marginの相殺についてアンケート
わたしは先月、Twitterでアンケートを行いました。
アンケートの結果、30pxと正しい答えに投票した人は39%でした。
この答えが30pxになる理由は、「マージンの相殺(Collapsing Margins)」と呼ばれるCSSの機能によって起こります。
CSSのmarginがどのように機能するか
CSSのマージンがどのように機能するかを理解するために、ボックスモデルを再確認しておきましょう。CSSのボックスモデルは前の記事「Controlling The Box Model」で触れたように、ドキュメントツリーの各要素はコンテンツ、パディング、ボーダー、スペースの4つのエリアで構成された長方形のボックスです。
.box要素を例に見てましょう。
1 2 3 4 5 6 7 |
.box { width: 300px; height: 300px; padding: 50px; border: 50px solid grey; margin: 50px; /* マージンのエリア */ } |
マージンはボーダーの外側で、下図のストライプのエリアです。
マージン: ストライプのエリア
マージンはボックスモデルの他の3つのエリアとは異なり、要素自体の表示には影響を与えません。しかしマージンの相殺のように、Webページに表示される実際のマージンは他の要素の影響を受ける可能性があります。
marginの相殺(Collapsing Margins)とは
マージンの相殺は、垂直マージンを指定した2つのブロックレベル要素が並んだ時に起こります。マージンの相殺が起こると、2つのマージンのうち大きい方(等しい場合はいずれか)が1つのマージンとしてみなされます。
Twitterのアンケートから例を引用します。
2つのdiv要素があり、Aのdiv要素は10pxのmargin-bottomを、Bのdiv要素には30pxのmargin-topを指定します。
マージンを指定した2つのdiv要素
この2つのブロックレベルの要素をマークアップで順番に並べると、下記のように表示されます。
2つのdiv要素を表示
2つの要素の間にあるマージン(10pxと30px)はマージンの相殺が起き、大きい方のマージンである30pxのマージンが残ります。
marginの相殺はいつ起こるのか
原則として、インフロー、ブロックレベル、ボックス間の隣接する垂直マージンは常に相殺されます。これは4つのシナリオで起こります。
ケース1: 親と最初の子の上マージン
margin-topが親要素に指定し、インフローの最初の子要素にも指定した場合、それらのマージンは相殺されます。
1 2 3 4 5 6 7 8 9 10 11 12 |
.parent { margin-top: 30px; height: 150px; background-color: rgb(200,200,200); /* グレー */ } .child { margin-top: 30px; width: 100px; height: 100px; background-color: rgb(250, 219, 92); /* イエロー */ } |
親要素の「margin-top: 30px;」、子要素の「margin-top: 30px;」は相殺され、マージンは30pxで表示されます。
インフローで相殺される隣接する垂直マージン
ケース2: 親と最後の子の下マージン
ケース1と同じように、margin-bottomが親要素に、インフローの最後の子要素にも指定した場合、マージンは相殺されます。
ただし、上マージンとは異なり、下マージンは親の高さがautoの場合にのみ相殺されます。
1 2 3 4 5 6 7 8 9 10 11 12 |
.parent { margin-bottom: 30px; height: auto; background-color: rgb(200,200,200); } .child { margin-bottom: 30px; width: 100px; height: 100px; background-color: rgb(250, 219, 92); } |
親要素の「margin-bottom: 30px;」、子要素の「margin-bottom: 30px;」は相殺され、マージンは30pxで表示されます。
※親要素の高さが、autoの場合のみ。
インフローで相殺される隣接する垂直マージン
ケース3: 兄弟要素の下と上のマージン
このケースは、アンケートで提示した例です。
margin-bottomを1つ目の要素に、margin-topを2つ目の要素に指定した場合、それらの間にあるマージンは相殺されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.sibling-one { margin-bottom: 10px; width: 100px; height: 100px; background-color: rgb(250, 219, 92); } .sibling-two { margin-top: 30px; width: 100px; height: 100px; background-color: rgb(200,200,200); } |
兄要素の「margin-bottom: 10px;」、弟要素の「margin-top: 30px;」は相殺され、マージンは30pxで表示されます。
ブロックレベルで相殺される隣接する垂直マージン
ケース4: 空の要素
最後は要素の高さが0、いわゆる空の要素にmarign-bottomとmargin-topを指定した場合、それらのマージンは相殺されます。
1 2 3 |
<p>This paragraph is before the empty element</p> <div class="empty"><!-- 空の要素 --></div> <p>This paragraph is after the empty element</p> |
1 2 3 4 |
.empty { margin-bottom: 30px; margin-top: 30px; } |
空要素の「margin-bottom: 30px;」と「margin-top: 30px;」は相殺され、マージンは30pxで表示されます。
ボックス間で相殺される隣接する垂直マージン
例外
マージンの相殺が起きない例外も少数ですが、あります。
- Flexbox、Grid、その他のブロックレベルでない要素
- マージンの相殺はブロックレベルの要素にのみ適用されます。つまり、displayプロパティの値がblock, list-item, tableのいずれかの時です。そのため、flexアイテムやgridアイテムや絶対値アイテム、そしてブロックレベルではない要素には適用されません。
- ルート要素
- ルート要素のボックスのマージンは絶対、相殺されません。
- ボーダーやパディングを使ったラインのボックス
- 下図のように、2つの要素間にあるラインのボックス、パディングやボーダーがある場合、相殺されません。ケース1では親と最初の子の上マージンは相殺されましたが、これにボーダーを加えるだけで、相殺されません。
ボーダーを加えると、相殺されない
これがなぜ起きるかというと、親のマージンと子のマージンは直接接触していないことがその理由です。
marginの相殺を回避するテクニック
マージンの相殺がいつ発生するのかを正しく理解していないと、思い通りのレイアウトができないで困ることがあります。それを回避するための第一歩は、その相殺がどのケースなのか、正確に理解することです。
空要素や親子要素で起きるマージンの相殺は、実際には避けることができません。これに対応する唯一の方法は、要素の間にボーダーなど何かを挿入することです。ほかの対応方法としては、要素のプロパティをブロックレベル以外(flex, gridなど)に変更します。
隣接する兄弟要素で起きるマージンの相殺は、CSSのスタイルを変更することで回避することができます。個人的には「Single-direction margin declarations」に書かれている「マージンの指定は単一方向にする」に従うことを好みます。このルールはマージンの相殺を回避するだけでなく、ほかにも利点があります。
sponsors