1. 程式人生 > >須知的css——margin不重疊的情形

須知的css——margin不重疊的情形

一起學前端 學習 adding sam 交流群 瀏覽器 改變 height select

margin重疊

摘自css2.1規範中文版

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

margin重疊的計算規則

摘自css2.1規範中文版

當兩個或者更多的margin合並時,產生的margin寬度為合並margin寬度中的最大值。至於負margin,就從正相鄰margin的最大值中減去負相鄰margin的絕對值的最大值。如果沒有正margin,就用0減去相鄰margin的絕對值的最大值

什麽是相鄰的margin

摘自css2.1規範中文版
兩個margin是相鄰的,當且僅當:

  • 都屬於流內塊級盒,處於同一個塊格式化上下文。
  • 沒有行盒(line box),沒有空隙,沒有padding並且沒有border把它們隔開(註意,因此某些0高度行盒)
  • 都屬於豎直相鄰盒邊(vertically-adjacent box edges),即來自下列某一對:
    1.一個盒的top margin和它的第一個流內子級的top margin
    2.一個盒的bottom margin和它的下一個流內後面的兄弟(its next in-flow following sibling)的top margin
    3.最後一個流內子級的bottom margin和它的父級的bottom margin,如果父級的高度的計算值為‘auto‘
    4.一個盒的top和bottom margin,該盒沒有建立一個新的塊格式化上下文並且min-height的計算值為0,height的計算值為0或者‘auto‘,並且沒有流內子級

如果一個margin的任何部分margin與另一個margin相鄰的話,就認為它與那個margin相鄰,是合並(collapsed)margin。

具體分析各個條件

1.都屬於流內塊級盒,處於同一個塊格式化上下文。

什麽是流內元素?如果一個元素是浮動的,絕對定位的或者是根元素,那麽它就是流外元素。如果一個元素不是流外的,就叫流內元素。
流內塊級盒,就是流內塊級元素生成的一個盒。

結論1:根元素的盒子margin不會發生重疊(原因:根元素雖然是塊級盒,但不是流內元素)。

舉個??:根元素與body的margin不會重疊

 html {margin-top:10px;}
 body {margin-top:10px;}

事實:body距離視口頂部20px。

結論2: 任何浮動的、絕對定位的盒子不會與任何其他盒子的margin合並(原因:它們是流外塊級盒)。

舉個??:兩個絕對定位的盒子,不會發生margin重疊。

<style>
    .div1 {
        width: 100px;
        height: 100px;
        position: absolute;
        background: red;
        margin-bottom: 10px;
        top: 0;
    }

    .div2 {
        width: 100px;
        height: 100px;
        position: absolute;
        background: yellow;
        margin-top: 10px;
        top: 100px;
    }
</style>
    <div class="div1"></div>
<div class="div2"></div>

在瀏覽器一看,咦,兩個div間距剛好是10px,這不是發生margin重疊了嗎?no,no,no。如果此時,改變其中一個div的margin值,都不會影響任何一個div的布局。通俗的講就是,把絕對定位的盒子比作飛起來的盒子,那麽這兩個飛起來的盒子,一定處於不同高度,因此,不管這個盒子如何移動,都不會影響任何一個飛起來的盒子。

什麽是格式化上下文? 常規流中的盒屬於一個格式化上下文,可能是塊或是內聯,但不能都是(既是塊又是內聯)。塊級盒參與塊格式化上下文。內聯級盒參與內聯格式化上下文 。

