之所以要專門寫一篇文章去解釋margin重疊,一是因為前面的文章裡有提到過,怕有些童鞋不瞭解;二是要寫的內容不是三言兩語就能說清楚的。
在講重疊之前,我們先來了解一下margin這個屬性。
一. margin 基礎講解
這個屬性呢,太常見,我就大概講講,有幾點大家注意一下就好。
margin, 實為margin-left, margin-right, margin-top, margin-bottom的一個簡寫,這些子屬性分別用來設定box的左 / 右 / 上 / 下外邊距的寬度,它們的具體用法如下:
屬性名: margin-left / margin-right / margin-top / margin-bottom
值: <length> | <percentage> | inherit
初始值: 0
繼承性: 無
應用物件:所有dom元素,除了display為table-row-group,table-row, table-column-group, table-column, table-header-group, table-footer-group, table-cell
百分比: 參考containing block的寬度
計算值(computed value,參考第4條):開發人員指定的百分比值 或 一個絕對長度
有一些使用細節需要說明一下:
- margin-top和margin-bottom在inline box(看第18條)上沒有任何效果。
- 屬性值設為百分比時,參考物件為containing block的寬度,即使是margin-top,margin-bottom也是醬紫的
- margin設為一個值時,表明四個子屬性均為此值;設為兩個值時,表明margin-top和margin-bottom將為第一個值,margin-left和margin-right將為第二個值;設為三個值,表明margin-top取第一個值,margin-left和margin-right取第二個值,margin-bottom取第三個值;設為四個值,則按照top, right, bottom, left的順序從第一個值開始設定。例如:
margin:20px; 等同於 所有邊均為20px
margin:10px 20px; 等同於 margin-top & margin-bottom為10px, margin-left & margin-right為20px
margin:10px 20px 30px; 等同於 margin-top為10px, margin-left & margin-right為20px, margin-bottom為30px
margin:10px 20px 30px 40px; 等同於 margin-top為10px,margin-right為20px,margin-bottom為30px,margin-left為40px複製程式碼
嗯哼~蠻簡單的~~那就來點複雜的吧!
二. margin 重疊 詳解
何為margin重疊?兩個或多個box的相鄰margin合在一起,成為一個margin。其實就是兩個margin重疊在一塊,那麼呈現出來的效果當然是一個的咯。
如何才能產生這種效果呢?
首先,你得保證用的是垂直方向的margin(margin-top & margin-bottom)。你要是用margin-left和margin-right,試一百次都不會出現!
其次,應用物件要選好。不是所有box都可以!(突然覺得css裡的規則一套一套的,水好深~~)
最後,重疊的環境要準備好。即使物件選好了,重疊也不是百分百就有,只有滿足特定的條件才會產生。
重疊物件
在我說出之前,大家可以先想想哪些物件會有margin重疊。
我們可以試試排除法。CSS中的box無非就四種:float box,absolute positioned box,inline-level box, block-level box。
看過前面的定位文章的童鞋應該知道,float box和absolute positioned box都會脫離正常流而自成一條流,流與流之間是各玩各的,互不干擾,那麼我們可以先排除這兩種。而inline-level box在渲染過程中會參與inline formatting context,這個上下文中的box不會發生margin重疊。那麼剩下的只有block-level box。
那麼,所有的block-level box都會發生重疊嗎?
是的,但是——要排除root box(第28條)。
現在,我們大致知道重疊物件會是兩個block-level box(不包括root box)。這只是一個初篩條件,這兩個重疊物件還必須同屬一個block formatting context,具體為什麼呢,看看之前介紹bfc的文章就明白了。
重疊環境
對於一個符合條件的box而言,以下任何一種情況都會發生重疊:
- top margin 與 它的第一個處於普通流中的孩子的top margin
- height 為auto,它的bottom margin 與 它的最後一個處於普通流中的孩子的bottom margin
- bottom margin 與 它的下一個處於普通流中的兄弟的top margin
- overflow為visible(即該box不會建立bfc), min-height 的computed value(第四條)為0,height的computed value為0或auto,無孩子box,它的top margin與bottom margin
特例:overflow不為visible的block-level box的margin不會與它的任何在普通流中的孩子發生margin 重疊,但可與處在同一bfc的兄弟box發現margin 重疊。
我們來看看示例:
例1:父box與第一個子孩子box
<!DOCTYPE>
<html>
<head>
<style>
.parent{
margin-top:20px;
margin-bottom:10px;
background-color: #e6e96e;
}
.child{
background-color: aquamarine;
}
.first{
margin-top:30px;
margin-bottom:30px;
}
</style>
</head>
<body>
<div class='parent'>
<div class='child first'>haha</div>
</div>
</body>
</html>複製程式碼
chrome瀏覽器顯示:
很明顯,兩者margin發生重疊。
例2:box自身的top margin與bottom margin發生重疊 && 兄弟box之間margin重疊 && overflow不為visible的box不與孩子box發生margin重疊
<!DOCTYPE>
<html>
<head>
<style>
.parent{
width:500px;
min-height: 0;
height:auto;
margin-top:20px;
margin-bottom:10px;
background-color: #e6e96e;
}
.parent-second{
overflow:hidden;
}
.child{
background-color: aquamarine;
}
.first-child{
margin-top:30px;
margin-bottom:30px;
}
.second-child{
width:200px;
margin-top:60px;
margin-bottom:60px;
}
</style>
</head>
<body>
<div class='parent'>
</div>
<div class='parent parent-second'>
<div class='child first-child'>haha in second div</div>
<div class='child second-child'>lala in second div</div>
</div>
</body>
</html>複製程式碼
chrom顯示如下:
我們看第一個 div.parent ,它的top margin與bottom margin發生重疊,這個重疊結果又與div.parent.second-parent的top margin發生重疊,所以頁面最上方的空白處margin只有20px,這個數值可以通過檢視div.parent.second-parent的margin得到(下圖的橙色部分)。
由上圖,我們也可以看到,div.parent.second-parent並未與自己的第一個孩子box發生margin 重疊。
重疊margin計算
假設第一個box的top margin值為A,它的第一個子孩子的top margin值為B,兩者margin重疊,重疊結果會按如下規則計算:
A,B均為正值,則取max(A, B)
A為負值,B為正值,則為B-|A|
A,B均為負值,則取0-max(|A|,|B|)
來個例子
為了更好的展示重疊結果,將html元素的top margin設為100px(注:html元素產生的是root box,不會發生margin重疊),同時去掉瀏覽器為body設定的margin。
<!DOCTYPE>
<html>
<head>
<style>
html{
margin-top:100px;
}
*{
margin-top:0;
margin-bottom:0;
}
.parent{
width:100px;
height:100px;
background-color: #e6e96e;
}
.child{
width:100%;
height:100%;
background-color: aquamarine;
}
</style>
</head>
<body>
<div class='parent'>
<div class='child'>haha</div>
</div>
</body>
</html>複製程式碼
chrome展示如下:
例3:A為負值,B為正值
為div.parent及div.child加上margin-top
.parent{
width:100px;
height:100px;
margin-top:-60px;
background-color: #e6e96e;
}
.child{
width:100%;
height:100%;
margin-top:10px;
background-color: aquamarine;
}複製程式碼
chrome裡顯示如下:
用inspect方式檢視margin的範圍:
可以看到,重疊margin值為html元素所設margin值的一半,即50px。它背後的運算過程是:10-|-60| = -50
例4:A, B均為負值
為兩個div加上margin-top
.parent{
width:100px;
height:100px;
margin-top:-10px;
background-color: #e6e96e;
}
.child{
width:100%;
height:100%;
margin-top:-50px;
background-color: aquamarine;
}複製程式碼
chrome顯示如下:
再檢視下margin範圍
margin重疊的結果依然為50px,但背後的運算卻不同,0 - max(|-10|, |-50|) = 0-50 = -50
小結:只有垂直margin才可重疊,且參與的物件為同一個bfc的block-level box;重疊只有滿足特定的條件才會發生;重疊的計算因margin值的正負情況而有所不同。