先前在學(xué)習(xí)CSS float時(shí),有同學(xué)提到了BFC這個(gè)詞,作為求知好問的好學(xué)生,哪里不懂查哪里,那么今天就來研究一下BFC究竟是什么。
BFC 是什么?
首先,BFC(block formatting context),中文直譯:塊格式化上下文。BFC的概念,無論是在W3C CSS2.1官方文檔,還是在MDN文檔中,都是十分難讀懂的。再翻閱了大量博客后,首先必須了解,視覺格式化模型這個(gè)概念:
視覺格式化模型
CSS 視覺格式化模型(visual formatting model)是用來處理文檔并將它顯示在視覺媒體上的機(jī)制。這是 CSS 的一個(gè)基礎(chǔ)概念。 視覺格式化模型根據(jù) CSS 盒模型為文檔的每個(gè)元素生成 0,1 或多個(gè)盒。
- 盒尺寸:明確指定,受限或沒有指定
- 盒類型:行內(nèi)(inline), 行內(nèi)級(jí)別(inline-level), 原子行內(nèi)級(jí)別(atomic inline-level), 塊(block)盒;
- 定位方案(positioning scheme): 常規(guī)流,浮動(dòng)或絕對(duì)定位;
- 樹中的其它元素: 它的子代與同代;
- 視口(viewport) 尺寸與位置;
- 內(nèi)含圖片的固定尺寸;
- 其它信息。
CSS 視覺格式化模型的一部分工作是從文檔元素生成盒。生成的盒擁有不同類型,并對(duì)視覺格式化模型的處理產(chǎn)生影響。生成盒的類型取決于 CSS 屬性
display。
對(duì)于這個(gè)概念,可以簡(jiǎn)單理解為,頁面文檔在瀏覽器(視覺媒體)上的顯示,是通過一定的模型構(gòu)建的,就如同我們?cè)趙ord中寫文章時(shí),可以進(jìn)行排版一樣,這些模型就是幫助我們?cè)跒g覽器中構(gòu)建網(wǎng)頁內(nèi)容的排版。那么頁面中的元素,就會(huì)根據(jù)這些模型生成一個(gè)個(gè)的盒子,這就是我們頁面中的最基本的單位。
BFC基本描述
塊格式化上下文(block formatting context) 是Web頁面的可視CSS渲染的一部分。它是塊盒子的布局發(fā)生及浮動(dòng)體彼此交互的區(qū)域。
再看到MDN對(duì)于BFC的描述,可以理解為頁面中的塊盒(block boxes)所使用的的渲染模型就是BFC,當(dāng)元素滿足一定條件時(shí),我們稱之為觸發(fā)了BFC,使其滿足這個(gè)渲染模型的規(guī)范。
那么問題來了,什么是塊盒(block boxes)?
塊盒(block boxes)
塊級(jí)元素與塊盒(Block-level elements and block boxes)
當(dāng)元素的 CSS 屬性
display為block,list-item或table 時(shí),它是塊級(jí)元素block-level 。塊級(jí)元素(比如<p>)視覺上呈現(xiàn)為塊,豎直排列。塊級(jí)盒參與(塊格式化上下文 block formatting context)。每個(gè)塊級(jí)元素至少生成一個(gè)塊級(jí)盒,稱為主要塊級(jí)盒(principal block-level box)。一些元素,比如<li>,生成額外的盒來放置項(xiàng)目符號(hào),不過多數(shù)元素只生成一個(gè)主要塊級(jí)盒。
主要塊級(jí)盒將包含后代元素生成的盒以及生成的內(nèi)容。它也是可以使用(定位方案 positioning scheme)的盒。
Block boxes一個(gè)塊級(jí)盒可能也是一個(gè)塊容器盒。塊容器盒(block container box) 只包含其它塊級(jí)盒,或生成一個(gè)行內(nèi)格式化上下文(inline formatting context),由此只包含行內(nèi)盒。注意塊級(jí)盒與塊容器盒概念不同。 前者描述元素跟它的父元素與兄弟元素之間的表現(xiàn),后者描述元素跟它的后代之間的影響。有些塊級(jí)盒,比如表格,不是塊容器盒。相反,一些塊容器盒,比如非替換行內(nèi)塊及非替換表格單元格,不是塊級(jí)盒。
同時(shí)是塊容器盒的塊級(jí)盒稱為塊盒(block boxes)。(譯注:塊級(jí)盒與塊盒名字相近,注意分別-)
根據(jù)MDN文檔,這里我整理了關(guān)于盒子的三個(gè)概念:
-
Block-level boxes
塊級(jí)盒(Block-level boxes)指由塊級(jí)元素構(gòu)成的盒子,每個(gè)塊級(jí)元素至少會(huì)生成一個(gè)盒子,我們稱其為主塊級(jí)盒子。塊級(jí)盒描述塊級(jí)元素跟它的父元素和兄弟元素的表現(xiàn)。
-
Block containing boxes
塊容器盒(Block containing boxes)指只包含其他塊級(jí)盒的盒子,或指生成行內(nèi)格式化上下文(inline fomatting context)的盒子,由此生成的盒子只包含行內(nèi)盒(inline boxes)。其描述了元素與后代之間的影響。
-
Block boxes
塊盒(Block boxes)指既是塊級(jí)盒,又是塊容器盒的盒子。
總的來看,塊盒屬于一個(gè)復(fù)雜概念的集合,當(dāng)一個(gè)盒子既包含塊級(jí)盒又包含塊級(jí)容器的概念時(shí),它就是一個(gè)塊盒。其中,包含了塊級(jí)元素與父親、兄弟、子代關(guān)系的描述和影響,還涉及了其他視覺格式化的內(nèi)容。因此,BFC可以說是一種CSS 渲染的表現(xiàn)形式。
對(duì)于BFC,我們還需要了解其特性及觸發(fā)條件:
BFC特性&創(chuàng)建條件
特性:
- 內(nèi)部的Box會(huì)在垂直方向,從頂部開始一個(gè)接一個(gè)地放置。
- Box垂直方向的距離由margin決定。屬于同一個(gè)BFC的兩個(gè)相鄰Box的margin會(huì)發(fā)生疊加
- 每個(gè)元素的margin box的左邊,與包含塊border box的左邊相接觸(對(duì)于從左往右的格式化,否則相反)。即使存在浮動(dòng)也是如此。
- BFC的區(qū)域不會(huì)與float box疊加。
- BFC就是頁面上的一個(gè)隔離的獨(dú)立容器,容器里面的子元素不會(huì)影響到外面的元素,反之亦然。
- 計(jì)算BFC的高度時(shí),浮動(dòng)元素也參與計(jì)算。
——《CSS之BFC詳解 》
創(chuàng)建條件:
塊格式化上下文由以下之一創(chuàng)建:
- 根元素或其它包含它的元素
- 浮動(dòng) (元素的
float不是none)- 絕對(duì)定位的元素 (元素具有
position為absolute或fixed)- 內(nèi)聯(lián)塊 inline-blocks (元素具有
display: inline-block)- 表格單元格 (元素具有
display: table-cell,HTML表格單元格默認(rèn)屬性)- 表格標(biāo)題 (元素具有
display: table-caption, HTML表格標(biāo)題默認(rèn)屬性)- 塊元素具有
overflow,且值不是visibledisplay:flow-root
BFC 可以用來做什么?
1. 解決margin重疊的問題
根據(jù)BFC的特性,同一個(gè)BFC下的兩個(gè)相鄰的盒子會(huì)出現(xiàn)垂直margin重疊的問題,這個(gè)問題會(huì)影響我們對(duì)頁面布局的控制,通常我們可以為其中一個(gè)盒子添加一個(gè)父元素,并使其觸發(fā)BFC,即可解決這個(gè)問題:

