深刻理解CSS外邊距摺疊(Margin Collapse)

外邊距疊加一直是前端開發必須瞭解的一個概念,面試通常也會問到這個問題。因此整理一下相關外邊距疊加相關的知識點。外邊距疊加是什麼?何時會發生外邊距疊加?如何避免外邊距疊加?css

什麼是外邊距疊加

先來看看 W3C 對於外邊距疊加的定義:html

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中,兩個或多個毗鄰的普通流中的盒子(多是父子元素,也多是兄弟元素)在垂直方向上的外邊距會發生疊加,這種造成的外邊距稱之爲外邊距疊加。面試

咱們能夠注意定義中的幾個關鍵字:毗鄰、兩個或多個、垂直方向和普通流。less

毗鄰

毗鄰說明了他們的位置關係,沒有被 paddingborderclearline box 分隔開。this

兩個或多個

兩個或多個盒子是指元素之間的相互影響,單個元素不會存在外邊距疊加的狀況。翻譯

垂直方向

Horizontal margins never collapse.code

只有垂直方向的外邊距會發生外邊距疊加。水平方向的外邊距不存在疊加的狀況。orm

普通流(in flow)

啥爲普通流?W3C 只對 out of flow 做了定義:htm

An element is called out of flow if it is floated, absolutely positioned, or is the root element.An element is called in-flow if it is not out-of-flow.

從定義中咱們能夠知道只要不是 floatabsolutely positionedroot element 時就是 in flow。

何時會發生外邊距疊加

外邊距疊加存在兩種狀況:一是父子外邊距疊加;二是兄弟外邊距疊加。

W3C 對於什麼是毗鄰的外邊距也有定義:

Two margins are adjoining if and only if: - both belong to in-flow block-level boxes that participate in the same block formatting context - no line boxes, no clearance, no padding and no border separate them - both belong to vertically-adjacent box edges, i.e. form one of the following pairs:

  • top margin of a box and top margin of its first in-flow child
  • bottom margin of box and top margin of its next in-flow following sibling
  • bottom margin of a last in-flow child and bottom margin of its parent if the > parent has "auto" computed height
  • top and bottom margins of a box that does not establish a new block formatting context and that has zero computed "min-height", zero or "auto" computed "height", and no in-flow children

從定義中咱們能夠很清楚的知道要符合哪些狀況纔會發生外邊距摺疊:

  • 都屬於普通流的塊級盒子且參與到相同的塊級格式上下文中
  • 沒有被padding、border、clear和line box分隔開
  • 都屬於垂直毗鄰盒子邊緣:

    • 盒子的top margin和它第一個普通流子元素的top margin
    • 盒子的bottom margin和它下一個普通流兄弟的top margin
    • 盒子的bottom margin和它父元素的bottom margin
    • 盒子的top margin和bottom margin,且沒有建立一個新的塊級格式上下文,且有被計算爲0的min-height,被計算爲0或auto的height,且沒有普通流子元素

Demo 1

.parent1 {
    height: 20px;
    background: yellow;
    margin-bottom: 20px;
}
.parent2 {
    margin: 20px 0 30px;
}
.parent3 {
    height: 20px;
    background: green;
    margin-top: 20px;
}
.child {
    background: red;
    height: 20px;
    margin: 40px 0 30px;
}

<div class="parent1"></div>  
<div class="parent2">  
    <div class="child"></div>
    <div class="child"></div>
    <div class="child"></div>
</div>  
<div class="parent3"></div>

這個 demo 裏的 .parent2 和第一個 .child 的 top margin 疊加,致使 .parent1.parent2 之間的邊距爲 40px。

Demo 2

仍是用上面的代碼,.parent2 中的 .child 中的 top margin 和 bottom margin 發生外邊距疊加,它們之間的外邊距爲 40px。

Demo 3

仍是上面的代碼,.parent2 中的最後一個 .child 發生 bottom margin 疊加,.parent2
.parent3 之間的邊距爲 30px。

Demo 4

.demo {
    height: 30px;
    background: red;
}
.margin-test {
    margin: 20px 0 30px;
}

<div class="container">  
    <div class="demo"></div>
    <div class="margin-test"></div>
    <div class="demo"></div>
</div>

這個 demo 是上面的第四種狀況,元素自身的外邊距 topbottom 發生摺疊,咱們能夠看出 .container 的高度爲 90px,這裏能夠看到 margin-testtopbottom 外邊距發生了摺疊。

如何避免外邊距疊加

上面講了外邊距的疊加,那如何避免呢,其實只要破壞上面講到的四個條件中的任何一個便可:毗鄰、兩個或多個、普通流和垂直方向。

W3C也對此作了總結:

  • Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children).
  • Margins of elements that establish new block formatting contexts (such as floats and elements with "overflow" other than "visible") do not collapse with their in-flow children.
  • Margins of absolutely positioned boxes do not collapse (not even with their in-flow children).
  • Margins of inline-block boxes do not collapse (not even with their in-flow children).
  • The bottom margin of an in-flow block-level element always collapses with the top margin of its next in-flow block-level sibling, unless that sibling has clearance.
  • The top margin of an in-flow block element collapses with its first in-flow block-level child"s top margin if the element has no top border, no top padding, and the child has no clearance.
  • The bottom margin of an in-flow block box with a "height" of "auto" and a "min-height" of zero collapses with its last in-flow block-level child"s bottom margin if the box has no bottom padding and no bottom border and the child"s bottom margin does not collapse with a top margin that has clearance.
  • A box"s own margins collapse if the "min-height" property is zero, and it has neither top or bottom borders nor top or bottom padding, and it has a "height" of either 0 or "auto", and it does not contain a line box, and all of its in-flow children"s margins (if any) collapse.

翻譯一下:

  • 浮動元素不會與任何元素髮生疊加,也包括它的子元素
  • 建立了 BFC 的元素不會和它的子元素髮生外邊距疊加
  • 絕對定位元素和其餘任何元素之間不發生外邊距疊加,也包括它的子元素
  • inline-block 元素和其餘任何元素之間不發生外邊距疊加,也包括它的子元素
  • 普通流中的塊級元素的 margin-bottom 永遠和它相鄰的下一個塊級元素的 margin-top 疊加,除非相鄰的兄弟元素 clear
  • 普通流中的塊級元素(沒有 border-top、沒有 padding-top)的 margin-top 和它的第一個普通流中的子元素(沒有clear)發生 margin-top 疊加
  • 普通流中的塊級元素(height爲 auto、min-height爲0、沒有 border-bottom、沒有 padding-bottom)和它的最後一個普通流中的子元素(沒有自身發生margin疊加或clear)發生 margin-bottom疊加
  • 若是一個元素的 min-height 爲0、沒有 border、沒有padding、高度爲0或者auto、不包含子元素,那麼它自身的外邊距會發生疊加

本文首發於有贊技術博客:http://tech.youzan.com/css-ma...

相關文章
相關標籤/搜索