1. 程式人生 > >[轉]學習塊格式化上下文(BlockFormattingContext)

[轉]學習塊格式化上下文(BlockFormattingContext)

arrow .cn 推理 creat pri left 之間 script over

原文:https://www.cnblogs.com/elcarim5efil/p/4745796.html

格式化上下文

格式化上下文( formatting contexts )
├── 塊級格式化上下文( Block formatting contexts )( BFC )
├── 行內格式化上下文( Inline formatting contexts ) ( IFC )
├── 自適應格式化上下文( Flex Formatting Contexts )( FFC )
└── 網格布局格式化上下文( GridLayout Formatting Contexts )( GFC )

------------------------------------------------------------------

什麽是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的範圍

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包含創建該上下文元素的所有子元素,但不包括創建了新BFC的子元素的內部元素。

這段看上去有點奇怪,我是這麽理解的,加入有下面代碼,class名為.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清除浮動所利用的特性,關於清除浮動將在後面講述。

如果一個元素能夠同時處於兩個BFC中,那麽就意味著這個元素能與兩個BFC中的元素發生作用,就違反了BFC的隔離作用,所以這個假設就不成立了。

BFC的效果

就如剛才提到的,BFC的最顯著的效果就是建立一個隔離的空間,斷絕空間內外元素間相互的作用。然而,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).

簡單歸納一下:

  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。

參考

視覺格式化模型 | MDN

塊格式化上下文| MDN

CSS之BFC詳解

W3C block-formatting

分類: HTML/CSS

[轉]學習塊格式化上下文(BlockFormattingContext)