BFC到底是個什麼東東?

FC

FC是Formatting Context的簡寫,直譯過來是格式化上下文。其實並非什麼複雜的東西,我的對於它的理解是:FC就是html頁面中的某個元素內的一套渲染規則,決定了其子元素如何佈局,以及和其餘元素在html頁面中的位置css

好比說BFC, BFC是block formatting context,也就是塊級格式化上下文,是用於佈局塊級盒子的一塊渲染區域,舉個例子來講就是一個position爲absolute(觸發BFC的條件之一)的div就是一個BFC。html

常見的FC還有前端

  • IFC(inline formatting context,即內聯級元素內的渲染規則
  • GFC(grid formatting context,display爲grid的元素內的渲染規則)
  • FFC(flex formatting context,display爲flex的元素內的渲染規則)。

什麼是觸發XFC(x表明B,I,G,F其中之一)?

即經過設置某個元素的某些屬性值來使得該元素應用某種渲染規則。例如將一個div的display屬性設置爲grid,那麼就稱觸發了GFC,該元素內就造成了一個GFC,該元素內的渲染規則就要使用GFC規則segmentfault

BFC

如何觸發BFC?

即如何讓某元素內造成BFC環境瀏覽器

某個元素知足下列條件之一就可造成一個BFCapp

  1. 該元素是根元素,即<html></html>標籤內就是一個BFC環境
  2. float的值不爲none
  3. overflow的值不爲visible
  4. display的值爲inline-block、table-cell、table-caption
  5. position的值爲absolute或fixed

BFC的渲染機制(BFC特性)

1.在塊格式化上下文中,從包含塊的頂部開始,垂直地一個接一個地排列盒子。

In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block.less

第一條特性我以爲描述得並不嚴謹,應該是塊級盒子會在垂直方向上一個接一個放置佈局

那什麼是塊級盒子呢?下面是w3c文檔對塊級盒子的描述flex

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'.this

塊級元素是那些在源文檔中可視爲塊的元素(如,段落p標籤)。display屬性爲以下屬性的元素是塊級元素:blocklist-item, 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.

其大體意思: 塊級盒子就是那些參與塊級格式化上下文的盒子(廢話-_-)。每一個塊級元素都會產生一個主要的塊級盒子來容納子元素和生成的內容,而且是定位模式中會涉及到的元素(我的理解就是塊級盒子會影響元素的位置)。一些塊級元素也可能產生除主要盒子以外的附屬盒子好比list-item(li)元素

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.

除了後面一章描述的table盒子和替換元素(瀏覽器根據元素的標籤和屬性,來決定元素的具體顯示內容。如img和input標籤)以外,塊級盒子也是塊級容器盒子(注意二者的區別)。一個塊級容器盒子要麼只容納塊級盒子,要麼就會創建內聯格式化上下文,所以也只容納內聯級盒子(個人理解:一個盒子要麼是塊級盒子,要麼就是內聯級盒子)。並非全部的塊級容器盒子都是塊級盒子: 非替換內聯塊和單元格(td, th)不是塊級盒子。既是塊級盒子,同時又是塊級容器才能被稱爲塊盒子。(最後一句我也是醉了,在下水平有限,不能get到原文想要表達的意思)

The three terms "block-level box," "block container box," and "block box" are sometimes abbreviated as "block" where unambiguous.

「塊級盒子」、「塊容器盒子」和「塊盒子」這三個術語有時在沒有歧義的時候能夠簡寫爲「塊」,(這句話一開始我理解錯了,感謝@Tipwheal的指正!)

那什麼是沒有歧義的時候呢?我的理解是「塊級盒子」、「塊容器盒子」和「塊盒子」都是指塊級盒子的時候能夠簡寫爲塊,即diplay爲block的元素。(筆者也不太肯定,若是有朋友理解,但願您能在評論中留言)

2.垂直方向上的距離由margin決定,屬於同一個BFC的兩個相鄰Box的margin會發生重疊。

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.

這個垂直方向上的距離由margin決定通俗易懂,不須要贅述。屬於同一個BFC的兩個相鄰Box的margin會發生重疊

這個重疊主要會有兩種狀況: 1.上下相鄰的兩個元素 2.父元素與子元素的margin發生重疊

上下相鄰的兩個元素的margin會重疊

重疊的規則是:二者之間的垂直方向上的距離取決於誰的margin大

驗證一下

.top, .btm {
  width: 200px;
  height: 200px;
}
.top {
  margin-bottom: 20px;
  background: deepskyblue;
}
.btm {
  margin-top: 30px;
  background: darkorange;
}
複製代碼
<div id="app">
    <div class="top"></div>
    <div class="btm"></div>
</div>
複製代碼

這個時候top與btm之間的距離不是50px,而是30px

左邊的圖中間的部分是top的margin-top,右邊的圖的中間部分是btm的margin-top,能夠看到二者的距離就是btm的margin-top的距離

那麼問題來了,怎麼消除上下margin重疊呢?

給須要去除margin重疊的上下元素加float屬性

.top, .btm {
  width: 200px;
  height: 200px;
  float:left;
  clear: both; /* 使元素可以垂直排列 */ 
}
.top {
  margin-bottom: 20px;
  background: deepskyblue;
}
.btm {
  margin-top: 30px;
  background: darkorange;
}
複製代碼

也能夠用border,padding替代margin達到想要的效果。

我認爲上下相鄰的兩個元素的margin重疊是沒有必要消除的,除非想要實現某些效果時才須要消除

父元素與子元素的margin發生重疊

若是父元素的margin-top爲0,padding-top爲0,沒有border,而子元素的margin-top不爲0,那麼父元素距離上方的距離就會是子元素margin-top的值,margin-bottom同理

舉個栗子

* {
  padding: 0;
  margin: 0;
}
#app {
  background: yellowgreen;
}

