原作者:doyoe
原文鏈接:http://blog.doyoe.com/2013/12/04/css/margin%E7%B3%BB%E5%88%97%E4%B9%8B%E5%A4%96%E8%BE%B9%E8%B7%9D%E6%8A%98%E5%8F%A0/
幾乎可以不用懷疑,前端工作中的你一定遇見過 margin 折疊。
不確定?別著急,你可能寫過這樣的代碼:
p{
margin: 50px;
}
<div id="demo">
<p>我是一個華麗的段落,別看我文字少</p>
<p>我是另一個華麗的段落</p>
</div>
大家覺得這 2p 之間會發(fā)生點什么?是會合體呢?還是分開?來看看 DEMO1
margin折疊
好吧,它們真的合體了。按照常規(guī)思路,這 2p
之間的空白應該是第一個 p
的 margin-bottom 50px
加上第二 p
的 margin-top 50px
,即 50 + 50px = 100px
,但結(jié)果總是出乎意料不是么?它們之間只剩下了 50px
,這就是 margin折疊
。所以任何人遇見過我都不會覺得意外,因為這樣的Code看起來沒有任何問題。
這 2p
內(nèi)部到底發(fā)生了什么,才會有這樣的表現(xiàn)?
早在CSS1中就有對 margin
折疊的說明,我們來看看:
原文:The width of the margin on non-floating block-level elements specifies the minimum distance to the edges of surrounding boxes. Two or more adjoining vertical margins (i.e., with no border, padding or content between them) are collapsed to use the maximum of the margin values. In most cases, after collapsing the vertical margins the result is visually more pleasing and closer to what the designer expects.
翻譯:外邊距用來指定非浮動元素與其周圍盒子邊緣的最小距離。兩個或兩個以上的相鄰的垂直外邊距會被折疊并使用它們之間最大的那個外邊距值。多數(shù)情況下,折疊垂直外邊距可以在視覺上顯得更美觀,也更貼近設計師的預期。
從這段話中,我們能獲得一些有用的信息:
所以 DEMO1
中的 2p
符合折疊的條件,相鄰且都不是浮動元素,于是它們就自然合體了。至于取最大的那個值作為折疊后的最終值,因為都是50px,所以無所謂誰誰誰了。
從上文中,應該能知道個大概?在前面的文章中,我們說過,CSS的基本模型是排版。只是前端工程師現(xiàn)在做得更多的是 布局
而非 文字排版
,但CSS并未界定這兩者的區(qū)別。而 margin
折疊是為實現(xiàn)文本排版的段落間距而提供的特性。所以很多時候 margin
折疊的特性會帶給我們諸多疑惑。
再回到 DEMO1
仔細看看,你會驚訝的發(fā)現(xiàn),其實你只要設置每個 p 有相同的垂直外邊距,由于發(fā)生會 margin 折疊,所有的 p 之間,及包含塊與 p 之間的間隙都是相同的,非常美妙且實現(xiàn)簡單,不是么?這正印證了我們引用 CSS1 中的那短話:多數(shù)情況下,折疊垂直外邊距可以在視覺上顯得更美觀,也更貼近設計師的預期。
質(zhì)疑精神一直都是進步最重要的驅(qū)動力之一,我們?yōu)槭裁床荒苣??改下代碼看看:
p{
float: left;
margin: 50px;
}
只改CSS代碼,HTML不變。迫不及待的想看到驗證情況,來吧,還等什么。DEMO2
驗證浮動元素是否會發(fā)生margin折疊。
結(jié)果告訴我們,真的沒有折疊,2p
間的間隙足足有 100px
。
剩下的2點大家就自行驗證吧,相信你能得到滿意的額測試結(jié)果。
回想一下我們在 margin系列之百分比 文中提到過受書寫模式影響的一些特性,非常不幸,margin
折疊正好是其中之一。
是的,在CSS2及后續(xù)的規(guī)范中,將margin 折疊描述得更為詳盡了。
在水平書寫模式下,發(fā)生 margin
折疊的是垂直方向,即 margin-top/margin-bottom
,在垂直書寫模式下,margin
折疊發(fā)生在水平方向上,即 margin-right/margin-left
。
在CSS中,兩個或以上的塊元素(可能是兄弟,也可能不是)之間的相鄰外邊距可以被合并成一個單獨的外邊距。通過此方式合并的外邊距被稱為折疊,且產(chǎn)生的已合并的外邊距被稱為折疊外邊距。
處于同一個塊級上下文中的塊元素,沒有行框、沒有間隙、沒有內(nèi)邊距和邊框隔開它們,這樣的元素垂直邊緣毗鄰,則稱之為相鄰。
auto
。min-height
的計算值為零、height
的計算值為零或 auto
、且沒有屬于常規(guī)流中的孩子。說得很清楚了,我想是的。你可能需要注意的是發(fā)生 margin
折疊的元素不一定是兄弟關系,也能是父子或祖先的關系。
我想肯定有人要問,那我不想有 margin
折疊的情況發(fā)生,該怎么辦?其實從上面的規(guī)則中,我們已經(jīng)可以抽出避免 margin
折疊的條件來。
margin
折疊元素只發(fā)生在塊元素上;margin
折疊;margin
折疊;margin
不與任何 margin
發(fā)生折疊。margin
不與其它任何 margin
發(fā)生折疊;border-top
、padding-top
,且其第一個浮動的塊級子元素沒有間隙,則該元素的上外邊距會與其常規(guī)流中的第一個塊級子元素的上外邊距折疊。DEMO3
,在其第一個浮動子元素加個全角空格做間隙,來個反證 DEMO4
min-height
屬性為0,且沒有上或下邊框以及上或下內(nèi)邊距,且 height
為0或者 auto
,且不包含行框,且其屬于常規(guī)流的所有孩子的外邊距都折疊了,則折疊其外邊距。驗證一下 DEMO5
如果不想發(fā)生 margin
折疊,那么你可以根據(jù)上面的規(guī)則得到方法,不是么?我把它改成非塊元素,讓它浮動,讓它絕對定位,讓它 overflow:hidden
DEMO6
,用邊框隔開它們 DEMO7
…隨你怎樣,信手拈來。
今天狀態(tài)不太好,有些地方寫得欠妥,之后可能會修改一下。
BTW: 這篇文章里可能有不少之前文章中沒出現(xiàn)過的名詞,比如:塊級上下文、行框、常規(guī)流,如果你對此不甚了解,可以先找資料看看,我以后會講到。
enjoy it.
更多建議: