理解BFC、IFC

常見定位方案

普通流 (normal flow)

在普通流中,元素按照其在 HTML 中的前後位置至上而下佈局,在這個過程當中,行內元素水平排列,直到當行被佔滿而後換行,塊級元素則會被渲染爲完整的一個新行,除非另外指定,不然全部元素默認都是普通流定位,也能夠說,普通流中元素的位置由該元素在 HTML 文檔中的位置決定。css

浮動 (float)

在浮動佈局中,元素首先按照普通流的位置出現,而後根據浮動的方向儘量的向左邊或右邊偏移,其效果與印刷排版中的文本環繞類似html

絕對定位 (absolute positioning)

在絕對定位佈局中(position值爲absolute或fixed),元素會總體脫離普通流,所以絕對定位元素不會對其兄弟元素形成影響,而元素具體的位置由絕對定位的座標決定。git

Formatting context(格式化上下文)

Formatting context(格式化上下文) 是 W3C CSS2.1 規範中的一個概念。它是頁面中的一塊渲染區域,而且有一套渲染規則,它決定了其子元素將如何定位,以及和其餘元素的關係和相互做用github

格式化上下文有如下幾種類型:segmentfault

  • BFC: 塊級格式化上下文
  • IFC: 行內格式化上下文
  • 其餘格式化上下文(GFC/FFC)

Box

一個頁面是由不少個Box組成的,元素的類型和display屬性決定了這個Box的類型。不一樣類型的 Box,會參與不一樣的 Formatting Context。
Block level的box會參與造成BFC,好比display值爲block,list-item,table的元素。
Inline level的box會參與造成IFC,好比display值爲inline,inline-table,inline-block的元素。ide

BFC

塊格式化上下文(Block Formatting Context,BFC) 是Web頁面的可視化CSS渲染的一部分,是塊盒子的佈局過程發生的區域,也是浮動元素與其餘元素交互的區域。(我的理解:BFC佈局方式和上述普通流佈局方式類似)佈局

具備 BFC 特性的元素能夠看做是隔離了的獨立容器,容器裏面的元素不會在佈局上影響到外面的元素,而且 BFC 具備普通容器所沒有的一些特性。flex

