2つの要素の縦方向のmarginが重なる場合、大きい方の値のみが適用される。これは一般にmarginの相殺と呼ばれる仕様である。

ただ、直感的な挙動でないため、指定したmarginが効いていないのでは、と誤解しやすい。また、W3Cの仕様にこそ明記されているものの、なぜそれが必要なのかに関する公式の説明はない(見つけられないだけかもしれないが)。

気持ち悪いので、自己満足のために、W3Cの仕様をさらいつつ仮説を立ててみたいと思う。

「marginの相殺」の定義

「marginの相殺」というのは意訳である。W3Cの仕様には、以下のような記述がある。

In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.

CSSでは、2つ以上の隣り合うボックスのマージンは、1つのマージンにまとめられることがある。このようにまとめられたマージンを「collapse」(相殺されたもの、≒折りたたまれたもの≒崩壊したもの)と言い、結果として得られたマージンは「相殺されたマージン」と呼ぶ。

引用元:Collapsing margins

個人的には、相殺というより折りたたみや崩壊の方がしっくりくる。相殺という言葉に、1に1をぶつけたら0になる、みたいなイメージを持っているからだ(多分ぷよぷよのせい)。

しかし、一般的には「マージンの相殺」と呼ばれているので、本記事でも他の語ではなく相殺という語を使う。

仕様上の挙動

マージンの相殺は、以下のように定義されている。

垂直方向のマージンは、以下のケースを除き相殺される。

  • ルート要素のマージンは相殺されない。
  • クリアランスのある要素の上下のマージンが隣接している場合、そのマージンは隣接する要素のマージンに相殺される。ただし得られたマージンは、親ブロックの下のマージンとは折りたたまれない。
  • 水平方向のマージンは折りたたまれない。

また、マージンの相殺が起こるのは、以下の条件が満たされた時である。

  • 同じブロック整形コンテキストに参加する、インフローのブロックボックスが隣接している。

  • 両者の間に、インラインボックスがない。あるいは、双方の親要素にクリアランス、パディング、ボーダーが指定されていない(※高さ0のインラインボックスは無視される)。

  • 両方が垂直に隣接したボックスエッジに属している、すなわち次のいずれかのペアを形成している

    • ボックスの上マージンと、その最初のインフローの子の上マージン
    • ボックスの下マージンと、その次のインフローで続く兄弟要素の上マージン
    • 最後のインフローの子の下マージンと、親の下マージン(親が ‘auto’ で計算された高さを持つ場合)
    • 新しいブロック整形コンテキストを確立しないボックスの上下のマージンで、そのボックスが計算されたmin-height0、または、height0autoであり、インフローの子を持たない場合

なお、相殺されたマージンは、その構成要素のマージンのいずれかが他のマージンと隣接している場合、それも隣接しているとみなされる。

わけがわからん。

と投げ出したくなるのをぐっと堪えて、ここで出てくるブロック整形コンテキストについて考えてみたい。

整形コンテキストとは

ブラウザは、ブロックレベル、インラインレベルなどに合わせて整形コンテキストという単位を用意し、要素をレイアウトする。

整形コンテキストには、以下のような種類がある。

で、原始Webでは、主にブロック整形コンテキストとインライン整形コンテキストによって要素をレイアウトしていた。このレイアウトは現代でもバリバリ現役だが、これに付随する形で選択肢が増えた。

ざっくり流れを整理してみたい。

昔々のレイアウト

原始Webでは、見出し、段落、リストなど、縦並びかつテキストベースのシンプルな構成のドキュメントが主流だった。縦並びは、ブロック整形コンテキストの領域である。

このレイアウトに限って考えれば、marginの相殺は便利だ。プロパティ1つで、複数の要素の間隔を揃えることができる。兄弟要素だけでなく、子要素のマージンまで相殺されるのも、縦並びで要素の間隔を揃えたい、という需要を考えれば頷ける。

また、間にパディングやボーダーがある場合に相殺を除外しているのは、親要素によってコンポーネントの棲み分けがなされている場合を考慮してのものではないかと思う。

現代のレイアウト

昔々のWebと違い、現代では複雑なレイアウトが求められる。それに伴ってCSSも拡張されている。かつてはfloatやテーブルレイアウトを駆使してトリッキィに対処していたものが、flexgridを使えば簡単に実現できるようになった。

要素同士の間隔も、gapや整列系のプロパティで直感的に調整できる。

こういったプロパティは、重なっている部分こそあるものの、それぞれ導入の核となるレイアウトに基づいて設計されている。marginの相殺が理解しづらいのは、階層的に追加されてきたレイアウトで本来の需要が見えづらくなっているせいではないかと想像する。

縦のmarginは避けるべきか

marginの相殺は混乱のもととなる。縦のmarginは避ける、というのも場合によっては有用なプラクティスになり得る。

ただ、現代のWebデザインが複数のレイアウトの組み合わせで実現されていることを理解すれば、marginの相殺は決して混乱を招くものではない、と個人的には思う。

仮説のはずが、いつの間にかお気持ち表明になってしまった。

おしまい。

参考資料