新建塊級格式化上下文(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。

在一個塊格式化上下文中,盒在豎直方向一個接一個地放置,從包含塊的頂部開始。兩個兄弟盒之間的豎直距離由margin屬性決定。同一個塊格式化上下文中的相鄰塊級盒之間的豎直margin會合並。

結論3:建立了新的塊級格式化上下文的元素的margin不會與它們的流內子集合並。(原因:不在同一個塊級格式化上下文)

舉個??:overflow不為‘visible’的元素,不會與它的流內子級合並。

.father {
     width: 100px;
     height: 100px;
     background: red;
     margin-top: 10px;
 }
 .child {
     width: 50px;
     height: 50px;
     background: yellow;
     margin-top: 20px;
 }
<div class="father">
  <div class="child"></div>
</div>

這種情況是,father的overflow是‘visible‘,發生了margin重疊,father向下偏移20px,如下圖所示。

技術分享
overflow不為‘visible’的元素,不會與它的流內子級合並

如果把father的overflow的值改為不是‘visible‘的值,那麽就不會發生margin重疊,如下圖所示。

技術分享
overflow不為‘visible’的元素,不會與它的流內子級合並

2.沒有行盒(line box),沒有空隙,沒有padding並且沒有border把它們隔開。

意思就是說,如果兩個margin之間有東西隔著,它們並不是緊挨著一起,那麽就不會發生margin重疊。

舉個??:父元素有border,父子元素不會發生margin重疊。

  <style>
 .father{
     width: 100px;
     height: 100px;
     background: red;
     margin-top: 10px;
 }
 .child {
     width: 100px;
     height: 50px;
     background: yellow;
     margin-top: 20px;
 }
</style>

<div class="father">
<div class="child"></div>
</div>

這種情況是,父子元素margin沒有被隔開的。因此,margin重疊了。如圖所示:

技術分享
父元素有border,父子元素不會發生margin重疊


如果給父元素頂部添加1像素的border,那麽父子元素margin被邊框隔離,此時不會發生margin重疊。如圖所示:

技術分享
父元素有border,父子元素不會發生margin重疊


此時child距離father頂部20px;

在舉個例子:空div的margin自身重疊

  <style>
    .div1 {
        width: 100px;
        margin-top: 100px;
        margin-bottom: 100px;
    }
    .div2 {
        width: 100px;
        height: 100px;
        background: red;
    }
</style>
<div class="div1">
</div>
<div class="div2"></div>

如果空div的上下margin沒有隔開,就會發生重疊,如圖所示:

技術分享
空div的margin自身重疊

紅色div向下偏離了100px,而不是200px,因為空div發生了margin重疊。如果給空div加上padding-top=10px,就不會發生margin重疊,如圖所示:

技術分享
空div的margin自身重疊


此時紅色div向下偏移了210px(100+100+10)。

3.最後一個流內子級的bottom margin和它的父級的bottom margin,如果父級的高度的計算值為‘auto‘。

  <style>
    .father {
        width: 100px;
        margin-bottom: 100px;
    }
    .child {
        width: 100px;
        height: 100px;
        margin-bottom: 150px;
        background: red;
    }
    .sibling {
        width: 100px;
        height: 100px;
        background: yellow;
    }
</style>
<div class="father">
    <div class="child"></div>
</div>
<div class="sibling"></div>

此時father元素高度是auto,father的margin-bottom與child的margin-bottom,發生了重疊,因此,sibling距離father150px;
如圖所示:

技術分享
最後一個流內子級的bottom margin和它的父級的bottom margin,如果父級的高度的計算值為‘auto‘。

如果此時給father設置height:100px;那麽father的margin-bottom就不會和child的margin-bottom發生重疊。此時sibling與father的垂直距離,只跟它們的margin值有關,與child的margin值無關。如圖所示:

技術分享
最後一個流內子級的bottom margin和它的父級的bottom margin,如果父級的高度的計算值為‘auto‘。

4.一個盒的top和bottom margin,該盒沒有建立一個新的塊格式化上下文並且min-height的計算值為0,height的計算值為0或者‘auto‘,並且沒有流內子級。

   <style>
    .div1 {
        width: 100px;
        margin-top: 100px;
        margin-bottom: 100px;
    }

    .div2 {
        width: 100px;
        height: 100px;
        background: red;
    }
</style>
<div class="div1">
</div>
<div class="div2"></div>

這種情況下,div1沒有建立一個新的格式化上下文並且height:auto,也沒有流內子級。div1自身div就重疊了,div2便宜100px。如圖所示:

技術分享
一個盒的top和bottom margin,該盒沒有建立一個新的塊格式化上下文並且min-height的計算值為0,height的計算值為0或者‘auto‘,並且沒有流內子級。

如果將div1的overflow設置為’不為visible‘的值,或添加流內子級<span>1</span>(不能是空標簽,否則margin照樣重疊),或添加height值。此時,margin都不會重疊。這個就不貼圖片了。

總結

把margin重疊的條件分析了一遍,就得到了margin不重疊的情況。
我的總結是:只要兩個margin被隔開了,就一定不會發生margin重疊。可以是上下border隔開,可以是被上下padding隔開,也可以是被高度隔開,可以是被流內子級隔開,可以被空隙(空隙的產生與clear有關)隔開,可以被新建立的格式化上下文隔開。
以下是css2.1規範的總結

  • 一個浮動的盒與任何其它盒之間的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邊的位置。

學習過程中遇到什麽問題或者想獲取學習資源的話,歡迎加入學習交流群
343599877,我們一起學前端!

須知的css——margin不重疊的情形