理解CSS-BFC概念
前言
BFC 已經是一個耳聽熟聞的詞語了,但是我對於BFC的概念以及應用場景一直都不是很明白,據說搞懂BFC可以讓我們理解CSS中某些原本詭異的地方。今天著重去了解了一下,做了以下總結。
一、文件流
在解釋BFC之前,先說一下文件流。我們常說的文件流其實分為 定位流 、 浮動流 、 普通流 三種。而普通流其實就是指BFC中的FC。
FC(Formatting Context) ,直譯過來就是“格式化上下文”,它是頁面中的一塊渲染區域,有一套渲染規則,決定了其子元素如何佈局,以及和其他元素之間的關係和作用。常見的FC有 BFC(塊級格式化上下文) 、 IFC(行級格式化上下文)、 GFC(網格佈局格式化上下文) 、 FFC(自適應格式化上下文) 。本文著重介紹BFC,其餘的就不在這裡深入展開了
二、文件流的定位方案
【1】常規流(Normal flow)
- 在常規流中,盒一個接著一個排列;
- 在塊級格式化上下文裡面, 它們豎著排列;
- 在行內格式化上下文裡面, 它們橫著排列;
- 當position為static或relative,並且float為none時會觸發常規流;
- 對於靜態定位(static positioning),position: static,盒的位置是常規流佈局裡的位置;
- 對於相對定位(relative positioning),position: relative,盒偏移位置由top、bottom、left、right屬性定義。即使有偏移,仍然保留原有的位置,其它常規流不能佔用這個位置。
【2】浮動(Floats)
- 左浮動元素儘量靠左、靠上,右浮動同理
- 這導致常規流環繞在它的周邊,除非設定 clear 屬性
- 浮動元素不會影響塊級元素的佈局
- 但浮動元素會影響行內元素的佈局,讓其圍繞在自己周圍,撐大父級元素,從而間接影響塊級元素佈局
- 最高點不會超過當前行的最高點、它前面的浮動元素的最高點
- 不超過它的包含塊,除非元素本身已經比包含塊更寬
- 行內元素出現在左浮動元素的右邊和右浮動元素的左邊,左浮動元素的左邊和右浮動元素的右邊是不會擺放浮動元素的
【3】絕對定位(Absolute positioning)
- 絕對定位方案,盒從常規流中被移除,不影響常規流的佈局;
- 它的定位相對於它的包含塊,相關CSS屬性:top、bottom、left、right;
- 如果元素的屬性position為absolute或fixed,它是絕對定位元素;
- 對於position: absolute,元素定位將相對於上級元素中最近的一個relative、fixed、absolute,如果沒有則相對於body;
二、BFC是什麼?
MDN上的解釋:塊格式化上下文(Block Formatting Context,BFC) 是Web頁面的視覺化CSS渲染的一部分,是佈局過程中生成塊級盒子的區域,也是浮動元素與其他元素的互動限定區域。
BFC(Block Formatting Context) 直譯為“塊級格式化上下文”,是用於佈局塊級盒子的一塊渲染區域。它規定了內部的塊級如何佈局,並且與這個區域外部毫不相干。簡單的概括為: 所謂的BFC就是CSS佈局的一個概念,是一塊區域,一個環境。
三、BFC觸發方式
上文提到BFC是一塊渲染區域,那這塊渲染區域到底在哪,它有多大,這些由生成BFC的元素決定,CSS2.1中規定滿足下列CSS宣告之一的元素便會生成BFC。
【1】根元素,即HTML元素
【2】浮動元素:float值為 left
、 right
【3】overflow值不為 visible,為 auto
、 scroll
、 hidden
【4】display的值為 inline-block
、 inltable-cell
、 table-caption
、 table
、 inline-table
、 flex
、 inline-flex
、 grid
、 inline-grid
【5】position的值為 absolute
或 fixed
四、瀏覽器對BFC的約束規則
【1】內部的Box會在垂直方向上一個接一個的放置
【2】垂直方向上的距離由margin決定。(完整的說法是:屬於同一個BFC的兩個相鄰Box的margin會發生重疊(塌陷),與方向無關。)
【3】每個元素的margin box的左邊, 與包含塊border box的左邊相接觸(對於從左往右的格式化,否則相反)。即使浮動元素也是如此。(這說明BFC中子元素不會超出他的包含塊,而position為absolute的元素可以超出他的包含塊邊界)
【4】BFC的區域不會與float的元素區域重疊
【5】計算BFC的高度時,浮動子元素也參與計算
【6】BFC就是頁面上的一個隔離的獨立容器,容器裡面的子元素不會影響到外面元素,反之亦然
五、 BFC在佈局中的應用
BFC是頁面上的一個隔離的獨立容器,容器裡面的子元素不會影響到外面元素,反之亦然。我們可以利用BFC的這個特性來做很多事。
【1】防止margin重疊(塌陷)
根據BFC佈局規則第【2】條 :垂直方向上的距離由margin決定。(完整的說法是:屬於同一個BFC的兩個相鄰Box的margin會發生重疊(塌陷),與方向無關。)兩個p元素之間的距離應該為(50+50)px,發生了margin重疊後,兩個p之間的距離為50px
解決: 我們可以在其中一個p外面包裹一層容器,並觸發該容器生成一個新BFC。那麼兩個P便不屬於同一個BFC,就不會發生margin重疊了。
<style> p { color: rgba(21, 22, 22, 0.972); background: rgb(231, 105, 2); width: 200px; line-height: 100px; text-align:center; margin: 50px; font-weight: bold; } </style> <body> <p>Hello</p> <p>Hi</p> </body>複製程式碼
<style> .wrap { /* 新的BFC */ overflow: hidden; } </style>複製程式碼
【2】清除內部浮動
根據BFC佈局規則第【5】條 :計算BFC的高度時,浮動子元素也參與計算。parent內部元素浮動了,因此div的高度就坍塌了,要解決坍塌,就得清除浮動。
解決: 為達到清除內部浮動,我們可以觸發parent生成BFC,那麼parent在計算高度時,parent內部的浮動元素child也會參與計算。
<style> .parent { border: 5px solid rgb(231, 105, 2); width: 300px; } .child { border: 5px solid rgba(95, 179, 235, 0.972); width: 100px; height: 100px; float: left; } </style> <body> <div class="parent"> <div class="child"></div> <div class="child"></div> </div> </body>複製程式碼
<style> .parent { border: 5px solid rgb(231, 105, 2); width: 300px; /* 新的BFC */ overflow: hidden; } </style>複製程式碼
【3】自適應多欄佈局
根據BFC佈局規則第【3】條 :每個元素的margin box的左邊, 與包含塊border box的左邊相接觸(對於從左往右的格式化,否則相反)。即使浮動元素也是如此。 因此,雖然存在浮動的元素aslide,但main的左邊依然會與包含塊的左邊相接觸。
解決: 我們可以通過通過給main設定overflow:hidden來觸發main生成BFC, 當觸發main生成BFC後,這個新的BFC不會與浮動的aside重疊。因此會根據包含塊的寬度,和aside的寬度,自動變窄。從而實現自適應兩欄佈局。
<style> body { width: 400px; position: relative; } .aside { width: 100px; height: 150px; float: left; background: rgb(48, 44, 44); } .main { height: 200px; background: rgb(194, 189, 189); } </style> <body> <div class="aside"></div> <div class="main"></div> </body>複製程式碼
<style> .main { /* 新的BFC */ overflow: hidden; height: 200px; background: rgb(194, 189, 189); } </style>複製程式碼
【4】 用於佈局
聖盃佈局和雙飛翼佈局,他們的都要求三列布局,中間寬度自適應,兩邊定寬,這樣做的優勢是重要的東西放在文件流前面可以優先渲染。詳情連結:聖盃佈局&& 雙飛翼佈局
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script> </head> <style> body { min-width: 550px; font-weight: bold; font-size: 20px; } #header, #footer { background: rgba(29, 27, 27, 0.726); text-align: center; height: 60px; line-height: 60px; } #footer { clear: both; } #container { padding-left: 200px; padding-right: 150px; overflow: hidden; } #container .column { position: relative; float: left; text-align: center; height: 300px; line-height: 300px; } #center { width: 100%; background: rgb(206, 201, 201); } #left { width: 200px; right: 200px; margin-left: -100%; background: rgba(95, 179, 235, 0.972); } #right { width: 150px; margin-right: -150px; background: rgb(231, 105, 2); } </style> <body> <div id="header">#header</div> <div id="container"> <div id="center" class="column">#center</div> <div id="left" class="column">#left</div> <div id="right" class="column">#right</div> </div> <div id="footer">#footer</div> </body> </html>複製程式碼