須知的css——margin不重疊的情形
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不重疊的情形