要素と要素の間に隙間を作るmarginプロパティですが、使い方を誤ると面倒な現象がいくつか発生します。
今日はmarginプロパティを使用する際の注意点をいくつか解説します。
marginとは何か
marginは、要素の外側に隙間を作るプロパティです。
要素の隙間を作るプロパティはいくつか存在しますので、併せて紹介しましょう。
・margin
要素の外側に隙間を作る
https://developer.mozilla.org/ja/docs/Web/CSS/margin
・padding
要素の内側に隙間を作る
https://developer.mozilla.org/ja/docs/Web/CSS/padding
・border
要素の境界に隙間を作る(線を書く)
https://developer.mozilla.org/ja/docs/Web/CSS/border
<div class="outer">
<div class="element">
<p class="text">
text
</p>
</div>
</div>
<style>
.outer {
background-color: red;
padding: 1px;
}
.element {
padding: 20px;
border: 20px solid lightgreen;
margin: 20px;
background-color: blue;
}
.text {
background-color: white;
}
</style>
要素に隙間を作るプロパティは、ざっくりと要素の外側から
- margin
- border
- padding
の順に作用していくと覚えておきましょう。
兄弟要素におけるマージンの相殺
さて本題です。先ほど要素の外側に隙間を作ると解説したmarginですが、厄介な性質を持っています。
マージンの相殺と呼ばれているそれが、どういった現象を引き起こすかを見てみましょう。
例えば以下のようなデザインを想定します。
itemとitemの間に40pxの隙間を取りたいとします。
各アイテムの上下に20pxずつmarginをとってやればよさそうなので、試してみましょう。
<ul class="items">
<li class="item">item</li>
<li class="item">item</li>
<li class="item">item</li>
</ul>
<style>
.item {
margin: 20px 0;
background: pink;
padding: 10px;
}
</style>
おや、想定よりも隙間が小さいです。何が起こっているのでしょうか。
chromeのインスペクタで見てみるとわかりやすいです。
インスペクタで見たとき、オレンジ色で表示されているのがマージン領域です。
上の要素と下の要素のマージン領域が、それぞれのある場所に食い込んでいるのがわかるでしょうか。
これがマージンの相殺という現象です。
マージンの相殺の習得 – CSS: カスケーディングスタイルシート | MDN
https://developer.mozilla.org/ja/docs/Web/CSS/CSS_box_model/Mastering_margin_collapsing
隣接兄弟要素のマージンは相殺されます (後ろの兄弟要素がそれ以前の浮動状態を解除する必要がある場合を除く)。
この現象を対策するためには、いくつかの選択肢が存在します。
下側のマージンのみで隙間を作り、最後の要素を検知してマージンを消す方法
<ul class="items">
<li class="item">item</li>
<li class="item">item</li>
<li class="item">item</li>
</ul>
<style>
.items {
border: 1px solid black;
}
.item {
margin: 0 0 40px 0;
background: pink;
padding: 10px;
}
.item:nth-last-of-type(1) {
margin: 0;
}
</style>
マージンを要素の下側のみに取ることによって、マージンの相殺が起きないようにしています。
また、一番下に来る要素を:nth-last-of-type(1)で検知し、最下部に余計なマージンを作らないようにしました。
flexを使用する
<div class="outer">
<ul class="items">
<li class="item">item</li>
<li class="item">item</li>
<li class="item">item</li>
</ul>
</div>
<style>
.outer {
border: 1px solid black;
}
.items {
margin: -20px 0;
display: flex;
flex-direction: column;
}
.item {
margin: 20px 0;
background: pink;
padding: 10px;
}
</style>
本シリーズの記事ではもはや常連になってしまったflexですが、なんとこの問題についても解決してくれました。
マージンの相殺が発生するのは、ブロック要素やフレックスコンテナ等のブロックとして扱われる物に付与されたmarginについてのみですので、要素をフレックスアイテムにしてしまえば相殺は発生しなくなるわけです。
最初から相殺を想定したmarginを設定する
<div class="outer">
<ul class="items">
<li class="item">item</li>
<li class="item">item</li>
<li class="item">item</li>
</ul>
</div>
<style>
.outer {
border: 1px solid black;
}
.items {
margin: -40px 0;
}
.item {
margin: 40px 0;
background: pink;
padding: 10px;
}
</style>
力技にも見えますが、一番オーソドックスなやり方ではあります。
十分注意して扱いましょう。
親子要素におけるマージンの相殺
次に、以下のようなデザインを考えます。
上のアイテムと下のアイテムの間に40pxのスペースを取りたいので、親子要素でそれぞれ20pxずつ下側にマージンを入れてみましょう。
<div class="item">
<p class="text">上のアイテム</p>
</div>
<div class="item">
<p class="text">下のアイテム</p>
</div>
<style>
.item {
background: pink;
margin-bottom: 20px;
}
.text {
background: lightgreen;
padding: 10px;
margin-bottom: 20px;
}
おや、やはりなにかがおかしいです。
マージンが親と子のどちらかしか適用されておらず、隙間が20pxしかありません。
これも何が起こっているのか、インスペクタで見てみましょう。
親のマージンも、子のマージンも同じ場所に存在するように見えます。
これもやはりマージンの相殺が起こっています。
マージンの相殺の習得 – CSS: カスケーディングスタイルシート | MDN
https://developer.mozilla.org/ja/docs/Web/CSS/CSS_box_model/Mastering_margin_collapsing
あるブロックの margin-top と、1 つ以上の子孫ブロックの margin-top を隔てる境界、パディング、インライン部分、ブロック整形コンテキストの生成、浮動の解除のいずれもがない場合、もしくは、あるブロックのmargin-bottomと1つ以上の子孫ブロックの margin-bottomを隔て境界、パディング、インラインコンテンツ、 height, min-height, max-height のいずれもがない場合、それぞれマージンが折り畳まれます。折り畳まれた側のマージンは、親要素の外側に出ます。
ざっくり言うと、親要素(この場合は.item)にpaddingもborderも存在しない場合、子要素(この場合は.text)のマージンは親要素を突き抜けてしまいます。
解決法として、borderや極小のpaddingを親要素に設定する、親要素をflexにしてしまうなど存在するにはするのですが、より可読性が低いコードになってしまいがちです。
こちらのマージンの相殺については、親要素のみでマージンを取るなど、子要素のマージンがはみ出すような実装を最初からしない方向で進めたほうがより良いでしょう。
まとめ
デザイン実装の際に避けては通れないmarginプロパティですが、マージンの相殺という不安定な要素を含んだものであるということを強く認識する必要があります。
思わぬデザイン崩れを招かないよう、十分注意して使用してください。








