LINEで現役エンジニアに直接質問してみよう!登録無料

marginの相殺を理解しよう!相殺の起こるパターンと回避テクニック

この記事のまとめ

marginの相殺について解説します。

これは仕様はあまりにトリッキーすぎて、初心者に「バグなんじゃないの?」と思われてしまうことが多く、躓きやすいポイントです。
しかし、思い通りのデザインを組もうとしたときには絶対に必要になる知識です。

イラストを多く使って極力わかりやすく「marginの相殺」から「相殺を回避するテクニック」まで紹介しているので、まずはトライしてみてくだいさい。

marginの相殺とは

marginの相殺とは、要素が2つ縦に並んだ時marginが打ち消される事を言います。

例えば、このように2つの<div>要素があったとします。

1つには20pxのmargin-bottom、もう2つには40pxのmargin-topが設定されています。

これらの要素を縦に並べると、下記のようにmarginが打ち消されて大きなmarginだけが適用されます。

この場合だと、margin-bottom:20pxは無効化され、margin-top:40pxのみ有効化されます。

marginの相殺がいつ起こる?

marginが打ち消されるパターンがいくつかあり、3つ例を紹介します。

ケース1: 兄弟要素が上下に並んだmargin

marginの付いた要素を上下にそれぞれ並べると、隣接したmarginは大きい方のmarginだけが有効になります。

画像では、要素1のmargin-bottomよりも要素2のmargin-topの方が大きいのあで、要素2の方のみ使われます。

ケース2: 親要素と最初の子要素の上にmargin

親子どちらも上にmarginがある場合、marginの相殺が発生し大きい方のmarginだけが有効になります。

ケース3: 親要素と最初の子要素の下にmargin

同様に、親子のどちらも下のmarginがある場合、marginの相殺が発生し大きい方のmarginだけが有効になります。

ケース4: 要素自体の高さ0の空要素のmargin

要素の高さ0の場合は、要素全体がmarginの相殺によって見えなくなることもあります。

marginの相殺が起こらないケース

逆にmarginの相殺が起こらないケースもあります。

ケース1: Flexbox、Gridなどブロック要素

marginの相殺は、ブロック要素(ブロックレベルの要素)でのみ適用されるルールです。

displayの値が、

  • block(ブロック要素。<divタグやh1>タグなど)
  • list-item(リスト要素。<li>など)
  • table(テーブル要素。<table>など)

の場合のみ適用され、このケース以外でmarginの相殺は起こりません

ケース2: marginとmarginの間にpaddingがある場合

先程解説したように、親子に関係で同じ方向にmarginが設定されている場合、大きい方のみが適用されmarginの相殺が発生します。

しかし、親要素の方にpaddingを使い、marginとmarginの間にpaddingがあるようにすると、このようにmarginの相殺が発生しなくなります

これは、margin同士が直接触れ合わなくなることが原因です。

この例では、margin-topを例にしましたが、margin-bottomでも同じように間にpaddingをかませると、マージンの相殺は起こらなくなります。

ケース3: HTMLのルート要素の場合

HTMLのルート要素とは、一番外側にある<html>タグの事です。このタグではmarginの相殺は発生しません。

それは、<html>タグの親要素は存在しないからです。

MEMO

margin-topmargin-bottomでは相殺は発生しますが、margin-leftmargin-rightでは相殺は発生しません。
また、padding同士では隣り合っても相殺は起こりません。

marginの相殺を回避するポイントやテクニック

marginの相殺はトリッキーな挙動なので、デザインでハマってしまう原因になります。
できればこのような挙動はしないでほしいですよね?

そこで、相殺を回避する方法をまとめました。

  1. ( オススメ)1方向のみにmarginを使うようにする
  2. ( 非推奨)要素と要素の間にborderを挿入する
  3. ( 非推奨)要素をブロックレベル以外の要素に変更する(flex, gridなど)
  4. ( 非推奨)親要素か子要素にfloatを設定する
MEMO

ここではいくつか特殊なテクニックを紹介していますが、まずはマージンの相殺がどのような条件で発生するのかをしっかりと理解することが大切です。

1方向のみにmarginを使うようにする

よほどの理由がない限り、この方法を使うようにしましょう。

「マージンの指定を一方向のみに適用する」というのを心がけて、上下の兄弟要素で発生するマージンの相殺をそもそも発生させない工夫をするのが一番オススメです。

例えば、「このサイトでは基本的にmargin-topしか使わない!」と決めてしまう事です。そしてどうしても下にもmarginが必要になった場合のみmargin-bottomを使うようにします。

こうすれば、マージンの相殺に遭遇する回数はグッと減ります。

要素と要素の間にborderを挿入する

それでもどうしても相殺が発生してしまうことはあります。その時のテクニック「要素と要素の間にborderを挿入する」という方法を紹介します。

paddingを間に挿入するとマージンの相殺が発生しなくなることを解説しました。まさにアレのborder版です。

要素をブロックレベル以外の要素に変更する(flex, gridなど)

隣接している要素でも、親子関係の要素でもいいですが、そのうちのどれかをブロックレベル以外の要素に変更するという方法もあります。

やり方は簡単で、下記のようにdisplayを変えるだけです。

div {
    display: flex;
}

但し、displayは要素の配置やデザインを司る重要な設定の1つですので、むやみに変更するのは危険です。

最悪デザインが崩れてしまうので、使うならば局所的にしましょう。

親要素か子要素にfloatを設定する

親要素か子要素のどちらかをfloatにしてしまうという手もあります。

これもCSSを下記のようにCSSを変更します。

div {
    float: left;
}

これも要素をブロックレベル以外の要素に変更する方法と同じように局所的に使うようにしましょう。

まとめ

  • marginの相殺が起こるケースは4種類
    • 兄弟要素が上下に並んだmargin
    • 親要素と最初の子要素の上にmargin
    • 親要素と最初の子要素の下にmargin
    • 要素自体の高さ0の空要素のmargin
  • 相殺が起こらないケースもある
  • marginの相殺が起こらないような設計にするのを心がけよう!
この記事を書いた人

自身がプログラミングを独学で勉強し始めて躓いた経験を元に、これから勉強をする人に向けに「イラスト多めでわかりやすい記事」にこだわって情報を発信しています。

現在はフルスタックエンジニアとしてサービス開発などのお仕事をしています。