引子
自己最初根本不知道 BFC 和 margin 疊加的概念,但是在寫 web 簡歷頁面的時(shí)候發(fā)現(xiàn)個(gè)奇怪的現(xiàn)象,才了解到原來 CSS 還有這么個(gè)神奇的東西。先簡單說說當(dāng)初遇到的現(xiàn)象吧,就是下面這樣:
html:
<body>
<div class="first-block"></div>
<div class="second-block">
<h2>title</h2>
</div>
</body>
css:
.first-block
{
background: #F44336;
width: 200px;
height: 200px;
}
.second-block
{
background: #00BCD4;
width: 200px;
height: 200px;
}
很簡單是吧,可是看到瀏覽器中的效果時(shí)我還是有點(diǎn)懵逼,是這樣的:
為什么 first-block 和 second-block 之間會(huì)有這么寬的間距?我并沒有給他們設(shè)置 margin 啊!
原因
外邊距折疊
那么為什么會(huì)這樣呢,先自己動(dòng)手找下原因吧,F(xiàn)12審查下元素,很快找到原因了:
原來這個(gè)間距是h2的上外邊距引起的,可是 h2 不是 second-block 的子元素么,為什么它的 margin 可以穿透出去頂?shù)?first-block ?
不懂就google一下吧,沒費(fèi)多大勁就找到原因了:
在CSS當(dāng)中,相鄰的兩個(gè)盒子(可能是兄弟關(guān)系也可能是祖先關(guān)系)的外邊距可以結(jié)合成一個(gè)單獨(dú)的外邊距。這種合并外邊距的方式被稱為折疊,并且因而所結(jié)合成的外邊距稱為折疊外邊距。
原來是外邊距折疊造成的,以前也在head first上看到過這個(gè)概念,但是當(dāng)時(shí)書上只提到說兩個(gè)相鄰的塊元素的上下外邊框直接會(huì)產(chǎn)生折疊現(xiàn)象,當(dāng)時(shí)想當(dāng)然地以為所謂的相鄰的塊元素是指兩個(gè)兄弟關(guān)系的塊元素,沒想到也包括祖先關(guān)系。
折疊的條件
兩個(gè)塊元素要產(chǎn)生折疊現(xiàn)象,必須滿足一個(gè)必備條件,那就是這兩個(gè)元素的 margin 必須是相鄰的,那么如果定義相鄰呢,w3c 規(guī)范,兩個(gè) margin 是鄰接的必須滿足以下條件:
- 必須是處于常規(guī)文檔流(非float和絕對定位)的塊級(jí)盒子,并且處于同一個(gè) BFC 當(dāng)中。
- 沒有inline盒子,沒有空隙,沒有 padding 和 border 將他們分隔開。
- 都屬于垂直方向上相鄰的外邊距,可以是下面任意一種情況:
- 元素的 margin-top 與其第一個(gè)常規(guī)文檔流的子元素的 margin-top。
- 元素的 margin-bottom 與其下一個(gè)常規(guī)文檔流的兄弟元素的 margin-top。
- height 為 auto 的元素的 margin-bottom 與其最后一個(gè)常規(guī)文檔流的子元素的 margin-bottom。
- 高度為0并且最小高度也為0,不包含常規(guī)文檔流的子元素,并且自身沒有建立新的BFC的元素的 margin-top 和 margin-bottom。
BFC
好不容易才理解了折疊,怎么又跑出來個(gè)BFC?繼續(xù)google吧:
BFC(Block formatting context)直譯為"塊級(jí)格式化上下文"。它是一個(gè)獨(dú)立的渲染區(qū)域,只有 Block-level box 參與, 它規(guī)定了內(nèi)部的 Block-level Box 如何布局,并且與這個(gè)區(qū)域外部毫不相干。
簡單來說,CSS 里的布局和渲染都是以 Box 為單位的,不同的 Box 有不同的布局規(guī)則,而 BFC 是其中的一種,相似的還有 IFC 和 CSS3 中增加的 GFC 和 FFC,這里就不深入介紹了。
BFC布局規(guī)則
BFC 的布局遵從如下規(guī)則:
- 內(nèi)部的 Box 會(huì)在垂直方向,一個(gè)接一個(gè)地放置。
- Box 垂直方向的距離由 margin 決定。屬于同一個(gè) BFC 的兩個(gè)相鄰 Box 的 margin 會(huì)發(fā)生重疊
- 每個(gè)元素的 margin box 的左邊, 與包含塊 border box 的左邊相接觸(對于從左往右的格式化,否則相反)。即使存在浮動(dòng)也是如此。
- BFC 的區(qū)域不會(huì)與 float box 重疊。
- BFC 就是頁面上的一個(gè)隔離的獨(dú)立容器,容器里面的子元素不會(huì)影響到外面的元素。反之也如此。
- 計(jì)算BFC的高度時(shí),浮動(dòng)元素也參與計(jì)算。
哪些元素會(huì)生成BFC
- 根元素。
- float 屬性不為 none。
- position 為 absolute 或 fixed。
- display 為 inline-block, table-cell, table-caption, flex, inline-flex。
- overflow 不為 visible(hidden, scroll, auto)。
結(jié)合 BFC 布局規(guī)則一看,以前學(xué)過的好多 CSS 規(guī)則方法的原理都在 BFC 這啊,比如最常用的清除浮動(dòng)什么的。
解決方案
知道了問題產(chǎn)生的原因,那就可以對癥下藥了。
-
方法一
我們注意到折疊條件的第二條:沒有inline盒子,沒有空隙,沒有 padding 和 border 將他們分隔開。 自然而然地就可以想到我們可以把 second-block 加上一個(gè)邊框來讓折疊失效:
修改css:
.second-block { background: #00BCD4; width: 200px; height: 200px; border: 1px solid rgba(0,0,0,0); /*添加一個(gè)透明邊框*/ }
效果:
嗯,折疊問題解決了,但是由于有1px的邊框,second-block 看起來會(huì)比 first-block 寬一點(diǎn),沒關(guān)系,添加
box-sizing: border-box
屬性可以解決這個(gè)問題:修改css:
.second-block { background: #00BCD4; width: 200px; height: 200px; border: 1px solid rgba(0,0,0,0); /*添加一個(gè)透明邊框*/ box-sizing: border-box; }
效果:
-
方法二
我們知道,這里之所以會(huì)產(chǎn)生折疊,是因?yàn)閮蓚€(gè) block 處于同一個(gè) BFC(根元素生成的BFC)中,那我們可以讓 second-block 單獨(dú)生成一個(gè) BFC,就可以防止出現(xiàn)折疊了。
修改css:
.second-block { background: #00BCD4; width: 200px; height: 200px; overflow: hidden; /*觸發(fā)BFC*/ }
效果:
嗯,完美~!
參考文章: