深入理解BFC和IFC


1. 為什么會有BFC和IFC

  首先要先了解兩個概念:Box和formatting context;
  Box:CSS渲染的時候是以Box作為渲染的基本單位。Box的類型由元素的類型和display屬性決定,box的類型分為block-level box 和inline-level box(不包括css3的時候)。不同類型的box參與不同類型的formatting context布局。

  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. 

  block-level box:形式上表現為塊(此處和塊元素的區別主要是不包含塊元素里的non-replaced inline blocks(這里一般指canvas,svg,input元素等) and non-replaced table cells)或者display 屬性為 block, list-item, table 的元素,會生成 block-level box。並且參與 block fomatting context; 
  inline-level box:display 屬性為 inline, inline-block, inline-table 的元素,會生成 inline-level box。並且參與 inline formatting context;
  run-in box: css3 中才有,即GFC,FFC  
  Formatting context:每個渲染區域用formatting context表示。它決定了其子元素將如何定位,以及和其他元素的關系和相互作用
       BFC和IFC則可以理解為不同渲染區域遵循的不同規則。

2. 什么是BFC和IFC

  • BFC

  1. 什么時候會產生BFC:

  1. float is not none
  2. position is absolute & fixed
  3. display is table-cell,table-caption,inline-block,flex,inline-flex
  4. overflow is not visible
  5. block-level box

  2. 特性:

o   內部的Box會在垂直方向,一個接一個地放置。
o   Box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰Box的margin會發生重疊每個元素的margin box的左邊,與包含塊border box的左邊相接觸(對於從左往右的格式化,否則相反)。即使存在浮動也是如此。
o   BFC的區域不會與float box重疊
o   BFC就是頁面上的一個隔離的獨立容器,容器里面的子元素不會影響到外面的元素。反之也如此。
o   計算BFC的高度時,浮動元素也參與計算。   

  3. 作用:

     通常會用BFC來解釋以下2個問題:
    1. margin collapse:上下margin會合並(這里不過多闡述,可參考鏈接[3])
    2. contain float: 
    其中的一種解決方法:overflow:hidden ,創建新的BFC,可以包含float元素,父元素就有高度值了

    此處闡述一下自己的理解:如果父元素只包含浮動元素,因為浮動元素是不包含在正常流的,浮動孩子將會脫離頁面的常規流,因此父元素相當於不包含任何元素,高度為0。

    而BFC里面有兩條規則:
    1、BFC就是頁面上的一個隔離的獨立容器,容器里面的子元素不會影響到外面的元素。反之也如此。
    2、計算BFC的高度時,浮動元素也參與計算
    overflow:hidden會產生新的BFC,子元素的被包含在父元素的BFC中,因此父元素不受子元素影響,恢復常規布局,遵循BFC規則,同時計算高度時,父元素的高度會將浮動元素算進來,因此父元素有了高度。

    不過這里要闡述一件事就是高度塌陷只出現在父元素包含且只包含浮動元素的時候:

    看圖:在父元素沒有明確定義height的時候,如果只包含浮動元素,父元素會出現高度塌陷的問題。(其中的解決方法主要有添加偽元素clear:both,設置父元素height,設置父元素overflow:hidden等方式)

下圖:當父元素內部有非float元素時(clear:both的原理)
  
  • IFC
  IFC也是一種布局規則,inline元素和inline-block符合IFC的布局規則。 在IFC布局中重點關注一下line box。
  (補充一下:IFC的生成條件是元素滿足inline-level box)

       在IFC中,內聯元素在水平方向上一個接一個的排布,其中,容器之間水平方向上的margin,padding,border方向上是好使的。他們垂直方向上有很多種對其方式,比如居底部或頂端對齊,或者基線對齊。他們對齊完了之后形成的這個四方塊兒區域,叫做一個line box(行框)。

  一個line box的寬度由包含它的元素的寬度和包含它的元素里面有沒有float元素來決定,而高度由內部元素中實際高度最高的元素而計算出來。

  line box的高度是足夠高來包含他內部的容器們的,也可能比它包含的容器們都高(比如在基線對齊的時候),當他包含的內部容器的高度小於line box的高度的時候,內部容器的垂直位置由自己的vertical這個屬性來確定。當內部的容器盒子太多了一個line box裝不下來,他們折行之后會變成兩個或者多個line box, line box們相互之間垂直方向不能分離,不能重疊。

  一般來說,line box的左邊緣挨着包含它的元素的左邊緣,並且右邊緣挨着包含它的元素的右邊緣,浮動元素會在包含他們的元素的邊緣和line box的邊緣之間,所以雖然在同一個IFC下的line box們通常擁有相同的寬度(就是包含他們的容器的寬度),但是也會因為浮動元素的搗亂,導致line box們的可用寬度產生了變化不一樣了。在同一個Ifc下的line box們的高度也會不一樣(比如說,一個line box里有個比較大的image,他就高了)。

  如果一個line box 里的內聯元素們的寬度總和小於這個line box的寬度,那么他們在這個line box里的水平方向的排布方式由 text-align這個屬性來決定,如果這個屬性被設置成了“justify”,可以使這些盒子在剩余空間內拉伸(除了inline-table 和 inline-block的元素)

  在一個line box中,當他包含的內部容器的高度小於line box的高度的時候,內部容器的垂直位置由自己的vertical這個屬性來確定。那么,我們設想一下,如果手動創建一個IFC的環境,讓line box的高度是包含塊的高度的100%,讓line box內部的元素使用vertical-align:middle,就可以實現垂直居中。

  一個line box的高度由內部元素中實際高度最高的元素而計算出來。所以,我們在line box中插入一個高度100%的inline-block元素。則會把整個line box撐高直到包含塊的100%.
   當內聯元素的寬度超過了line box的寬度,那么它會折行分裂成了幾個line box,如果這個元素里面的內容不可以折行,例如只有一個字,或者white-space設置了nowrap/pre。那么內聯元素會溢出line box。
  當一個內聯元素分裂時,分裂處的 margins, borders 和 padding不會有任何視覺效果(或者其他任何分裂,只要是有多個line box)。
  line box 的生存條件是在IFC中並且包含inline-level元素,如果line box里沒有文本,空白,換行符,內聯元素,也沒有其他的存在IFC環境中的元素,(如inline-block,inline- table,images等),將會被視為零高度,也將會被視為沒有意義。
  補充:在IFC的環境中,是不能存在block-level元素的,如果將block-level元素插入到IFC中,那么此IFC將會被破壞掉, 而block-level元素前的元素和block-level元素后的元素將會各自自動產生一個匿名容器其包圍,這個匿名的容器內部環境將是一個新的 IFC。


  此處補充一些自己對於IFC高度計算的理解:主要是line-height和height

  IFC中height的計算方式:line height表示高度

  *line-height如果沒有顯式聲明,那么繼承父元素的line-height;如果顯示聲明了,則用聲明后的高度(vertical-align的時候參考的邊界值)

  css中的line-height表示line space(行間差值) + font-size

看下圖:

 

可以得到:1.height對inline元素並不起作用 2.只有設置了line-height的inline元素才會參與vertical-align的排列規則(這里個人分析是因為只有設置了高度,vertical-align時才能計算到邊界值,從而對其進行排列,否則默認都是baseline規則)

此處可以再看一個例子:

 

 這個地方設置第二個元素的line-height是80,而父元素的line-height是100,vertical-align默認是相對於父元素的排列。首先中線的位置是一半,所以(100/2)-(80/2)=10,第二個元素下移了10px。
更多關於vertical-align的知識可以參考[6],[7]。
 
參考文獻:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM