先前在學(xué)習(xí)CSS float時,有同學(xué)提到了BFC這個詞,作為求知好問的好學(xué)生,哪里不懂查哪里,那么今天就來研究一下BFC究竟是什么。
BFC 是什么?
首先,BFC(block formatting context),中文直譯:塊格式化上下文。BFC的概念,無論是在W3C CSS2.1官方文檔,還是在MDN文檔中,都是十分難讀懂的。再翻閱了大量博客后,首先必須了解,視覺格式化模型這個概念:
視覺格式化模型
CSS 視覺格式化模型(visual formatting model)是用來處理文檔并將它顯示在視覺媒體上的機(jī)制。這是 CSS 的一個基礎(chǔ)概念。 視覺格式化模型根據(jù) CSS 盒模型為文檔的每個元素生成 0,1 或多個盒。
- 盒尺寸:明確指定,受限或沒有指定
- 盒類型:行內(nèi)(inline), 行內(nèi)級別(inline-level), 原子行內(nèi)級別(atomic inline-level), 塊(block)盒;
- 定位方案(positioning scheme): 常規(guī)流,浮動或絕對定位;
- 樹中的其它元素: 它的子代與同代;
- 視口(viewport) 尺寸與位置;
- 內(nèi)含圖片的固定尺寸;
- 其它信息。
CSS 視覺格式化模型的一部分工作是從文檔元素生成盒。生成的盒擁有不同類型,并對視覺格式化模型的處理產(chǎn)生影響。生成盒的類型取決于 CSS 屬性
display
。
對于這個概念,可以簡單理解為,頁面文檔在瀏覽器(視覺媒體)上的顯示,是通過一定的模型構(gòu)建的,就如同我們在word中寫文章時,可以進(jìn)行排版一樣,這些模型就是幫助我們在瀏覽器中構(gòu)建網(wǎng)頁內(nèi)容的排版。那么頁面中的元素,就會根據(jù)這些模型生成一個個的盒子,這就是我們頁面中的最基本的單位。
BFC基本描述
塊格式化上下文(block formatting context) 是Web頁面的可視CSS渲染的一部分。它是塊盒子的布局發(fā)生及浮動體彼此交互的區(qū)域。
再看到MDN對于BFC的描述,可以理解為頁面中的塊盒(block boxes)所使用的的渲染模型就是BFC,當(dāng)元素滿足一定條件時,我們稱之為觸發(fā)了BFC,使其滿足這個渲染模型的規(guī)范。
那么問題來了,什么是塊盒(block boxes)?
塊盒(block boxes)
塊級元素與塊盒(Block-level elements and block boxes)
當(dāng)元素的 CSS 屬性
display
為block
,list-item
或table 時,它是塊級元素
block-level 。塊級元素(比如<p>)視覺上呈現(xiàn)為塊,豎直排列。塊級盒參與(塊格式化上下文 block formatting context)。每個塊級元素至少生成一個塊級盒,稱為主要塊級盒(principal block-level box)。一些元素,比如<li>,生成額外的盒來放置項目符號,不過多數(shù)元素只生成一個主要塊級盒。
主要塊級盒將包含后代元素生成的盒以及生成的內(nèi)容。它也是可以使用(定位方案 positioning scheme)的盒。
Block boxes一個塊級盒可能也是一個塊容器盒。塊容器盒(block container box) 只包含其它塊級盒,或生成一個行內(nèi)格式化上下文(inline formatting context),由此只包含行內(nèi)盒。注意塊級盒與塊容器盒概念不同。 前者描述元素跟它的父元素與兄弟元素之間的表現(xiàn),后者描述元素跟它的后代之間的影響。有些塊級盒,比如表格,不是塊容器盒。相反,一些塊容器盒,比如非替換行內(nèi)塊及非替換表格單元格,不是塊級盒。
同時是塊容器盒的塊級盒稱為塊盒(block boxes)。(譯注:塊級盒與塊盒名字相近,注意分別-)
根據(jù)MDN文檔,這里我整理了關(guān)于盒子的三個概念:
-
Block-level boxes
塊級盒(Block-level boxes)指由塊級元素構(gòu)成的盒子,每個塊級元素至少會生成一個盒子,我們稱其為主塊級盒子。塊級盒描述塊級元素跟它的父元素和兄弟元素的表現(xiàn)。
-
Block containing boxes
塊容器盒(Block containing boxes)指只包含其他塊級盒的盒子,或指生成行內(nèi)格式化上下文(inline fomatting context)的盒子,由此生成的盒子只包含行內(nèi)盒(inline boxes)。其描述了元素與后代之間的影響。
-
Block boxes
塊盒(Block boxes)指既是塊級盒,又是塊容器盒的盒子。
總的來看,塊盒屬于一個復(fù)雜概念的集合,當(dāng)一個盒子既包含塊級盒又包含塊級容器的概念時,它就是一個塊盒。其中,包含了塊級元素與父親、兄弟、子代關(guān)系的描述和影響,還涉及了其他視覺格式化的內(nèi)容。因此,BFC可以說是一種CSS 渲染的表現(xiàn)形式。
對于BFC,我們還需要了解其特性及觸發(fā)條件:
BFC特性&創(chuàng)建條件
特性:
- 內(nèi)部的Box會在垂直方向,從頂部開始一個接一個地放置。
- Box垂直方向的距離由margin決定。屬于同一個BFC的兩個相鄰Box的margin會發(fā)生疊加
- 每個元素的margin box的左邊,與包含塊border box的左邊相接觸(對于從左往右的格式化,否則相反)。即使存在浮動也是如此。
- BFC的區(qū)域不會與float box疊加。
- BFC就是頁面上的一個隔離的獨立容器,容器里面的子元素不會影響到外面的元素,反之亦然。
- 計算BFC的高度時,浮動元素也參與計算。
——《CSS之BFC詳解 》
創(chuàng)建條件:
塊格式化上下文由以下之一創(chuàng)建:
- 根元素或其它包含它的元素
- 浮動 (元素的
float
不是none
)- 絕對定位的元素 (元素具有
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
,且值不是visible
display
:flow-root
BFC 可以用來做什么?
1. 解決margin重疊的問題
根據(jù)BFC的特性,同一個BFC下的兩個相鄰的盒子會出現(xiàn)垂直margin重疊的問題,這個問題會影響我們對頁面布局的控制,通常我們可以為其中一個盒子添加一個父元素,并使其觸發(fā)BFC,即可解決這個問題:
2. 浮動帶來的布局問題
根據(jù)前面其他作者總結(jié)的BFC特性的第三條和第四條,我們知道在同一個BFC下即使有元素浮動,BFC下元素的最左邊邊緣總是會與包含它的盒子左邊相接觸,那么就會出現(xiàn)浮動元素遮蓋了其他元素的情況。BFC還有一條重要特性:BFC的區(qū)域不會與float box 重疊。試想,在一個BFC,如果存在一個float元素,和一個div,浮動元素會遮蓋住div,此時,如果給這個div構(gòu)建一個新的BFC,由于BFC特性,內(nèi)外不相互影響,此時div會被float元素擠開。
比如下面這個例子,綠色盒子會因為浮動遮蓋住紅色的盒子,但由于兩個盒子都在同一個BFC(body元素)下,根據(jù)BFC特性,紅色盒子會與包含塊相接,此時只要讓紅色盒子觸發(fā)BFC,我們?yōu)榧t色盒子添加一個觸發(fā)BFC的條件overflow:hidden,此時紅色盒子由于BFC的特性隔離開綠色,這樣我們就可以通過float元素的方式實現(xiàn)兩欄布局。
3. 清除浮動
這里就要說到我們常見的浮動元素引起的高度坍塌的問題。由于浮動特性,浮動元素會脫離父元素,我們是否可以通過觸發(fā)BFC來解決高度坍塌的問題呢?
根據(jù)特性的第6條,在觸發(fā)BFC后,這個盒子的高度將包含浮動元素的高度,在計算時,浮動元素會參與高度計算,我們可以理解為,當(dāng)一個父元素中包含了浮動元素,而浮動元素超出了父元素,此時我們?yōu)楦冈貏?chuàng)建BFC,那么浮動元素就會包裹進(jìn)這個BFC解決了父元素中高度塌陷的問題。
如下面的例子,div.parent
包含了兩個div.child
,而兩個div由于賦予了float:left
使其浮動,導(dǎo)致了div.parent
高度的坍塌,此時我們給div.parent
添加一個overflow:hidden
屬性值,使div.parent
觸發(fā)BFC,由于BFC下的盒子會包含浮動元素的高度,因此盒子就被撐了起來,高度塌陷的問題也就得到了解決。
除了上面的清除浮動用到了BFC的一些特性外,還有一些其他的清除浮動的技巧,這里就不再做深入討論。
其他
在學(xué)習(xí)BFC過程中,主要借鑒了一些博客文章及MDN的說明,由于自己的書面表達(dá)能力有限,這篇文章主要用于記錄學(xué)習(xí)BFC的過程,如有表述不清的地方還請見諒。
此外,為了補充疏漏的地方,增加W3C官方文檔的閱讀。不過官方文檔中BFC及相關(guān)概念大多為描述,沒有非常確切的定性,所以這里只放出來作為參考。由于自己的英語水平有限,如有描述不當(dāng)?shù)牡胤剑堃訵3C 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).
簡單的人肉+谷歌翻譯:
浮動元素、絕對定位元素、塊容器(比如 inline-blocks,table-cells,table-captions)及
overflow
值不為visable
(除非該值已被傳到視口)的塊盒(block boxes),都會為其內(nèi)容建立新的塊格式化上下文(BFC)。在一個BFC中,盒子將會垂直的從包含塊(containing block)的頂部一個接一個的向下布置,兄弟元素之間的垂直距離將由
margin
屬性確定。在BFC中,兩個相鄰的塊級盒子(block-level boxes)之間的垂直邊距(vertical margins)將會坍塌。在一個BFC中,每個盒子的左外邊緣會接觸包容塊的左邊緣(對于從右往左的格式,則相反)。即便是在浮動
floats
情況下也是如此(盡管盒子的線框可能由于浮動而收縮),除非盒子建立了一個新的BFC(這種情況下,盒子自身可能會因為浮動變得更窄)。
格式化上下文(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.
簡單的人肉+谷歌翻譯:
正常流中屬于格式化上下文的盒子,可以是塊或者內(nèi)聯(lián),但不能同時存在。塊級盒參與塊級格式化上下文,行內(nèi)級參與行級格式上下文。
包含塊(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.
簡單的人肉+谷歌翻譯:
在 CSS2.1中,許多盒子的定位(positions)和尺寸(size)被用來計算相對于矩形盒子的邊緣,這種矩形盒子我們稱其為包容塊(containing block)。通常,生成的盒子將作為后代盒子的包含塊,我們稱其一個盒子為其后代建立(establishes)包容塊。“一個盒子的包容塊(a box's containning block)“指”這個盒子所在的包容塊“,而不是指這個盒子產(chǎn)生的塊。
塊級盒子(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.
簡單的人肉+谷歌翻譯:
塊級元素是源文檔中作為塊被視覺格式化的元素(比如:paragraphs)。
display
屬性作為元素塊級的表示,其值有block
、list-item
,table
。塊級元素是參與BFC的盒子。每一個塊級元素會生成一個主要塊級元素盒(principal block-level box),盒中包含后代盒子和生成的內(nèi)容,同時這個盒也包含任意定位方案。除了主塊級元素盒外,一些塊級元素也可能產(chǎn)生額外的盒子,比如:
list-item
元素。這些額外的盒子會被放置在相對主盒的地方。除了后面章節(jié)描述的表格盒(table boxes)和替換元素外,塊級元素盒(block-level box)同時也是一個塊容器盒(block container box)。塊容器盒要么只包塊級盒,或建立內(nèi)聯(lián)格式化上下文(inline formatting)的情況下只包含內(nèi)聯(lián)級盒子(inline-level boxes)。并非所有塊容器盒都是塊級盒,不包含內(nèi)聯(lián)盒子和表單cell(table cell)的是塊容器(block container),而不是塊級盒(block-level boxes)。既是塊級盒(block-level boxes)同時也是塊容器(block container)的稱為塊盒(block boxes)。
塊級盒(block-level block),塊容器盒(block container box),塊盒(block box)這三個術(shù)語有時會縮寫為明確的:塊(block)
參考: