全面分析總結BFC原理及實踐

前言

常常在面試中被問到「如何清除浮動?」、「爲何 overflow: hidden 能夠清除浮動?」等等比較基礎的問題。雖然這些題目案在各類寫面試題的文章中都有提供答案,但這種教科書式的問答確定不是咱們的目的,與其記住答案不如完全掌握其核心原理——塊級格式化上下文(BFC)html

這篇文章主要就是完全分析清楚BFC原理、總結BFC經典場景中的用法,最後再實踐分析解決佈局中常遇到的問題。git

本文首發自 迪諾筆記,轉載請註明出處😁

1、BFC做用

  • 清除浮動:BFC會包含建立它的元素內部的全部內容(包含浮動元素)
  • 外邊距摺疊:解決同一BFC容器中的相鄰元素間的外邊距摺疊問題
  • 左圖右文佈局:利用浮動元產生BFC以及BFC之間不會互相覆蓋實現左圖右文佈局
以上BFC的做用能夠當作一次檢驗,思考下如何實現,本文後面將會有原理以及實現的講解

2、如何產生BFC

名稱 如何產生 備註
html根元素 html元素自己就是一個BFC元素 記住就好,body元素不是BFC
浮動元素 元素的float屬性不是none 經常使用
絕對定位元素 position屬性爲absolute或fixed 經常使用
行內塊元素 display屬性爲inline-block 經常使用
表格元素 表格元素默認display屬性便是BFC 表格單元格、表格標題也是
彈性元素 display屬性爲flex或inline-flex元素的直接子元素 很是重要(flex佈局經常使用)
網格元素 display屬性爲grid或inline-grid元素的直接子元素 新特性用得少
多列容器 元素的column-count或column-width不爲auto,包括 column-count爲1 新特性用得少
overflow屬性 overflow屬性值不爲visible的元素 經常使用oveflfow:visible
display屬性 display屬性值爲flow-root的元素,flow-root: 一個新的display屬性的值,它能夠建立無反作用的BFC 用得少
contain屬性 contain屬性值爲layout、content、paint的元素 用得少

總結成一句話:凡脫離文檔流均可以產生BFCgithub

3、BFC原理

三種文檔定位方式

在講BFC的原理以前先看看html文檔的三種定位方式面試

普通流

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

浮動

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

絕對定位

在絕對定位中,元素會總體脫離普通流,所以絕對定位元素不會對其兄弟元素形成影響,而元素具體的位置由絕對定位的座標決定。

BFC產生做用的緣由

其實BFC是上面三種佈局方式中的普通流,BFC會產生一個獨立的容器,該容器內部的元素不會在佈局上影響到外部的元素,在外部的普通流看來它和其餘普通流元素無差異,文檔最終會按照上面說的普通流計算佈局。框架

BFC的注意事項

塊格式化上下文對浮動定位與清除浮動都很重要。浮動定位和清除浮動時只會應用於同一個BFC內的元素。
浮動不會影響其它BFC中元素的佈局,而清除浮動只能清除同一BFC中在它前面的元素的浮動。
外邊距摺疊也只會發生在屬於同一BFC的塊級元素之間。

4、BFC常見用法

爲了更好的理解BFC,咱們先看看下面這些常見的用法。less

🌰清除浮動防止高度塌陷

按照上面三種定位方式中說的,浮動元素會脫離普通文檔流,致使外部元素的高度計算不包括浮動元素自己高度,造成高度塌陷。ide

高度塌陷

<div class="container">
  <div class="box box1"></div>
</div>
.box {
  width: 20px;
  height: 50px;
  float: left; // 脫離了文檔流造成了一個BFC
    border: 4px solid green;
}

採用上述產生BFC元素的方法之一使外層元素產生BFC,能夠防止元素高度塌陷。佈局

.container {
    overflow: hidden; // 外層容器產生BFC
}

修復高度塌陷

🌰處理外邊距摺疊的問題

在普通文檔流中,元素(非BFC元素)的外邊距margin會自動摺疊,產生以下現象。flex

外邊距摺疊

<div class="container">
  <div class="box box1 m20"></div>
  <div class="box box2 m20"></div>
</div>
.m20 {
  margin: 20px;
}
.box {
  border: 1px solid green;
}

這個是html的特性不算bug,可是咱們更但願margin不產生摺疊效果,經過利用BFC元素之間的外邊距不會摺疊的特性來實現。ui

<div class="container">
  <div class="box box1 m20"></div>
  <div class="box box2 m20"></div>
</div>
.m20 {
  margin: 20px;
}
.box {
  overflow: hidden; // 使得兩個box成爲BFC元素
  border: 4px solid green;
}

