深究盒模型的margin合併問題

Jacen發表於2017-11-07

1.首先,瞭解一些詞彙

– 流內元素?
如果一個元素是浮動的,絕對定位的或者是根元素,那麼它就是流外元素。即我們常說的脫離文件流的元素。如果一個元素不是流外的,即仍在文件流中的元素,就叫流內元素。
– 流內塊級盒?
流內塊級盒,就是流內塊級元素生成的一個盒。
– 什麼是格式化上下文?
常規流中的盒屬於一個格式化上下文,可能是塊或是內聯,但不能都是(既是塊又是內聯)。塊級盒參與塊格式化上下文。內聯級盒參與內聯格式化上下文 。在一個塊格式化上下文中,盒在豎直方向一個接一個地放置,從包含塊的頂部開始。兩個兄弟盒之間的豎直距離由margin屬性決定。同一個塊格式化上下文中的相鄰塊級盒之間的豎直margin會合並。
新建塊級格式化上下文(BFC)的條件:

  • 浮動元素,float除了none以外的值。
  • 絕對定位元素,position(absolute,fixed)
  • display 為以下其中之一的值 inline-blocks,table-cells,table-captions
  • overflow 除了 visible 以外的值(hidden,auto,scroll)
  • 注意:”display:table” 本身並不產生 BFC,而是由它產生匿名框,匿名框中包含 “display:table-cell” 的框會產 BFC。

– 行盒(line box)
在一個行內格式化上下文中,盒是一個接一個水平放置的,從包含塊的頂部開始。這些盒之間的水平margin,border和padding都有效。盒可能以不同的方式豎直對齊:以它們的底部或者頂部對齊,或者以它們裡面的文字的基線對齊。包含來自同一行的盒的矩形區域叫做行盒
– 相鄰的margin?
兩個margin是相鄰的,當且僅當:

  • 都屬於流內塊級盒,處於同一個塊格式化上下文。
  • 沒有行盒(line box),沒有空隙,沒有padding並且沒有border把它們隔開(注意,因此某些0高度行盒)
  • 都屬於豎直相鄰盒邊(vertically-adjacent box edges),即來自下列某一對:

    * 一個盒的top margin和它的第一個流內子級的top margin
    * 一個盒的bottom margin和它的下一個流內後面的兄弟(its next in-flow following sibling)的top margin
    * 最後一個流內子級的bottom margin和它的父級的bottom margin,如果父級的高度的計算值為`auto`
    * 一個盒的top和bottom margin,該盒沒有建立一個新的塊格式化上下文並且min-height的計算值為0,height的計算值為0或者`auto`,並且沒有流內子級
  • 如果一個margin的任何部分margin與另一個margin相鄰的話,就認為它與那個margin相鄰,是合併(collapsed)margin。

2.什麼是margin合併(重疊)

       在CSS中,兩個或者多個盒(可能但不一定是兄弟)的相鄰的margin會被結合成一個margin。Margin按這種方式結合叫合併(collapse),產生的結合的margin叫做合併margin。

3.合併的規則

  1. 相鄰的豎直margin會合並,除了:

    • 根元素的盒的margin不合並
    • 如果一個有空隙(clearance)的元素的top和bottom margin是相鄰的,它的margin會與緊跟著的兄弟的相鄰margin合併,但產生的margin不會與父級塊的bottom margin合併
  2. 水平margin不會合並
合併的計算規則
  • 當兩個或者更多的margin合併時,產生的margin寬度為合併margin寬度中的最大值。
  • 至於負margin,就從正相鄰margin的最大值中減去負相鄰margin的絕對值的最大值。
  • 如果沒有正margin,就用0減去相鄰margin的絕對值的最大值

4.總結

所以綜上所述,只要兩個margin被隔開了,就一定不會發生margin重疊。可以是上下border隔開,可以是被上下padding隔開,也可以是被高度隔開,可以是被流內子級隔開,可以被空隙(空隙的產生與clear有關)隔開,可以被新建立的格式化上下文隔開。

以下是css2.1規範的總結

  • 一個浮動的盒與任何其它盒之間的margin不會合並(甚至一個浮動盒與它的流內子級之間也不會)任何浮動的、絕對定位的盒子不會與任何其他盒子的margin合併(原因:它們是流外塊級盒)。
  • 建立了新的塊格式化上下文的元素(例如,浮動盒與overflow不為`visible`的元素)的margin不會與它們的流內子級合併。(原因:不在同一個塊級格式化上下文)
  • 絕對定位的盒的margin不會合並(甚至與它們的流內子級也不會)把絕對定位的盒子比作飛起來的盒子,那麼這兩個飛起來的盒子,一定處於不同高度,因此,不管這個盒子如何移動,都不會影響任何一個飛起來的盒子。
  • 內聯盒的margin不會合並(甚至與它們的流內子級也不會)
  • 一個流內塊級元素的bottom margin總會與它的下一個流內塊級兄弟的top margin合併,除非兄弟有空隙
  • 一個流內塊級元素的top margin會與它的第一個流內塊級子級的top margin合併,如果該元素沒有top border,沒有top padding並且該子級沒有空隙
  • 一個`height`為`auto`並且`min-height`為0的流內塊級盒的bottom margin會與它的最後一個流內塊級子級的bottom margin合併,如果該盒沒有bottom padding並且沒有bottom border並且子級的bottom margin不與有空隙的top margin合併
  • 盒自身的margin也會合並,如果`min-height`屬性為0,並且既沒有top或者bottom border也沒有top或者bottom padding,並且其`height`為0或者`auto`,並且不含行盒,並且其所有流內子級的margin(如果有的話)都合併了。
  • 如果盒的top和bottom margin相鄰,那麼可能會被徹底合併(collapse through)

margin。此時,元素的位置取決於與其它margin被合併了的元素的關係

  • 如果該元素的margin與其父級的top margin合併了,盒的top border邊被定義為與其父級的相同

否則,要麼該元素的父級沒有參與margin合併,要麼只涉及其父級的bottom margin。如果該元素的bottom border不為0的話,其top border邊的位置將正常顯示(the same as it would have been)。
注意,已被徹底合併了的元素的位置不影響其它margin被合併的元素的位置,只有在佈局這些元素的後代時,才需要top border邊的位置。

整理自css2.1規範:[http://www.ayqy.net/doc/css2-…]
以及:[http://www.jianshu.com/p/52a2…]

相關文章