.top {
  background: deepskyblue;
  height: 200px;
  margin: 20px;
}
.footer {
  height: 200px;
  width: 200px;
  background: yellow;
}
複製代碼
<div id="app">
    <div class="top"></div>
</div>
<div class="footer"></div>
複製代碼

能夠看到父元素app因爲top與上下都產生了外邊距

消除父子margin重疊的方法:

  1. 給父元素加border
  2. 設置父元素的padding或者margin
  3. 給父元素添加overflow:hidden

3.bfc的區域不會與float的元素區域重疊。

<div class="left"></div>
<div class="main"></div>
複製代碼
.main {
  background: deepskyblue;
  width: 400px;
  height: 400px;
}
.left {
  float: left;
  width: 200px;
  height: 200px;
  background: darkorange;
}
複製代碼

瀏覽器渲染的結果以下所示

main與left產生了重疊

而當設置overflow:hidden

.main {
  background: deepskyblue;
  width: 400px;
  height: 400px;
  overflow: hidden;
}
複製代碼

就消除了float的影響

利用float能夠造成文字環繞效果,可是也能夠利用這條特性消除文字環繞效果

4.在塊格式化上下文中,每一個box的左外邊緣都與包含塊的左邊緣相接觸(對於從右到左的格式化,右邊緣相接觸)

在塊格式化上下文中,每一個box的左外邊緣都與包含塊(注意這個名詞)的左邊緣相接觸(對於從右到左的格式化,右邊緣相接觸)。即便在浮動存在的狀況下也是如此(儘管box的box's line boxes 可能會由於浮動而收縮),除非box創建了一個新的塊格式上下文(在這種狀況下,box自己可能會由於浮動而變得更窄)。

原文是這樣的

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).

這段話在網上解釋的中文版本很是多,因而就產生了歧義

真正要理解這句話首先要搞懂一個概念,什麼是包含塊?

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.

在CSS 2.1中,許多盒子的位置和大小是根據一個矩形框(稱爲包含塊)的邊緣來計算的。一般,生成的盒子充當包含子盒子的塊;咱們說一個盒子爲它的後代「創建」了包含它的塊。短語「a box's contains block」的意思是「盒子所在的包含塊」,而不是它生成的塊。

Each box is given a position with respect to its containing block, but it is not confined by this containing block; it may overflow.

每一個盒子都被賦予相對於其包含塊的位置,但不受該包含塊的限制;它可能溢出。

那麼是否是全部元素的包含塊就是其父元素的content-box呢?

答案固然是:不是!!

只能說,大多數狀況下,包含塊就是這個元素最近的祖先塊元素的內容區。某個元素的包含塊與其直接父元素有可能一點關係都沒有。舉一個例子:一個position爲absolute的元素,包含塊就是由它的最近的 position 的值不是 static (fixed, absolute, relative, or sticky)的祖先元素的內邊距區的邊緣組成的。若是要深刻研究請參考這篇文章我所瞭解的包含塊

在懂了包含塊的概念以後咱們再來看這條特性,就豁然開朗。

那麼即便在浮動存在的狀況下也是如此,這個該怎麼理解呢?咱們知道當給元素設置float以後,只要寬度足夠,元素就會一個接一個橫向排列,那從第二個元素起,豈不是不會接觸包含塊的邊緣了?是否是文檔錯了呢?

文檔的下文還寫着除非box創建了一個新的塊格式上下文,而給元素添加float屬性就會造成新的BFC,因此文檔的描述是很精確的

5.計算bfc的高度時,浮動元素也參與計算

這條特性就是就是解決子元素浮動致使父元素沒法撐開的關鍵

.main {
  background: deepskyblue;
}
.main div {
  height: 100px;
  width: 100px;
  float: left;
}
複製代碼
<div class="main">
    <div></div>
    <div></div>
</div>
複製代碼

上面的渲染結果爲頁面一片空白...

而讓class爲main的父級div造成BFC後

.main {
  background: deepskyblue;
  position: absolute;  /* 觸發BFC */
}
複製代碼

渲染結果以下:

父元素就被撐開了。而且position設置爲absolute的塊級元素的width是不會佔滿剩餘空間,若是不設置寬度而且沒有子元素,其寬度爲0,若是有子元素,其寬度由子元素撐開

6.bfc就是頁面上的一個獨立容器,容器裏面的子元素不會影響外面元素。

這個特性通俗易懂,不須要解釋

總結

咱們能夠用BFC機制完成的事情:

  1. 清除浮動的影響
  2. 清除margin重疊

ps:本人前端小菜鳥一隻,若是文中有錯,歡迎各位看客可以指正

相關文章
相關標籤/搜索