使兩個box造成BFC或者分別用兩個BFC包裹box,而後造成的兩個BFC之間的外邊距不會摺疊,修復後效果以下圖。

修復外邊距摺疊

5、擴展一下

存在塊級格式化上下文BFC,則對應存在內聯格式化上下文IFC、網格格式化上下文GFC、自適應格式化上下文FFC,這些均可以統稱爲格式化上下文。

IFC

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

IFC示意圖

當在內聯元素中插入塊級元素會產生什麼效果呢?在內聯元素中插入位置先後的內聯元素各自造成一個IFC,而後按照普通文檔流進行佈局,效果以下圖。

內聯元素中插入塊級元素

GFC

網格佈局格式化上下文(display: grid

FFC

自適應格式化上下文(display: flex

6、常見問題分析

🍓爲何overflow: hidden能夠清除浮動?

overflow: hidden使得外層元素產生了一個BFC,BFC的高度計算包含其內部的浮動元素,從而達到清除浮動效果
<div style="border: 5px solid #6EBD91; overflow: hidden;">
  <div style="float: left; border: 5px solid #F4D491;">Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus, maxime fuga assumenda excepturi, exercitationem rerum quae voluptates sunt perspiciatis cupiditate sed itaque officia, placeat minus iure quod expedita earum nam.Eum aliquam totam iure mollitia deserunt, minus repellendus. Harum ullam tenetur, impedit aliquam nobis ut dignissimos eligendi, expedita illum iste esse odio ab quos explicabo, odit architecto. Tempora, hic facilis?</div>
</div>

效果以下:

清除浮動

分析過程

外層overflow: hidden的元素產生了一個BFC,自己float: left的元素也產生了一個BFC,外層BFC進行尺寸計算時包含內層BFC尺寸。

結果

🍓經常使用的clearfix清除浮動如何實現?

// 採用after僞元素實現
.clearfix::after {
  content: " ";
  display: block;
  height: 0;
  clear: both;
}
// 兼容IE6
.clearfix {
  zoom: 1;
}

.clearfix類綁定到外層非浮動元素上,clear: both屬性確保外層元素在進行高度計算時包含內部浮動元素。

使用clearfix清除浮動的元素自己並未產生BFC,依靠的是CSS的clear屬性。即該元素若沒有其餘屬性產生BFC時仍然按照普通文檔流進行定位,垂直外邊距仍是存在摺疊。

🍓如何實現兩列自適應佈局?

不考慮使用UI框架中的佈局組件狀況下,直接使用float: left + 固定左側寬度 + 右邊列margin-left
<div>
  <img style="float: left; width: 140px;" src="https://tva1.sinaimg.cn/large/00831rSTly1gcel7v9ji4j3041041wec.jpg" alt="logo">
  <div style="margin-left: 150px;">
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quos eligendi numquam nihil excepturi sint reiciendis iusto maiores nostrum fugiat harum?</p>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quam, perspiciatis magnam consectetur corrupti suscipit a ratione sunt commodi beatae ad!</p>
  </div>
</div>

實現效果以下圖:

左圖右文佈局

過程分析

左側部分使用float: left會產生一個BFC元素,這個BFC與右側塊級元素div一塊兒進行普通流定位;因爲是兩個按照普通流定位這個兩個元素以前不會產生覆蓋,即便不固定左側元素寬度和右側塊級元素給margin-left也能夠實現效果(這裏給寬度是爲了控制左側固定尺寸)。

🍓內聯元素中使用塊級元素會產生什麼效果?

內聯元素中插入塊級元素會在插入的塊級元素先後各產生一個匿名塊與插入的塊按照普通流進行定位

🍓內聯元素中使用插入浮動元素會產生什麼效果?

內聯元素使用了display: inline-block會產生一個IFC,其內部的浮動會在內部進行浮動定位,而後整個IFC當作一個塊級元素與外部進行文檔流定位
<span style="display: inline-block; background-color: #6EBD91;">
  Lorem ipsum dolor sit amet.
  <span style="float: left; background-color: chocolate;">Lorem, ipsum.</span>
  <div style="background-color: #F4D491;">Lorem, ipsum dolor sit amet consectetur adipisicing elit. Repellat labore, ipsa quo possimus mollitia, officiis quia provident inventore placeat nulla, rem velit ratione ducimus. Facilis eos repudiandae debitis quam voluptatem.</div>
  Lorem ipsum dolor sit amet consectetur.
</span>

效果以下:

效果

以上效果能夠在線預覽

參考文章

寫在最後

既然看到這裏了不妨點個贊鼓勵下做者唄 :)

做者博客:https://blog.lessing.online/

做者github:https://github.com/johniexu

相關文章
相關標籤/搜索