Margin Collapse、BFC外加一點(diǎn)點(diǎn)“清除浮動(dòng)”

建議在PC端閱讀
本文面向?qū)ο螅簩?duì)標(biāo)題中的概念基本不了解或僅僅聽(tīng)說(shuō)過(guò)名字的人。如果已有一定了解請(qǐng)直接拉到最下看推薦閱讀
另外其實(shí)這是個(gè)很大的話題共螺,這里僅當(dāng)拋磚引玉,并提供進(jìn)一步閱讀的文章

一些demo

我們先從一些現(xiàn)象開(kāi)始入手吧↓(建議在另一窗口打開(kāi)示例情竹,一邊修改示例一邊閱讀效果更佳)
本文示例

例一

第一個(gè)例子是最常見(jiàn)的一種邊界折疊(Margin Collapse)。一般我們很容易忽略掉這個(gè)現(xiàn)象匀哄,因?yàn)樗臀覀兇蠖鄶?shù)情況下的直覺(jué)比較符合秦效。
例如第一個(gè)例子里的兩個(gè)p標(biāo)簽,它們的關(guān)系是并列的涎嚼,所以我們?cè)O(shè)置margin:20px 0;時(shí)心里其實(shí)是想讓兩個(gè)p標(biāo)簽之間相隔20px(事實(shí)上現(xiàn)在也是這樣表現(xiàn)的)阱州。
但有時(shí)候我們并不想讓它們折疊(我們希望“修正”的同時(shí),保持使用margin并盡量少添加難以理解的CSS屬性)法梯,那要怎么做呢苔货?(即需要清楚產(chǎn)生邊界折疊的條件)

例子中提示的做法是用一個(gè)設(shè)置了overflow:hidden;的div將其包裹犀概,但是overflow:hidden;作用明明是剪裁溢出的內(nèi)容,為何能產(chǎn)生取消邊界折疊的效果呢夜惭?直接給出這樣的解決方案讓人難以理解而且容易忘記姻灶。

(似乎只能通過(guò)外加BFC創(chuàng)造不同的BFC來(lái)避免...)

例二

如果說(shuō)第一個(gè)例子一定程度上還算符合直覺(jué),那第二個(gè)例子的情況老實(shí)說(shuō)我是不能理解的...一度讓我以為是出了bug...但了解了Margin Collapse的產(chǎn)生條件之后,相信你能明白為何會(huì)出現(xiàn)這種現(xiàn)象以及如果消除它诈茧。

例三

第三個(gè)例子主要和BFC有關(guān)产喉。一般說(shuō)到"清除浮動(dòng)"就會(huì)想到clear:both; overflow:hidden;之類(lèi).但是給父元素設(shè)置浮動(dòng)居然也能"清除浮動(dòng)"???估計(jì)深受浮動(dòng)折磨的人看到這現(xiàn)象會(huì)進(jìn)一步崩潰:為什么這樣也能清除浮動(dòng)?到底有多少種清除浮動(dòng)的方法敢会?(當(dāng)然“清除浮動(dòng)”不是本文重點(diǎn)曾沈,若想進(jìn)一步了解請(qǐng)看推薦閱讀


所以這些現(xiàn)象到底跟標(biāo)題中的Margin Collapse、BFC有什么關(guān)系呢鸥昏?

上面例子的現(xiàn)象你都能給出解釋和解決方案嗎塞俱?如果都沒(méi)問(wèn)題的話恭喜你,可以直接下拉到最后看推薦閱讀進(jìn)行進(jìn)一步閱讀了吏垮。如果一頭霧水的話也沒(méi)關(guān)系障涯,我們一步一步來(lái)看是怎么回事。

想一下惫皱,有沒(méi)有覺(jué)得這有點(diǎn)像讀英語(yǔ)時(shí)每個(gè)單詞都認(rèn)識(shí)像樊,連在一起就看不懂的情況?這是因?yàn)槿狈ο嚓P(guān)的語(yǔ)法知識(shí)(當(dāng)然也有可能是缺少上下文)
每一條CSS Rule就像一個(gè)個(gè)單詞旅敷,而相應(yīng)的語(yǔ)法就是w3c制定的布局方案了(當(dāng)然這里的類(lèi)比不完全準(zhǔn)確生棍,自然語(yǔ)言是與上下文有關(guān)的語(yǔ)法,而CSS是與上下文無(wú)關(guān)的語(yǔ)法)

那w3c是怎么規(guī)定Margin Collapse的呢媳谁?


產(chǎn)生折疊的必備條件:margin必須是鄰接的!

