學習BFC

什么是BFC

BFC全稱是Block Formatting Context,即塊格式化上下文。它是CSS2.1規(guī)范定義的,關于CSS渲染定位的一個概念。要明白BFC到底是什么,首先來看看什么是視覺格式化模型。
視覺格式化模型
視覺格式化模型(visual formatting model)是用來處理文檔并將它顯示在視覺媒體上的機制,它也是CSS中的一個概念。

視覺格式化模型定義了盒(Box)的生成,盒主要包括了塊盒、行內(nèi)盒、匿名盒(沒有名字不能被選擇器選中的盒)以及一些實驗性的盒(未來可能添加到規(guī)范中)。盒的類型由display
屬性決定。

塊盒(block box)
塊盒有以下特性:

  • 當元素的CSS屬性displayblocklist-itemtable時,它是塊級元素 block-level;
  • 視覺上呈現(xiàn)為塊,豎直排列;
  • 塊級盒參與(塊格式化上下文);
  • 每個塊級元素至少生成一個塊級盒,稱為主要塊級盒(principal block-level box)。一些元素,比如<li>,生成額外的盒來放置項目符號,不過多數(shù)元素只生成一個主要塊級盒。

行內(nèi)盒(inline box)

  • 當元素的CSS屬性display的計算值為inlineinline-block
    inline-table時,稱它為行內(nèi)級元素;
  • 視覺上它將內(nèi)容與其它行內(nèi)級元素排列為多行;典型的如段落內(nèi)容,有文本(可以有多種格式譬如著重),或圖片,都是行內(nèi)級元素;
  • 行內(nèi)級元素生成行內(nèi)級盒(inline-level boxes),參與行內(nèi)格式化上下文(inline formatting context)。同時參與生成行內(nèi)格式化上下文的行內(nèi)級盒稱為行內(nèi)盒(inline boxes)。所有display:inline
    的非替換元素生成的盒是行內(nèi)盒;
  • 不參與生成行內(nèi)格式化上下文的行內(nèi)級盒稱為原子行內(nèi)級盒(atomic inline-level boxes)。這些盒由可替換行內(nèi)元素,或display值為inline-blockinline-table
    的元素生成,不能拆分成多個盒;

匿名盒(anonymous box)
匿名盒也有份匿名塊盒與匿名行內(nèi)盒,因為匿名盒沒有名字,不能利用選擇器來選擇它們,所以它們的所有屬性都為inherit或初始默認值;
如下面例子,會創(chuàng)鍵匿名塊盒來包含毗鄰的行內(nèi)級盒:

    <p>followed by a paragraph</p>
     followed by more inline text.
   </div>```

**三個定位方案**
在定位的時候,瀏覽器就會根據(jù)元素的盒類型和上下文對這些元素進行定位,可以說盒就是定位的基本單位。定位時,有三種定位方案,分別是常規(guī)流,浮動已經(jīng)絕對定位。
常規(guī)流(Normal flow)

* 在常規(guī)流中,盒一個接著一個排列;
* 在**塊級格式化上下文**里面, 它們**豎著**排列;
* 在**行內(nèi)格式化上下文**里面, 它們**橫著**排列;
當`position`為`static`或`relative`,并且`float`為`none`
時會觸發(fā)常規(guī)流;
對于**靜態(tài)定位**(static positioning),`position: static`
,**盒的位置是常規(guī)流布局里的位置**;
對于**相對定位**(relative positioning),`position: relative`,盒偏移位置由這些屬性定義`top`
,`bottom`,`left`and`right`
。**即使有偏移,仍然保留原有的位置**,其它常規(guī)流不能占用這個位置。

浮動(Floats)
* 盒稱為浮動盒(floating boxes);
* 它位于當前行的開頭或末尾;
* 這**導致常規(guī)流環(huán)繞在它的周邊**,除非設置 clear 屬性;

絕對定位(Absolute positioning)
* 絕對定位方案,**盒從常規(guī)流中被移除**,不影響常規(guī)流的布局;
* 它的定位相對于它的包含塊,相關CSS屬性:top
,bottom
,left
及right
;
* 如果元素的屬性 `position`為`absolute`或`fixed`,它是絕對定位元素;
* 對于`position: absolute`
,元素定位將相對于最近的一個`relative`、`fixed`或`absolute`的父元素,如果沒有則相對于`body`
;

塊格式化上下文
到這里,已經(jīng)對CSS的定位有一定的了解了,從上面的信息中也可以得知,塊格式上下文是頁面CSS 視覺渲染的一部分,**用于決定塊盒子的布局及浮動相互影響范圍的一個區(qū)域**。
BFC的創(chuàng)建方法
* **根元素**或其它包含它的元素;
* **浮動** (元素的`float`不為`none`);
* **絕對定位元素** (元素的`position`為`absolute`或`fixed`);
* **行內(nèi)塊**`inline-blocks`(元素的`display: inline-block`);
* **表格單元格**(元素的`display: table-cell,HTML`表格單元格默認屬性);
* `overflow`的值不為visible的元素;
* **彈性盒 flex boxes** (元素的`display: flex`或`inline-flex`);

但其中,最常見的就是`overflow:hidden`、`float:left/right`、`position:absolute`
。也就是說,每次看到這些屬性的時候,就代表了該元素以及創(chuàng)建了一個BFC了。
BFC的范圍
BFC的范圍在MDN中是這樣描述的。
```A block formatting context contains everything inside of the element creating it that is not also inside a descendant element that creates a new block formatting context.```

中文的意思一個BFC包含創(chuàng)建該上下文元素的所有子元素,但不包括創(chuàng)建了新BFC的子元素的內(nèi)部元素。
這段看上去有點奇怪,我是這么理解的,加入有下面代碼,class名為.BFC
代表創(chuàng)建了新的塊格式化:

<div id='div_1' class='BFC'>
<div id='div_2'>
<div id='div_3'></div>
<div id='div_4'></div>
</div>
<div id='div_5' class='BFC'>
<div id='div_6'></div>
<div id='div_7'></div>
</div>
</div>```

