1. 程式人生 > 其它 >前端知識,什麼是BFC?

前端知識,什麼是BFC?

技術標籤:web 前端csshtml

什麼是BFC?

BFC全稱是Block Formatting Context,即塊格式化上下文。它是CSS2.1規範定義的,關於CSS渲染定位的一個概念。要明白BFC到底是什麼,首先來看看什麼是視覺格式化模型。

視覺格式化模型

視覺格式化模型(visual formatting model)是用來處理文件並將它顯示在視覺媒體上的機制,它也是CSS中的一個概念。

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

塊盒(block box)

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

行內盒(inline box)

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

匿名盒(anonymous box)

匿名盒也有分匿名塊盒與匿名行內盒,因為匿名盒沒有名字,不能利用選擇器來選擇它們,所以它們的所有屬性都為inherit

或初始預設值;

如下面例子,會創鍵匿名塊盒來包含毗鄰的行內級盒:

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

三個定位方案

在定位的時候,瀏覽器就會根據元素的盒型別和上下文對這些元素進行定位。

盒就是定位的基本單位。定位時,有三種定位方案,分別是常規流,浮動已經絕對定位。

常規流(Normal flow)

  • 在常規流中,盒一個接著一個排列;
  • 塊級格式化上下文裡面, 它們豎著排列;
  • 行內格式化上下文裡面, 它們橫著排列;
  • positionstaticrelative,並且floatnone時會觸發常規流;
  • 對於靜態定位(static positioning),position: static盒的位置是常規流佈局裡的位置
  • 對於相對定位(relative positioning),position: relative,盒偏移位置由這些屬性定義topbottomleftandright即使有偏移,仍然保留原有的位置,其它常規流不能佔用這個位置。

浮動(Floats)

  • 盒稱為浮動盒(floating boxes);
  • 它位於當前行的開頭或末尾;
  • 導致常規流環繞在它的周邊,除非設定 clear 屬性;

絕對定位(Absolute positioning)

  • 絕對定位方案,盒從常規流中被移除,不影響常規流的佈局;
  • 它的定位相對於它的包含塊,相關CSS屬性:topbottomleftright
  • 如果元素的屬性positionabsolutefixed,它是絕對定位元素;
  • 對於position: absolute,元素定位將相對於最近的一個relativefixedabsolute的父元素,如果沒有則相對於body

塊格式化上下文

到這裡,已經對CSS的定位有一定的瞭解了,從上面的資訊中也可以得知,塊格式上下文是頁面CSS 視覺渲染的一部分,用於決定塊盒子的佈局及浮動相互影響範圍的一個區域

BFC的建立方法

  • 根元素或其它包含它的元素;
  • 浮動(元素的float不為none);
  • 絕對定位元素(元素的positionabsolutefixed);
  • 行內塊inline-blocks(元素的display: inline-block);
  • 表格單元格(元素的display: table-cell,HTML表格單元格預設屬性);
  • overflow的值不為visible的元素;
  • 彈性盒 flex boxes(元素的display: flexinline-flex);

但其中,最常見的就是overflow:hiddenfloat:left/rightposition:absolute。也就是說,每次看到這些屬性的時候,就代表了該元素以及建立了一個BFC了。

BFC的範圍

先看一段程式碼

複製程式碼

<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建立了一個塊格式上下文,這個上下文包括了#div_2#div_3#div_4#div_5。即#div_2中的子元素也屬於#div_1所建立的BFC。但由於#div_5建立了新的BFC,所以#div_6#div_7就被排除在外層的BFC之外。

這從另一方角度說明,一個元素不能同時存在於兩個BFC中

BFC的效果

就如剛才提到的,BFC的最顯著的效果就是建立一個隔離的空間,斷絕空間內外元素間相互的作用。然而,BFC還有更多的特性。

簡單歸納一下:

  1. 內部的盒會在垂直方向一個接一個排列(可以看作BFC中有一個的常規流);
  2. 處於同一個BFC中的元素相互影響,可能會發生margin collapse;
  3. 每個元素的margin box的左邊,與容器塊border box的左邊相接觸(對於從左往右的格式化,否則相反)。即使存在浮動也是如此;
  4. BFC就是頁面上的一個隔離的獨立容器,容器裡面的子元素不會影響到外面的元素,反之亦然;
  5. 計算BFC的高度時,考慮BFC所包含的所有元素,連浮動元素也參與計算;
  6. 浮動盒區域不疊加到BFC上;

這麼多性質有點難以理解,但可以作如下推理來幫助理解:html的根元素就是<html>,而根元素會建立一個BFC,建立一個新的BFC時就相當於在這個元素內部建立一個新的<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')向左浮動,它建立了一個新BFC,但暫時不討論它所建立的BFC。由於綠色框浮動了,它脫離了原本normal flow的位置,因此,粉色框('#right')就被定位到灰色父元素的左上角(特性3:元素左邊與容器左邊相接觸),與浮動綠色框發生了重疊。

同時,由於灰色框('#box')並沒有建立BFC,因此在計算高度的時候,並沒有考慮綠色框的區域(特性6:浮動區域不疊加到BFC區域上),發生了高度坍塌,這也是常見問題之一。

例項二

現在通過設定overflow:hidden來建立BFC,再看看效果如何。

複製程式碼

.BFC{
    overflow: hidden;
}

<div class='box BFC'>
    <div class='left'> </div>
    <div class='right'> </div>
</div>

複製程式碼

灰色框建立了一個新的BFC後,高度發生了變化,計算高度時它將綠色框區域也考慮進去了(特性5:計算BFC的高度時,浮動元素也參與計算);

綠色框和紅色框的顯示效果仍然沒有任何變化。

例項三

複製程式碼

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

複製程式碼

由於粉色框沒有建立新的BFC,因此粉色框中白色塊受到了綠色框的影響,被擠到了右邊去了。先不管這個,看看白色塊的margin。

例項四

利用同例項二中一樣的方法,為粉色框建立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>

複製程式碼

一旦粉色框建立了新的BFC以後,粉色框就不與綠色浮動框發生重疊了,同時內部的白色塊處於隔離的空間(特性4:BFC就是頁面上的一個隔離的獨立容器),白色塊也不會受到綠色浮動框的擠壓。

總結

以上就是BFC的分析,BFC的概念比較抽象,但通過例項分析應該能夠更好地理解BFC。

在實際中,利用BFC可以閉合浮動(例項二),防止與浮動元素重疊(例項四)。

同時,由於BFC的隔離作用,可以利用BFC包含一個元素,防止這個元素與BFC外的元素髮生margin collapse。