而根據(jù)w3c規(guī)范涂滴,兩個(gè)margin是鄰接的必須滿足以下條件:
1.必須是處于常規(guī)文檔流(非float和絕對(duì)定位)的塊級(jí)盒子,并且處于同一個(gè)BFC(BFC產(chǎn)生條件見(jiàn)下文)當(dāng)中。
2.沒(méi)有線盒晴音,沒(méi)有空隙(clearance柔纵,本文不涉及),沒(méi)有padding和border將他們分隔開(kāi)
3.都屬于垂直方向上相鄰的外邊距锤躁,可以是下面任意一種情況

  • 元素的margin-top與其第一個(gè)常規(guī)文檔流的子元素的margin-top(即例二)
  • 元素的margin-bottom與其下一個(gè)常規(guī)文檔流的兄弟元素的margin-top(即例一)
  • height為auto的元素的margin-bottom與其最后一個(gè)常規(guī)文檔流的子元素的margin-bottom
  • 高度為0并且最小高度也為0搁料,不包含常規(guī)文檔流的子元素,并且自身沒(méi)有建立新的BFC的元素的margin-top和margin-bottom

以上的條件意味著下列的規(guī)則:

  • 創(chuàng)建了新的BFC的元素(BFC元素的產(chǎn)生條件見(jiàn)下文)與它的子元素的外邊距不會(huì)折疊
  • 浮動(dòng)元素不與任何元素的外邊距產(chǎn)生折疊(包括其父元素和子元素)
  • 絕對(duì)定位元素不與任何元素的外邊距產(chǎn)生折疊
  • inline-block元素不與任何元素的外邊距產(chǎn)生折疊
  • 一個(gè)常規(guī)文檔流元素的margin-bottom與它下一個(gè)常規(guī)文檔流的兄弟元素的margin-top會(huì)產(chǎn)生折疊系羞,除非它們之間存在間隙(clearance)郭计。
  • 一個(gè)常規(guī)文檔流元素的margin-top 與其第一個(gè)常規(guī)文檔流的子元素的margin-top產(chǎn)生折疊,條件為父元素不包含 padding 和 border 椒振,子元素不包含 clearance昭伸。
  • 一個(gè) 'height' 為 'auto' 并且 'min-height' 為 '0'的常規(guī)文檔流元素的 margin-bottom 會(huì)與其最后一個(gè)常規(guī)文檔流子元素的 margin-bottom 折疊,條件為父元素不包含 padding 和 border 澎迎,子元素的 margin-bottom 不與包含 clearance 的 margin-top 折疊庐杨。
    一個(gè)不包含border-top选调、border-bottom、padding-top灵份、padding-bottom的常規(guī)文檔流元素仁堪,并且其 'height' 為 0 或 'auto', 'min-height' 為 '0'各吨,其里面也不包含行盒(line box)枝笨,其自身的 margin-top 和 margin-bottom 會(huì)折疊。

折疊的結(jié)果:

兩個(gè)相鄰的外邊距都是正數(shù)時(shí)揭蜒,折疊結(jié)果是它們兩者之間較大的值横浑。
兩個(gè)相鄰的外邊距都是負(fù)數(shù)時(shí),折疊結(jié)果是兩者絕對(duì)值的較大值屉更。
兩個(gè)外邊距一正一負(fù)時(shí)徙融,折疊結(jié)果是兩者的相加的和。

摘自w3plus: http://www.w3cplus.com/css/understanding-bfc-and-margin-collapse.html ? w3cplus.com


BFC(Block Formatting Contexts瑰谜,塊級(jí)上下文)的產(chǎn)生條件

BFC在CSS3中改為Flow Root欺冀,觸發(fā)條件多了下面加粗的部分

  • 浮動(dòng)元素,float 除 none 以外的值
  • 絕對(duì)定位元素萨脑,position(absolute隐轩,fixed
  • display 為以下其中之一的值 inline-blocks,table-cells渤早,table-captions
  • overflow 除了 visible 以外的值(hidden职车,auto,scroll)

注:"display:table" 本身并不產(chǎn)生 BFC鹊杖,但它會(huì)產(chǎn)生匿名框悴灵,匿名框中包含 "display:table-cell" 的框會(huì)產(chǎn)成 BFC。


好的骂蓖,上面一口氣丟了一大堆定義和條件出來(lái)积瞒,估計(jì)直接強(qiáng)行讀下來(lái)已經(jīng)有點(diǎn)暈了。沒(méi)關(guān)系我們結(jié)合文章開(kāi)頭的例子看一下吧登下。

例子解析

例一

顯然例一符合折疊的第一個(gè)條件:

1.必須是處于常規(guī)文檔流(非float和絕對(duì)定位)的塊級(jí)盒子,并且處于同一個(gè)BFC(BFC產(chǎn)生條件見(jiàn)下文)當(dāng)中茫孔。

那要取消折疊自然就是破壞第一個(gè)條件啦,于是第一反應(yīng)就是用overflow:hidden;來(lái)把p標(biāo)簽變成BFC被芳。然后你就會(huì)開(kāi)心的發(fā)現(xiàn)......并沒(méi)有什么變化银酬。
為什么呢?我們?cè)賮?lái)讀一下第一個(gè)條件