下列方式會建立塊級格式化上下文:ui

  • 根元素(<html>)
  • 浮動元素(元素的float不是 none
  • 絕對定位元素(元素的 position爲 absolute 或 fixed
  • 行內塊元素(元素的 display 爲 inline-block
  • 表格單元格(元素的 display爲 table-cell,HTML表格單元格默認爲該值)
  • 表格標題(元素的 display 爲 table-caption,HTML表格標題默認爲該值)
  • 匿名錶格單元格元素(元素的 display爲 table、`table-row、 table-row-group、table-header-group、table-footer-group(分別是HTML table、row、tbody、thead、tfoot的默認屬性)或 inline-table`)
  • overflow值不爲 visible的塊元素
  • display值爲 flow-root 的元素
  • contain值爲 layoutcontent或paint 的元素
  • 彈性元素(display爲 flex 或 inline-flex元素的直接子元素)
  • 網格元素(display爲 grid 或 inline-grid 元素的直接子元素)
  • 多列容器(元素的 column-count或 column-width不爲 auto,包括 `column-count 爲 1`)
  • column-span 爲 all 的元素始終會建立一個新的BFC,即便該元素沒有包裹在一個多列容器中(標準變動Chrome bug)。

塊格式化上下文包含建立它的元素內部的全部內容.spa

BFC佈局規則

  • 內部的Box會在垂直方向,一個接一個地放置。
  • Box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰Box的margin會發生重疊
  • 每一個元素的左外邊緣(margin-left), 與包含塊的左邊(contain box left)相接觸(對於從左往右的格式化,不然相反)。即便存在浮動也是如此。除非這個元素本身造成了一個新的BFC。
  • BFC的區域不會與float box重疊。
  • BFC就是頁面上的一個隔離的獨立容器,容器裏面的子元素不會影響到外面的元素。反之也如此。
  • 計算BFC的高度時,浮動元素也參與計算

BFC的特性和應用

BFC 能夠包含浮動的元素(清除浮動帶來的影響)

浮動的元素會脫離普通文檔流

<div style="border: 1px solid #000;">
    <div style="width: 100px;height: 100px;background: #eee;float: left;"></div>
</div>

1.jpg

因爲容器內元素浮動,脫離了文檔流,因此容器只剩下 2px 的邊距高度。若是使觸發容器的 BFC,那麼容器將會包裹着浮動元素。

效果如圖:
2.png

BFC 能夠阻止元素被浮動元素覆蓋

先來看一個文字環繞效果:

<div style="height: 100px;width: 100px;float: left;background: lightblue">我是一個左浮動的元素</div>
<div style="width: 200px; height: 200px;background: #eee">我是一個沒有設置浮動, 
也沒有觸發 BFC 元素, width: 200px; height:200px; background: #eee;</div>

3.png

這時候其實第二個元素有部分被浮動元素所覆蓋,(可是文本信息不會被浮動元素所覆蓋) 若是想避免元素被覆蓋,可觸第二個元素的 BFC 特性,在第二個元素中加入overflow: hidden,就會變成:
4.png

這個方法能夠用來實現兩列自適應佈局,效果不錯,這時候左邊的寬度固定,右邊的內容自適應寬度(去掉上面右邊內容的寬度)。

解決外邊距合併

相鄰兄弟元素margin摺疊問題

<head>
div{
    width: 100px;
    height: 100px;
    background: lightblue;
    margin: 100px;
}
</head>
<body>
    <div></div>
    <div></div>
</body>

5.png
從效果上看,由於兩個 div 元素都處於同一個 BFC 容器下 (這裏指 body 元素) 因此第一個 div 的下邊距和第二個 div 的上邊距發生了重疊,因此兩個盒子之間距離只有 100px,而不是 200px。

首先這不是 CSS 的 bug,咱們能夠理解爲一種規範,若是想要避免外邊距的重疊,能夠將其放在不一樣的 BFC 容器中。

<div class="container">
    <p></p>
</div>
<div class="container">
    <p></p>
</div>
.container {
    overflow: hidden;
}
p {
    width: 100px;
    height: 100px;
    background: lightblue;
    margin: 100px;
}

這時候,兩個盒子邊距就變成了 200px
6.png

父子元素margin重疊問題

<style>
.box{
width:100px;
height:100px;
background:#ccc;
}
.wrap {
  background:yellow;
}
.wrap h1{
  background:pink;
  margin:40px;
}
</style>
<body>
<div class="box">box</div>
<div class="wrap">
  <h1>h1</h1>
</div>
</body>

7.png

上圖wrap元素與h1元素之間l理論上本該有個40px的上下margin值,然而實際上父子元素並無存在margin值,與此同時,兩個div元素的間距爲40px。遇到這種情形,咱們如何處理?
處理方法其實有不少,在wrap元素中添加:overflow:hidden;或者overflow:auto;使其父元素造成一個BFC;也能夠在wrap元素中添加border:1px solid;或是padding:1px;這些均可以有效解決父子元素margin重疊問題。

8.png

IFC

IFC(Inline Formatting Contexts)直譯爲"內聯格式化上下文",IFC的line box(線框)高度由其包含行內元素中最高的實際高度計算而來(不受到豎直方向的padding/margin影響)。

IFC中框模型不徹底適用於參與內聯格式上下文的項。在水平書寫模式行中,水平填充、邊框和邊距將應用於元素,並左右推送文本。可是,不會應用元素上下的邊距。將應用垂直填充和邊框,但可能會在內容的上方和下方重疊,由於在內聯格式上下文中,填充和邊框不會將行框推開

IFC佈局規則

在行內格式化上下文中,框(boxes)一個接一個地水平排列,起點是包含塊的頂部。水平方向上的marginborderpadding在框之間獲得保留。框在垂直方向上能夠以不一樣的方式對齊:它們的頂部或底部對齊,或根據其中文字的基線對齊。包含那些框的長方形區域,會造成一行,叫作行框。

IFC 的應用

水平居中

當一個塊要在環境中水平居中時,設置其爲inline-block則會在外層產生IFC,經過text-align則可使其水平居中。

垂直居中

建立一個IFC,用其中一個元素撐開父元素的高度,而後設置其vertical-align:middle,其餘行內元素則能夠在此父元素下垂直居中。

其餘格式化上下文

GFC

GFC(GridLayout Formatting Contexts)直譯爲"網格佈局格式化上下文",當爲一個元素設置display值爲grid的時候,此元素將會得到一個獨立的渲染區域,咱們能夠經過在網格容器(grid container)上定義網格定義行(grid definition rows)和網格定義列(grid definition columns)屬性各在網格項目(grid item)上定義網格行(grid row)和網格列(grid columns)爲每個網格項目(grid item)定義位置和空間。 

GFC將改變傳統的佈局模式,他將讓佈局從一維佈局變成了二維佈局。簡單的說,有了GFC以後,佈局再也不侷限於單個維度了。這個時候你要實現相似九宮格,拼圖之類的佈局效果顯得格外的容易。

FFC

FFC(Flex Formatting Contexts)直譯爲"自適應格式化上下文",display值爲flex或者inline-flex的元素將會生成自適應容器(flex container)。

Flex Box 由伸縮容器和伸縮項目組成。經過設置元素的 display 屬性爲 flex 或 inline-flex 能夠獲得一個伸縮容器。設置爲 flex 的容器被渲染爲一個塊級元素,而設置爲 inline-flex 的容器則渲染爲一個行內元素。

伸縮容器中的每個子元素都是一個伸縮項目。伸縮項目能夠是任意數量的。伸縮容器外和伸縮項目內的一切元素都不受影響。簡單地說,Flexbox 定義了伸縮容器內伸縮項目該如何佈局。

總體來講,FFC與BFC有點兒相似,但仍有如下幾點區別:

  • Flexbox 不支持 ::first-line 和 ::first-letter 這兩種僞元素
  • vertical-align 對 Flexbox 中的子元素 是沒有效果的
  • float 和 clear 屬性對 Flexbox 中的子元素是沒有效果的,也不會使子元素脫離文檔流(可是對Flexbox 是有效果的!)
  • 多欄佈局(column-*) 在 Flexbox 中也是失效的,就是說咱們不能使用多欄佈局在Flexbox 排列其下的子元素
  • Flexbox 下的子元素不會繼承父級容器的寬

參考

https://developer.mozilla.org...
https://developer.mozilla.org...
https://segmentfault.com/a/11...
https://zhuanlan.zhihu.com/p/...

相關文章
相關標籤/搜索