Contents

[CSS] margin 排版問題(Collapsing margins)

CSS 的 Margin Collapsing(外距合併)是一個讓初學者感到困惑的排版機制:在某些情況下,兩個垂直方向的 margin 不會相加,而是合併(collapse)成較大的那個值

Margin Collapsing 的三種情況

1. 相鄰兄弟元素(Adjacent Siblings)

兩個緊鄰的區塊元素,上方元素的 margin-bottom 和下方元素的 margin-top 會合併:

1
2
<div style="margin-bottom: 20px;">上方元素</div>
<div style="margin-top: 30px;">下方元素</div>

實際間距不是 20 + 30 = 50px,而是取較大值 30px

2. 父子元素(Parent and First/Last Child)

當父元素和第一個子元素之間沒有 border、padding、BFC 阻隔時,子元素的 margin 會「穿透」到父元素外:

1
2
3
<div class="parent" style="margin-top: 10px;">
    <div class="child" style="margin-top: 30px;">子元素</div>
</div>

結果:parentchildmargin-top 合併為 30px,這個 margin 作用在父元素上,而非子元素相對於父元素內部。

3. 空的區塊元素(Empty Block)

一個沒有 border、padding、content 的空元素,自身的 margin-topmargin-bottom 會合併:

1
2
3
4
5
.empty {
    margin-top: 20px;
    margin-bottom: 30px;
    /* 實際占用的 margin 空間為 30px */
}

為什麼 inline-block 和 Flex 不會 Collapse?

inline-block 不會發生 Collapsing

inline-block 元素是行內格式化上下文(IFC)的一部分,而 margin collapsing 只發生在區塊格式化上下文(BFC)中的區塊元素之間。

1
2
3
4
5
/* 這兩個 margin 不會合併 */
.box {
    display: inline-block;
    margin: 20px;
}

Flex 容器不會發生 Collapsing

Flex 容器會為其子元素建立新的 BFC,因此 flex 子項目之間不會發生 margin collapsing:

1
2
3
4
5
.container {
    display: flex;
    flex-direction: column;
}
/* 子元素的 margin-bottom 和 margin-top 不會合併 */

重要規則

  • Margin collapsing 只發生在垂直方向(上下),水平方向的 margin(左右)永遠不會合併
  • block 元素只有上下 margin 會受影響,左右不受影響
  • 合併後的 margin 值 = 兩個值中較大的那個(若有負值則另有計算規則)

如何防止 Margin Collapsing

方法一:使用 overflow: hidden 建立 BFC

1
2
3
.parent {
    overflow: hidden; /* 建立 BFC,防止子元素 margin 穿透 */
}

方法二:加入 paddingborder

1
2
3
4
5
6
7
.parent {
    padding-top: 1px; /* 阻斷父子 margin 的合併 */
}

.parent {
    border-top: 1px solid transparent;
}

方法三:使用 Flexbox 或 Grid

1
2
3
4
5
.parent {
    display: flex;
    flex-direction: column;
    /* Flex 子項目之間不會 margin collapse */
}

方法四:使用 display: flow-root

1
2
3
.parent {
    display: flow-root; /* 建立 BFC,不影響視覺效果 */
}

參考資料