"....處于同一個(gè)BFC當(dāng)中筐钟。"

嗯,這里要搞清楚一個(gè)概念赋朦,BFC是一個(gè)區(qū)域篓冲,不是一個(gè)元素李破。
也就是說(shuō),你給p標(biāo)簽設(shè)的overflow:hidden;只是把p標(biāo)簽里的內(nèi)容設(shè)置成一個(gè)新的BFC壹将,但是這個(gè)p標(biāo)簽仍處于它之前所在BFC中這個(gè)事實(shí)沒(méi)有改變嗤攻。
所以給出的解決方案是外面多包裹一個(gè)div再把這個(gè)div變成BFC(如overflow:hidden;),這樣被包裹的p標(biāo)簽處于它的父元素創(chuàng)建的BFC,而它的父元素此時(shí)和另一個(gè)p標(biāo)簽處于同一個(gè)BFC诽俯,所以被包裹的p標(biāo)簽與另一個(gè)p標(biāo)簽自然不處于同一個(gè)BFC了(表達(dá)能力有限妇菱,這段寫(xiě)的有點(diǎn)繞)

雖然要多加一個(gè)標(biāo)簽,但其實(shí)仔細(xì)想想也沒(méi)有破壞語(yǔ)義性暴区。因?yàn)檎嵌嗉恿艘粋€(gè)標(biāo)簽才表示了被包裹的內(nèi)容與外面的內(nèi)容不處于同一個(gè)上下文闯团。

例二

例二其實(shí)也是因?yàn)樘幱谕粋€(gè)BFC中而導(dǎo)致的,你可以試著給.parent加上overflow:hidden;看看效果仙粱。demo中讓你嘗試加border或padding主要是因?yàn)檫@個(gè)折疊條件比較容易忽略房交。
不過(guò)產(chǎn)生BFC的條件多多少少都會(huì)有副作用,而這里其實(shí)只要讓子元素margin與父元素marigin不相鄰(折疊的最基本要求)就可以了
這里推薦的解決方案是使用偽元素:

.fathet:before{
     content:"";
     display: table;
}

首先content是偽元素生成的必要條件
這里的原理是:display:table;會(huì)生成包含display:table-cell;的匿名框(見(jiàn)上文BFC產(chǎn)生條件)伐割,從而產(chǎn)生了一個(gè)“沒(méi)有高度”的BFC區(qū)域(個(gè)人理解候味,如有錯(cuò)誤歡迎指出)將子元素和父元素的margin分割開(kāi)了。

例三

這里主要是因?yàn)锽FC的特性所致
BFC有如下特性:

  1. BFC可以包含浮動(dòng)元素

w3c原文:“'Auto' heights for block formatting context roots”隔心,也就是 BFC 會(huì)根據(jù)子元素的情況自動(dòng)適應(yīng)高度白群,即使其子元素中包括浮動(dòng)元素。

  1. BFC可以阻止元素被浮動(dòng)元素覆蓋(即取消文字環(huán)繞的效果)

所以例三給父元素設(shè)置浮動(dòng)后高度不再坍塌只是因?yàn)楦冈氐漠a(chǎn)生了BFC硬霍,而用其他產(chǎn)生BFC的方法同樣能包含浮動(dòng)元素帜慢。
值得注意的是,雖然BFC有閉合浮動(dòng)的效果须尚,但并不推薦利用BFC閉合浮動(dòng)崖堤。因?yàn)槊恳粋€(gè)用于產(chǎn)生BFC的條件都有一定程度的副作用手趣,盡管當(dāng)時(shí)可能副作用不明顯乌昔,但也是個(gè)很大的隱患。
推薦的“清除浮動(dòng)”的方法是Nicolas Gallagher大神提出的micro clearfix hack:

.clearfix:after{
  content:"";
  display:table;
  clear:both;
}

總結(jié)

  1. Margin Collapse不是bug臼予,而是在CSS布局規(guī)則里面有規(guī)定的撩轰,具體出現(xiàn)情況見(jiàn)上文胯甩。
  2. BFC是一個(gè)區(qū)域,或者說(shuō)是元素具有的一個(gè)特性堪嫂,而不是元素本身偎箫。
  3. BFC能閉合浮動(dòng),但不應(yīng)該用BFC來(lái)閉合浮動(dòng)皆串。

思考