這段代碼表示,#div_1
創(chuàng)建了一個塊格式上下文,這個上下文包括了#div_2
、#div_3
、#div_4
、#div_5
。即#div_2
中的子元素也屬于#div_1
所創(chuàng)建的BFC。但由于#div_5
創(chuàng)建了新的BFC,所以#div_6
和#div_7
就被排除在外層的BFC之外。
我認為,這從另一方角度說明,一個元素不能同時存在于兩個BFC中
BFC的一個最重要的效果是,讓處于BFC內(nèi)部的元素與外部的元素相互隔離,使內(nèi)外元素的定位不會相互影響。這是利用BFC清除浮動所利用的特性,關于清除浮動將在后面講述。
如果一個元素能夠同時處于兩個BFC中,那么就意味著這個元素能與兩個BFC中的元素發(fā)生作用,就違反了BFC的隔離作用,所以這個假設就不成立了。
BFC的效果
就如剛才提到的,BFC的最顯著的效果就是建立一個隔離的空間,斷絕空間內(nèi)外元素間相互的作用。然而,BFC還有更多的特性:
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.

In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the 'margin' properties. Vertical margins between adjacent block-level boxes in a block formatting context collapse.

In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box's line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).

簡單歸納一下:
內(nèi)部的盒會在垂直方向一個接一個排列(可以看作BFC中有一個的常規(guī)流);
處于同一個BFC中的元素相互影響,可能會發(fā)生margin collapse;
每個元素的margin box的左邊,與容器塊border box的左邊相接觸(對于從左往右的格式化,否則相反)。即使存在浮動也是如此;
BFC就是頁面上的一個隔離的獨立容器,容器里面的子元素不會影響到外面的元素,反之亦然;
計算BFC的高度時,考慮BFC所包含的所有元素,連浮動元素也參與計算;
浮動盒區(qū)域不疊加到BFC上;