2. 浮動(dòng)帶來的布局問題
根據(jù)前面其他作者總結(jié)的BFC特性的第三條和第四條,我們知道在同一個(gè)BFC下即使有元素浮動(dòng),BFC下元素的最左邊邊緣總是會(huì)與包含它的盒子左邊相接觸,那么就會(huì)出現(xiàn)浮動(dòng)元素遮蓋了其他元素的情況。BFC還有一條重要特性:BFC的區(qū)域不會(huì)與float box 重疊。試想,在一個(gè)BFC,如果存在一個(gè)float元素,和一個(gè)div,浮動(dòng)元素會(huì)遮蓋住div,此時(shí),如果給這個(gè)div構(gòu)建一個(gè)新的BFC,由于BFC特性,內(nèi)外不相互影響,此時(shí)div會(huì)被float元素?cái)D開。
比如下面這個(gè)例子,綠色盒子會(huì)因?yàn)楦?dòng)遮蓋住紅色的盒子,但由于兩個(gè)盒子都在同一個(gè)BFC(body元素)下,根據(jù)BFC特性,紅色盒子會(huì)與包含塊相接,此時(shí)只要讓紅色盒子觸發(fā)BFC,我們?yōu)榧t色盒子添加一個(gè)觸發(fā)BFC的條件overflow:hidden,此時(shí)紅色盒子由于BFC的特性隔離開綠色,這樣我們就可以通過float元素的方式實(shí)現(xiàn)兩欄布局。

3. 清除浮動(dòng)
這里就要說到我們常見的浮動(dòng)元素引起的高度坍塌的問題。由于浮動(dòng)特性,浮動(dòng)元素會(huì)脫離父元素,我們是否可以通過觸發(fā)BFC來解決高度坍塌的問題呢?
根據(jù)特性的第6條,在觸發(fā)BFC后,這個(gè)盒子的高度將包含浮動(dòng)元素的高度,在計(jì)算時(shí),浮動(dòng)元素會(huì)參與高度計(jì)算,我們可以理解為,當(dāng)一個(gè)父元素中包含了浮動(dòng)元素,而浮動(dòng)元素超出了父元素,此時(shí)我們?yōu)楦冈貏?chuàng)建BFC,那么浮動(dòng)元素就會(huì)包裹進(jìn)這個(gè)BFC解決了父元素中高度塌陷的問題。
如下面的例子,div.parent包含了兩個(gè)div.child,而兩個(gè)div由于賦予了float:left使其浮動(dòng),導(dǎo)致了div.parent高度的坍塌,此時(shí)我們給div.parent添加一個(gè)overflow:hidden屬性值,使div.parent觸發(fā)BFC,由于BFC下的盒子會(huì)包含浮動(dòng)元素的高度,因此盒子就被撐了起來,高度塌陷的問題也就得到了解決。

除了上面的清除浮動(dòng)用到了BFC的一些特性外,還有一些其他的清除浮動(dòng)的技巧,這里就不再做深入討論。
其他
在學(xué)習(xí)BFC過程中,主要借鑒了一些博客文章及MDN的說明,由于自己的書面表達(dá)能力有限,這篇文章主要用于記錄學(xué)習(xí)BFC的過程,如有表述不清的地方還請(qǐng)見諒。
此外,為了補(bǔ)充疏漏的地方,增加W3C官方文檔的閱讀。不過官方文檔中BFC及相關(guān)概念大多為描述,沒有非常確切的定性,所以這里只放出來作為參考。由于自己的英語水平有限,如有描述不當(dāng)?shù)牡胤?,?qǐng)以W3C CSS官方文檔為準(zhǔn)。
BFC(block formatting context)的官方描述
我們來看看W3C CSS2.1文檔中關(guān)于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).
簡(jiǎn)單的人肉+谷歌翻譯:
浮動(dòng)元素、絕對(duì)定位元素、塊容器(比如 inline-blocks,table-cells,table-captions)及
overflow值不為visable(除非該值已被傳到視口)的塊盒(block boxes),都會(huì)為其內(nèi)容建立新的塊格式化上下文(BFC)。在一個(gè)BFC中,盒子將會(huì)垂直的從包含塊(containing block)的頂部一個(gè)接一個(gè)的向下布置,兄弟元素之間的垂直距離將由
margin屬性確定。在BFC中,兩個(gè)相鄰的塊級(jí)盒子(block-level boxes)之間的垂直邊距(vertical margins)將會(huì)坍塌。在一個(gè)BFC中,每個(gè)盒子的左外邊緣會(huì)接觸包容塊的左邊緣(對(duì)于從右往左的格式,則相反)。即便是在浮動(dòng)
floats情況下也是如此(盡管盒子的線框可能由于浮動(dòng)而收縮),除非盒子建立了一個(gè)新的BFC(這種情況下,盒子自身可能會(huì)因?yàn)楦?dòng)變得更窄)。
格式化上下文(formatting context)
Boxes in the normal flow belong to a formatting context, which may be block or inline, but not both simultaneously.
Block-level boxes participate in a block formatting context. Inline-level boxes participate in an inline formatting context.
簡(jiǎn)單的人肉+谷歌翻譯:
正常流中屬于格式化上下文的盒子,可以是塊或者內(nèi)聯(lián),但不能同時(shí)存在。塊級(jí)盒參與塊級(jí)格式化上下文,行內(nèi)級(jí)參與行級(jí)格式上下文。
包含塊(containing block)
CSS 2.1 W3C 文檔:
In CSS 2.1, many box positions and sizes are calculated with respect to the edges of a rectangular box called a containing block. In general, generated boxes act as containing blocks for descendant boxes; we say that a box "establishes" the containing block for its descendants. The phrase "a box's containing block" means "the containing block in which the box lives," not the one it generates.
Each box is given a position with respect to its containing block, but it is not confined by this containing block; it may overflow.
簡(jiǎn)單的人肉+谷歌翻譯:
在 CSS2.1中,許多盒子的定位(positions)和尺寸(size)被用來計(jì)算相對(duì)于矩形盒子的邊緣,這種矩形盒子我們稱其為包容塊(containing block)。通常,生成的盒子將作為后代盒子的包含塊,我們稱其一個(gè)盒子為其后代建立(establishes)包容塊?!耙粋€(gè)盒子的包容塊(a box's containning block)“指”這個(gè)盒子所在的包容塊“,而不是指這個(gè)盒子產(chǎn)生的塊。
塊級(jí)盒子(block-level boxes)
Block-level elements are those elements of the source document that are formatted visually as blocks (e.g., paragraphs). The following values of the 'display' property make an element block-level: 'block', 'list-item', and 'table'.
Block-level boxes are boxes that participate in a block formatting context. Each block-level element generates a principal block-level box that contains descendant boxes and generated content and is also the box involved in any positioning scheme. Some block-level elements may generate additional boxes in addition to the principal box: 'list-item' elements. These additional boxes are placed with respect to the principal box.
Except for table boxes, which are described in a later chapter, and replaced elements, a block-level box is also a block container box. A block container box either contains only block-level boxes or establishes an inline formatting context and thus contains only inline-level boxes. Not all block container boxes are block-level boxes: non-replaced inline blocks and non-replaced table cells are block containers but not block-level boxes. Block-level boxes that are also block containers are called block boxes.
The three terms "block-level box," "block container box," and "block box" are sometimes abbreviated as "block" where unambiguous.
簡(jiǎn)單的人肉+谷歌翻譯:
塊級(jí)元素是源文檔中作為塊被視覺格式化的元素(比如:paragraphs)。
display屬性作為元素塊級(jí)的表示,其值有block、list-item,table。塊級(jí)元素是參與BFC的盒子。每一個(gè)塊級(jí)元素會(huì)生成一個(gè)主要塊級(jí)元素盒(principal block-level box),盒中包含后代盒子和生成的內(nèi)容,同時(shí)這個(gè)盒也包含任意定位方案。除了主塊級(jí)元素盒外,一些塊級(jí)元素也可能產(chǎn)生額外的盒子,比如:
list-item元素。這些額外的盒子會(huì)被放置在相對(duì)主盒的地方。除了后面章節(jié)描述的表格盒(table boxes)和替換元素外,塊級(jí)元素盒(block-level box)同時(shí)也是一個(gè)塊容器盒(block container box)。塊容器盒要么只包塊級(jí)盒,或建立內(nèi)聯(lián)格式化上下文(inline formatting)的情況下只包含內(nèi)聯(lián)級(jí)盒子(inline-level boxes)。并非所有塊容器盒都是塊級(jí)盒,不包含內(nèi)聯(lián)盒子和表單cell(table cell)的是塊容器(block container),而不是塊級(jí)盒(block-level boxes)。既是塊級(jí)盒(block-level boxes)同時(shí)也是塊容器(block container)的稱為塊盒(block boxes)。
塊級(jí)盒(block-level block),塊容器盒(block container box),塊盒(block box)這三個(gè)術(shù)語有時(shí)會(huì)縮寫為明確的:塊(block)
參考:
