經常問到的 BFC 和 IFC 是什麼?

xuweiblog發表於2021-04-10

什麼是BFC?什麼作用?

Block Formatting Context

塊盒子佈局發生的區域,浮動元素和其他元素互動的區域

浮動定位和清除浮動的時候只會應用於同一個BFC內的元素。浮動不會影響其他BFC中元素的佈局,而清除浮動只能清除同一BFC中在它前面的元素的浮動

外邊距的摺疊也只會發生在同一BFC中的塊級元素之間。可以建立新的BFC來消除外邊距的摺疊問題。

常見的定位佈局方案有,普通流,浮動和絕對定位。

BFC 是一塊渲染區域,有一套渲染定位規則。決定子元素定位其他元素的關係和相互作用,是屬於普通流的。具有 BFC 特性的元素可以看作是隔離了的獨立容器,容器裡面的元素不會在佈局上影響到外面的元素,並且 BFC 具有普通容器所沒有的一些特性。

其實也不是什麼新鮮東西,可能都在用但不知道這個概念。


案例1:使浮動元素和周圍內容等高

對於以下程式碼:

<style>
  .box {
    background-color: rgb(224, 206, 247);
    border: 5px solid rebeccapurple;
    /* overflow: auto; */
    /* display: flow-root; */
  }
  .float {
    float: left;
    width: 400px;
    height: 150px;
    background-color: white;
    border: 1px solid black;
    padding: 10px;
  }
</style>
<div>
  <div class="box">
    <div class="float">I am a floated box!</div>
    <p>I am content inside the container.</p>
  </div>
</div>

顯示的效果如下:

經常問到的 BFC 和 IFC 是什麼?

因為浮動盒子脫離了文件流。浮動的div元素更大,就穿出了邊框。

一般是需要將盒子和浮動元素做成等高的,即浮動元素應該包含在box內部,要達到這個效果,可以這樣:

  1. 使用display: flow-root

    一個新的display屬性值,可以建立無副作用的BFC。在父級元素中使用display: flow-root就可以建立新的BFC。

    可以理解為和建立根元素一樣,建立一個文件流的上下文

  2. 使用overflow:auto

    只要設定overflow為一個非visible的值就可以。使用overflow建立一個新的BFC,overflow會告訴瀏覽器如何處理超出部分的內容。

    但是如果只是用來建立BFC的話,可能引發其他情況。


案例2: 清除外部浮動

對於以下程式碼:

<style>
  section {
    height: 150px;
  }
  .box {
    background-color: rgb(224, 206, 247);
    border: 5px solid rebeccapurple;
  }
  .box[style] {
    background-color: aliceblue;
    border: 5px solid steelblue;
  }
  .float {
    float: left;
    overflow: hidden; /* required by resize:both */
    resize: both;
    margin-right: 25px;
    width: 200px;
    height: 100px;
    background-color: rgba(255, 255, 255, 0.75);
    border: 1px solid black;
    padding: 10px;
  }
</style>


<section>
  <div class="float">Try to resize this outer float</div>
  <div class="box"><p>Normal</p></div>
</section>
<section>
  <div class="float">Try to resize this outer float</div>
  <div class="box" style="display:flow-root"><p>	   	  	
    <code>display:flow-root</code><p>
  </div>
</section>

這裡需要關注的是float元素上的margin-right這個屬性。

經常問到的 BFC 和 IFC 是什麼?

上面的兩個元素之間,margin-right 沒有生效。但是對box新增display:flow-root屬性之後,margin-right 屬性就生效了,左邊的元素縮放的時候始終都保持有25px的距離。也就是display:flow-root對同級的外部元素的浮動也清除了

如果對HTML部分寫成這樣:

<section>
  <div class="float">Try to resize this outer float</div>
  <div class="float">Try to resize this outer float</div>
  <div class="box"><p>Normal</p></div>
</section>
<section>
  <div class="float">Try to resize this outer float</div>
  <div class="float">Try to resize this outer float</div>
  <div class="box" style="display: flow-root">
    <p><code>display:flow-root</code></p>
    <p>xx</p>
  </div>
</section>

消除同級元素的float, 顯示出 margin-right 的效果就更明顯了。