這么多性質(zhì)有點難以理解,但可以作如下推理來幫助理解:html的根元素就是<html>
,而根元素會創(chuàng)建一個BFC,創(chuàng)建一個新的BFC時就相當于在這個元素內(nèi)部創(chuàng)建一個新的<html>
,子元素的定位就如同在一個新<html>
頁面中那樣,而這個新舊html頁面之間時不會相互影響的。
上述這個理解并不是最準確的理解,甚至是將因果倒置了(因為html是根元素,因此才會有BFC的特性,而不是BFC有html的特性),但這樣的推理可以幫助理解BFC這個概念。
從實際代碼來分析BFC
講了這么多,還是比較難理解,所以下面通過一些例子來加深對BFC的認識。
實例一
<style> * { margin: 0; padding: 0; } .left{ background: #73DE80; /* 綠色 / opacity: 0.5; border: 3px solid #F31264; width: 200px; height: 200px; float: left; } .right{ / 粉色 */ background: #EF5BE2; opacity: 0.5; border: 3px solid #F31264; width:400px; min-height: 100px; } .box{ background:#888; height: 100%; margin-left: 50px; }</style><div class='box'> <div class='left'> </div> <div class='right'> </div></div>

顯示效果:

綠色框('#left')向左浮動,它創(chuàng)建了一個新BFC,但暫時不討論它所創(chuàng)建的BFC。由于綠色框浮動了,它脫離了原本normal flow的位置,因此,粉色框('#right')就被定位到灰色父元素的左上角(特性3:元素左邊與容器左邊相接觸),與浮動綠色框發(fā)生了重疊。
同時,由于灰色框('#box')并沒有創(chuàng)建BFC,因此在計算高度的時候,并沒有考慮綠色框的區(qū)域(特性6:浮動區(qū)域不疊加到BFC區(qū)域上),發(fā)生了高度坍塌,這也是常見問題之一。
實例二
現(xiàn)在通過設置overflow:hidden
來創(chuàng)建BFC,再看看效果如何。
.BFC{ overflow: hidden;}<div class='box BFC'> <div class='left'> </div> <div class='right'> </div></div>

灰色框創(chuàng)建了一個新的BFC后,高度發(fā)生了變化,計算高度時它將綠色框區(qū)域也考慮進去了(特性5:計算BFC的高度時,浮動元素也參與計算);
而綠色框和紅色框的顯示效果仍然沒有任何變化。
實例三
現(xiàn)在,現(xiàn)將一些小塊添加到粉色框中,看看效果:
<style> .little{ background: #fff; width: 50px; height: 50px; margin: 10px; float: left; }</style><div class='box BFC'> <div class='left'> </div> <div class='right'> <div class='little'></div> <div class='little'></div> <div class='little'></div> </div></div>

由于粉色框沒有創(chuàng)建新的BFC,因此粉色框中白色塊受到了綠色框的影響,被擠到了右邊去了。先不管這個,看看白色塊的margin。
實例四
利用同實例二中一樣的方法,為粉色框創(chuàng)建BFC:
<div class='box BFC'> <div class='left'> </div> <div class='right BFC'> <div class='little'></div> <div class='little'></div> <div class='little'></div> </div></div>

一旦粉色框創(chuàng)建了新的BFC以后,粉色框就不與綠色浮動框發(fā)生重疊了,同時內(nèi)部的白色塊處于隔離的空間(特性4:BFC就是頁面上的一個隔離的獨立容器),白色塊也不會受到綠色浮動框的擠壓。
總結(jié)
以上就是BFC的分析,BFC的概念比較抽象,但通過實例分析應該能夠更好地理解BFC。在實際中,利用BFC可以閉合浮動(實例二),防止與浮動元素重疊(實例四)。同時,由于BFC的隔離作用,可以利用BFC包含一個元素,防止這個元素與BFC外的元素發(fā)生margin collapse。
參考
視覺格式化模型 | MDN
塊格式化上下文| MDN
CSS之BFC詳解
W3C block-formatting

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標簽默認的外補...
    _Yfling閱讀 13,796評論 1 92
  • 轉(zhuǎn)載自(http://web.jobbole.com/83274/) BFC BFC全稱是Block Format...
    居客俠閱讀 2,151評論 0 20
  • BFC全稱是Block Formatting Context,即塊格式化上下文。它是CSS2.1規(guī)范定義的,關于C...
    xf0128閱讀 352評論 0 0
  • 先前在學習CSS float時,有同學提到了BFC這個詞,作為求知好問的好學生,哪里不懂查哪里,那么今天就來研究一...
    這名字真不對閱讀 6,577評論 3 19
  • 什么是BFC BFC全稱是Block Formatting Context,即塊格式化上下文。它是CSS2.1規(guī)范...
    clfeng閱讀 492評論 0 0