先給body加上border淹办,方便觀察。
試著給body標(biāo)簽加上margin恶复,再給body的第一個(gè)子元素(需要是塊級(jí)的)設(shè)置margin怜森,看是否會(huì)發(fā)生折疊速挑?
如果會(huì)發(fā)生折疊,也就是符合條件1

1.必須是處于常規(guī)文檔流(非float和絕對(duì)定位)的塊級(jí)盒子,并且處于同一個(gè)BFC當(dāng)中副硅。

也就是處于同一個(gè)BFC中姥宝。這時(shí)如果給第一個(gè)子元素設(shè)置浮動(dòng)又會(huì)發(fā)生什么呢?

實(shí)驗(yàn)的結(jié)果是body無(wú)法包含浮動(dòng)元素恐疲,這與BFC的特性矛盾腊满。但同時(shí)卻能發(fā)生Margin Collapse,也就是處于同一個(gè)BFC中培己。這似乎有點(diǎn)矛盾碳蛋。
當(dāng)然我也沒(méi)想通這是為什么,如果有明白的人歡迎指教漱凝。我能想到的就只有因?yàn)閎ody標(biāo)簽太特殊疮蹦,這是瀏覽器對(duì)它作出的特殊處理......


推薦閱讀

四篇文章搞定BFC(建議依次閱讀)

  1. 詳說(shuō) Block Formatting Contexts (塊級(jí)格式化上下文)
  2. W3C的官方定義
  3. Understanding Block Formatting Contexts in CSS
  4. Formatting contexts

BFC與Margin Collapse

深入理解BFC和Margin Collapse

搞定清除浮動(dòng)

那些年我們一起清除過(guò)的浮動(dòng)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市茸炒,隨后出現(xiàn)的幾起案子愕乎,更是在濱河造成了極大的恐慌,老刑警劉巖壁公,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件感论,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡紊册,警方通過(guò)查閱死者的電腦和手機(jī)比肄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)囊陡,“玉大人芳绩,你說(shuō)我怎么就攤上這事∽卜矗” “怎么了妥色?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)遏片。 經(jīng)常有香客問(wèn)我嘹害,道長(zhǎng),這世上最難降的妖魔是什么吮便? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任笔呀,我火速辦了婚禮,結(jié)果婚禮上髓需,老公的妹妹穿的比我還像新娘许师。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布枯跑。 她就那樣靜靜地躺著惨驶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪敛助。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天屋确,我揣著相機(jī)與錄音纳击,去河邊找鬼。 笑死攻臀,一個(gè)胖子當(dāng)著我的面吹牛焕数,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播刨啸,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼堡赔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了设联?” 一聲冷哼從身側(cè)響起善已,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎离例,沒(méi)想到半個(gè)月后换团,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宫蛆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年艘包,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耀盗。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡想虎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出叛拷,到底是詐尸還是另有隱情舌厨,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布胡诗,位于F島的核電站邓线,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏煌恢。R本人自食惡果不足惜骇陈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瑰抵。 院中可真熱鬧你雌,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至氓栈,卻和暖如春渣磷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背授瘦。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工醋界, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人提完。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓形纺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親徒欣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子逐样,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 問(wèn)答題47 /72 常見(jiàn)瀏覽器兼容性問(wèn)題與解決方案? 參考答案 (1)瀏覽器兼容問(wèn)題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,754評(píng)論 1 92
  • 1.浮動(dòng)元素有什么特征戏羽?對(duì)父容器、其他浮動(dòng)元素楼吃、普通元素始花、文字分別有什么影響? 何謂浮動(dòng)元素?有什么特征孩锡?所謂浮動(dòng)...
    草鞋弟閱讀 814評(píng)論 0 1
  • 浮動(dòng)元素的特征酷宵,對(duì)父容器、對(duì)其他浮動(dòng)元素躬窜、普通元素浇垦、文字的影響。 浮動(dòng)會(huì)使應(yīng)用的元素脫離文檔流荣挨。按指定的位置來(lái)移動(dòng)...
    邢烽朔閱讀 663評(píng)論 2 7
  • 1.在什么場(chǎng)景下會(huì)出現(xiàn)外邊距合并?如何合并口锭?如何不讓相鄰元素外邊距合并朦前?給個(gè)父子外邊距合并的范例 概念:在CSS當(dāng)...
    饑人谷_任磊閱讀 650評(píng)論 0 3
  • 在什么場(chǎng)景下會(huì)出現(xiàn)外邊距合并?如何合并恩伺?如何不讓相鄰元素外邊距合并赴背?給個(gè)父子外邊距合并的范例 在CSS當(dāng)中,相鄰的...
    Nicklzy閱讀 844評(píng)論 0 49