經常問到的 BFC 和 IFC 是什麼?

需要注意的是:清除同一BFC中的浮動,只能清除在它前面元素的浮動。


案例3: 外邊距塌陷問題

對於如下程式碼:

<style>
  .blue,
  .red-inner {
    height: 50px;
    margin: 50px 0;
    background: blue;
  }

  .red-outer {
    /* display: flow-root; */
    /* overflow: hidden; */
    background: red;
  }
</style>

<body>
  <div class="blue"></div>
  <div class="red-outer">
    <div class="red-inner">red inner</div>
  </div>
</body>

顯示的效果如下:

經常問到的 BFC 和 IFC 是什麼?

可以看到,對red-inner的margin沒法撐起盒子,兩個藍色盒子之間的距離是50px.

使用display: flow-root;

經常問到的 BFC 和 IFC 是什麼?

兩個藍色盒子就距離100px了,而且margin也完全顯示了出來。


建立BFC的方法

使用這些BFC的特性,需要建立出BFC:

  • 根元素(<html>)
  • 浮動元素(元素的 float 不是 none
  • 絕對定位元素(元素的 positionabsolutefixed
  • 行內塊元素(元素的 displayinline-block
  • 表格單元格(元素的 displaytable-cell,HTML表格單元格預設為該值)
  • 表格標題(元素的 displaytable-caption,HTML表格標題預設為該值)
  • 匿名錶格單元格元素(元素的 displaytable、``table-rowtable-row-group、``table-header-group、``table-footer-group(分別是HTML table、row、tbody、thead、tfoot 的預設屬性)或 inline-table
  • overflow 計算值(Computed)不為 visible 的塊元素
  • display 值為 flow-root 的元素
  • contain 值為 layoutcontent 或 paint 的元素
  • 彈性元素(displayflexinline-flex 元素的直接子元素)
  • 網格元素(displaygridinline-grid 元素的直接子元素)
  • 多列容器(元素的 column-countcolumn-width (en-US) 不為 auto,包括 ``column-count1
  • column-spanall 的元素始終會建立一個新的BFC,即使該元素沒有包裹在一個多列容器中(標準變更Chrome bug

什麼又是 IFC?

相對於塊級格式化上下文,還有行內格式化上下文,Inline formatting context

對於IFC,行內框一個接一個地排列,排列順序和書寫方向一致。

  • 水平書寫模式,行內框從左邊開始水平排列
  • 垂直書寫模式,行內框從頂部開始水平排列

一個行內框在被分割到多行中的時候,margin,border以及padding的設定不會在斷裂處生效(邊框跨行連續,不會產生兩塊border)

Margin,border和padding的設定在行方向上生效。

垂直方向上對齊

垂直方向上的位置主要是用vertical-align

<style>
  .horizontal {
    writing-mode: horizontal-tb;
   }

  .vertical {
    writing-mode: vertical-rl;
   }
	span {
    font-size: 200%;
    /* vertical-align: top; */
    vertical-align: bottom;
   }
</style>    

<div class="example horizontal">
      Before that night—<span>a memorable night</span>, as it was to prove—hundreds of millions of
      people had watched the rising smoke-wreaths of their fires without drawing any special
      inspiration from the fact.”
</div>

顯示效果:

經常問到的 BFC 和 IFC 是什麼?

而如果將vertical-align: bottom設定為top,效果則是頂部對齊

經常問到的 BFC 和 IFC 是什麼?

需要注意的是,如果文字方向是垂直書寫模式的話,對齊方式不變,但實際上應該是左右對齊,與vertical-align的字面意思稍有出入。在vertical-align:top再加上writing-mode: vertical-rl

經常問到的 BFC 和 IFC 是什麼?

水平方向上對齊

行內元素在水平方向上的位置主要是用text-align

<style>
   .horizontal {
    writing-mode: horizontal-tb;
   }

  .vertical {
    writing-mode: vertical-rl;
   }
	.example {
    text-align: center;
  }
</style>

<div class="example horizontal" style="border: 1px solid">One Two Three</div>
<div class="example vertical">One Two Three</div>

顯示效果:

經常問到的 BFC 和 IFC 是什麼?

參考:

相關文章