できない.dev

CSSで子要素の上マージンが親の外へはみ出すのを防ぐには

親要素の中の子に付けた margin-top が親の外へ突き抜けるのを、display: flow-root で防ぐ基本形を示す。
隣り合う要素のマージンが重なって一つになる相殺の仕組みと、止め方もあわせて確認できる。

公開:

プレビュー
<div class="wrap"><div class="parent"><p class="child">子の margin-top: 24px</p></div></div>
.wrap {
  width: 260px;
  border: 1px dashed #94a3b8;
  font: 14px system-ui;
}
.parent {
  display: flow-root;
  background: #dbeafe;
}
.child {
  margin: 24px 0 0;
  line-height: 1.7;
}

親に display: flow-root を付けると、親が独立したレイアウトの塊になり、子の margin-top が親の内側に収まる。
親と子のマージンが重なって親の外へ出る「マージン相殺」を、見た目に副作用を出さずに止めるためである(親の中に並ぶ兄弟どうしの相殺はそのまま残る)。

子の上マージンが親の外へ突き抜ける

ブロック要素の親と最初の子のあいだに border・padding・行ボックスのような仕切りがないと、子の margin-top は親の外側に出てしまう。

親の背景は子のマージンぶん下がらず、子の文字が親の上端に張り付いて見える。

できない例: 親に何も指定しない(余白が親の外に出る)
.wrap {
  width: 260px;
  border: 1px dashed #94a3b8;
  font: 14px system-ui;
}
.parent {
  background: #dbeafe;
}
.child {
  margin: 24px 0 0;
  line-height: 1.7;
}
できる例: 親に display: flow-root を付ける
.wrap {
  width: 260px;
  border: 1px dashed #94a3b8;
  font: 14px system-ui;
}
.parent {
  display: flow-root;
  background: #dbeafe;
}
.child {
  margin: 24px 0 0;
  line-height: 1.7;
}

隣り合う要素の余白は足し算にならない

縦に並んだブロック要素の margin は、大きい方に重なって一つになる。
上下に 20px ずつ付けた 2 つの箱の間隔は、40px ではなく 20px である。

間隔を足し算にしたいときは、並べる側を display: flex と flex-direction: column にする。
flex や grid の子どうしのマージンは相殺されない。

できない例: ブロックのまま並べる(間隔は 20px)
.stack {
  width: 200px;
  border: 1px dashed #94a3b8;
  font: 14px system-ui;
}
.box {
  margin: 20px 0;
  padding: 8px 12px;
  background: #dbeafe;
}
できる例: flex の列にする(間隔は 40px)
.stack {
  display: flex;
  flex-direction: column;
  width: 200px;
  border: 1px dashed #94a3b8;
  font: 14px system-ui;
}
.box {
  margin: 20px 0;
  padding: 8px 12px;
  background: #dbeafe;
}

どの方法で止めるか

親と子の相殺を止める方法は複数あり、副作用が違う。

  • display: flow-root: 子のマージンが親の外へ突き抜けるのを止めるだけで、見た目は変わらない
  • 親に padding または border を付ける: 見た目に余白や線が増える
  • overflow: hidden: 突き抜けは止まるが、はみ出す影や絶対配置の子が切れる
  • 親を display: flex や display: grid にする: 子のマージンは相殺されないが、子の並び方も変わる

まず display: flow-root を試し、レイアウトを変えたいときだけほかの方法を選ぶ。

このコードで動いた?