BFC 是前端面試中的一個常考的點,下面介紹一下 什麼是BFC,有什麼用
是 W3C CSS 2.1 規範中的一個概念,它決定了元素如何對其內容進行定位,以及與其餘元素的關係和相互做用。當涉及到可視化佈局的時候,Block Formatting Context提供了一個環境,HTML元素在這個環境中按照必定規則進行佈局。一個環境中的元素不會影響到其它環境中的佈局。好比浮動元素會造成BFC,浮動元素內部子元素的主要受該浮動元素影響,兩個浮動元素之間是互不影響的。這裏有點相似一個BFC就是一個獨立的行政單位的意思。也能夠說BFC就是一個做用範圍。能夠把它理解成是一個獨立的容器,而且這個容器的裏box的佈局,與這個容器外的絕不相干。html
另外一個通俗點的解釋是:在普通流中的 Box(框) 屬於一種 formatting context(格式化上下文) ,類型能夠是 block ,或者是 inline,但不能同時屬於這二者。而且, Block boxes(塊框) 在 block formatting context(塊格式化上下文) 裏格式化, Inline boxes(塊內框) 則在 inline formatting context(行內格式化上下文) 裏格式化。任何被渲染的元素都屬於一個 box ,而且不是 block ,就是inline 。即便是未被任何元素包裹的文本,根據不一樣的狀況,也會屬於匿名的 block boxes 或者 inline boxes。因此上面的描述,便是把全部的元素劃分到對應的 formatting context 裏。前端
其通常表現規則,我整理了如下這幾個狀況:面試
一、在建立了 Block Formatting Context 的元素中,其子元素按文檔流一個接一個地放置。垂直方向上他們的起點是一個包含塊的頂部,兩個相鄰的元素之間的垂直距離取決於 ‘margin’ 特性。瀏覽器
根據 CSS 2.1 8.3.1 Collapsing margins 第一條,兩個相鄰的普通流中的塊框在垂直位置的空白邊會發生摺疊現象。也就是處於同一個BFC中的兩個垂直窗口的margin會重疊。bash
根據 CSS 2.1 8.3.1 Collapsing margins 第三條,生成 block formatting context 的元素不會和在流中的子元素髮生空白邊摺疊。因此解決這種問題的辦法是要爲兩個容器添加具備BFC的包裹容器。app
二、在 Block Formatting Context 中,每個元素左外邊與包含塊的左邊相接觸(對於從右到左的格式化,右外邊接觸右邊), 即便存在浮動也是如此(儘管一個元素的內容區域會因爲浮動而壓縮),除非這個元素也建立了一個新的 Block Formatting Context 。ide
三、Block Formatting Context就是頁面上的一個隔離的獨立容器,容器裏面的子元素不會在佈局上影響到外面的元素,反之也是如此。佈局
四、根據 CSS 2.1 9.5 Floats 中的描述,建立了 Block Formatting Context 的元素不能與浮動元素重疊。ui
表格的 border-box、塊級的替換元素、或是在普通流中建立了新的 block formatting context(如元素的 'overflow' 特性不爲'visible' 時)的元素不能夠與位於相同的 block formatting context 中的浮動元素相重疊。spa
5 、當容器有足夠的剩餘空間容納 BFC 的寬度時,全部瀏覽器都會將 BFC 放置在浮動元素所在行的剩餘空間內。
六、 在 IE6 IE7 IE8 Chrome Opera 中,當 BFC 的寬度介於 "容器剩餘寬度" 與 "容器寬度" 之間時,BFC 會顯示在浮動元素的下一行;在 Safari 中,BFC 則仍然保持顯示在浮動元素所在行,而且 BFC 溢出容器;在 Firefox 中,當容器自己也建立了 BFC 或者容器的 'padding-top'、'border-top-width' 這些特性不都爲 0 時表現與 IE8(S)、Chrome 相似,不然表現與 Safari 相似。
經驗證,最新版本的瀏覽中只有firefox會在同一行顯示,其它瀏覽器均換行。
七、 在 IE6 IE7 IE8 Opera 中,當 BFC 的寬度大於 "容器寬度" 時,BFC 會顯示在浮動元素的下一行;在 Chrome Safari 中,BFC 則仍然保持顯示在浮動元素所在行,而且 BFC 溢出容器;在 Firefox 中,當容器自己也建立了 BFC 或者容器的 'padding- top'、'border-top-width' 這些特性不都爲 0 時表現與 IE8(S) 相似,不然表現與 Chrome 相似。
經驗證,最新版本的瀏覽中只有firefox會在同一行顯示,其它瀏覽器均換行。
八、根據CSS2.1 規範第10.6.7部分的高度計算規則,在計算生成了 block formatting context 的元素的高度時,其浮動子元素應該參與計算。
若是還有其它狀況,請各位回得中補充,我會及時更新!
下面先看一個比較典型的例子:
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>BFC</title>
<style>
*{
padding: 0;
margin: 0;
}
#red,#yellow,#orange,#green{
width: 100px;
height: 100px;
float: left;
}
#red{
background-color: red;
}
#yellow{
background-color: yellow;
}
#orange{
background-color: orange;
}
#green{
background-color: green;
}
</style>
</head>
<body>
<div id="c1">
<div id="red"></div>
<div id="yellow"></div>
</div>
<div id="c2">
<div id="orange"></div>
<div id="green"></div>
</div>
<p>Hellow,everyone,Here is the text!</p>
</body>
</html>複製代碼
效果以下:
該段代碼本意要造成兩行兩列的佈局,可是因爲#red,#yellow,#orange,#green四個div在同一個佈局環境BFC中,所以雖然它們位於兩個不一樣的div(#c1和#c2)中,但仍然不會換行,而是一行四列的排列。
若要使之造成兩行兩列的佈局,就要建立兩個不一樣的佈局環境,也能夠說要建立兩個BFC。那到底怎麼建立BFC呢?
當一個HTML元素知足下面條件的任何一點,均可以產生Block Formatting Context:
float的值不爲none。
overflow的值不爲visible。
display的值爲table-cell, table-caption, inline-block中的任何一個。
position的值不爲relative和static。
若是還其它方式,請在回覆中給出,我會及時更新!!
上面的例子,我再加兩行代碼,建立兩個BFC:
#c1,#c2{
overflow:hidden;
} 複製代碼
效果以下:
上面建立了兩個佈局環境BFC。內部子元素的左浮動不會影響到外部元素。因此#c1和#c2沒有受浮動的影響,仍然各自佔據一行!
若是一個浮動元素後面跟着一個非浮動的元素,那麼就會產生一個覆蓋的現象,不少自適應的兩欄佈局就是這麼作的。
很明顯,.aside 和 .mian重疊了。試分析一下,因爲兩個 box 都處在同一個 BFC 中,都是以 BFC 邊界爲起點,若是兩個 box 自己都具有 BFC 的話,會按順序一個一個排列布局,如今 .main 並不具有 BFC ,按照規則2,內部元素都會從左邊界開始,除非它自己具有 BFC ,按上面規則 4 擁有 BFC 的元素是不能夠跟浮動元素重疊的,因此只要爲 .mian 再建立一個 BFC ,就能夠解決這個重疊的問題。上面已經說過建立 BFC 的方法,能夠根據具體狀況選用不一樣的方法,這裏我選用的是加 overflow:hidden。
.main{
overflow:hidden;
}複製代碼
效果:
因爲ie的緣由須要再加一個解發haslayout的zoom:1,有關haslayout後面會講到。
只要把父元素設爲 BFC 就能夠清理子元素的浮動了,最多見的用法就是在父元素上設置 overflow : hidden 樣式,對於 IE6 加上 zoom :1 就能夠了( IE Haslayout )。
看下面例子:
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
html,body{
height: 100px;
}
*{
padding: 10px;
margin: 0;
color: #000;
text-decoration: none;
list-style: none;
font-family: "微軟雅黑";
}
.outer{
width: 300px;
border: 1px solid #666;
padding: 10px;
}
.innerLeft{
width: 100px;
height: 100px;
background: #f00;
float: left;
}
.innerRight{
width: 100px;
height: 100px;
background: #090;
float:right;
}
</style>
</head>
<body>
<div class="outer">
<div class="innerLeft"></div>
<div class="innerRight"></div>
</div>
</body>
</html>複製代碼
效果圖:
根據 CSS2.1 規範第 10.6.3 部分的高度計算規則,在進行普通流中的塊級非替換元素的高度計算時,浮動子元素不參與計算。
同時 CSS2.1 規範第10.6.7部分的高度計算規則,在計算生成了 block formatting context 的元素的高度時,其浮動子元素應該參與計算。
因此,觸發外部容器BFC,高度將從新計算。好比給outer加上屬性overflow:hidden觸發其BFC。
效果圖:
看下面的例子:
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
html,body{
height: 100%;
}
*{
padding: 0;
margin: 0;
color: #fff;
text-decoration: none;
list-style: none;
font-family: "微軟雅黑";
}
.rowone{
background: #f00;
height: 100px;
margin-bottom: 20px;
overflow: hidden;
}
.rowtwo{
background: #090;
height: 100px;
margin-top: 20px;
position: relative;
}
</style>
</head>
<body>
<div class="rowone"></div>
<div class="rowtwo"></div>
</body>
</html>複製代碼
效果以下:
根據 CSS 2.1 8.3.1 Collapsing margins 第一條,兩個相鄰的普通流中的塊框在垂直位置的空白邊會發生摺疊現象。也就是處於同一個BFC中的兩個垂直窗口的margin會重疊。
根據 CSS 2.1 8.3.1 Collapsing margins 第三條,生成 block formatting context 的元素不會和在流中的子元素髮生空白邊摺疊。因此解決這種問題的辦法是要爲兩個容器添加具備BFC的包裹容器。
因此解這個問題的辦法就是,把兩個容器分別放在兩個據有 BFC 的包裹容器中,IE 裏就是觸發layout 的兩個包裹容器中!
效果以下圖:
上面的例子中咱們用到了IE的zoom:1;其實是觸發了IE的layout。Layout 是 IE 瀏覽器渲染引擎的一個內部組成部分。在 IE 瀏覽器中,一個元素要麼本身對自身的內容進行組織和計算大小, 要麼依賴於包含塊來計算尺寸和組織內容。爲了協調這兩種方式的矛盾,渲染引擎採用了 ‘hasLayout’ 屬性,屬性值能夠爲 true 或 false。 當一個元素的 ‘hasLayout’ 屬性值爲 true時,咱們說這個元素有一個佈局(layout),或擁有佈局。能夠經過 hasLayout 屬性來判斷一個元素是否擁有 layout ,
如 object.currentStyle.hasLayout 。
hasLayout 與 BFC 有不少類似之處,但 hasLayout 的概念會更容易理解。在 Internet Explorer 中,元素使用「佈局」概念來控制尺寸和定位,分爲擁有佈局和沒有佈局兩種狀況,擁有佈局的元素由它控制自己及其子元素的尺寸和定位,而沒有佈局的元素則經過父元素(最近的擁有佈局的祖先元素)來控制尺寸和定位,而一個元素是否擁有佈局則由 hasLayout 屬性告知瀏覽器,它是個布爾型變量,true 表明元素擁有佈局,false 表明元素沒有佈局。簡而言之,hasLayout 只是一個 IE 下專有的屬性,hasLayout 爲 true 的元素瀏覽器會賦予它一系列的效果。
特別注意的是,hasLayout 在 IE 8 及以後的 IE 版本中已經被拋棄,因此在實際開發中只需針對 IE 8 如下的瀏覽器爲某些元素觸發 hasLayout。
5、怎樣觸發layout
一個元素觸發 hasLayout 會影響一個元素的尺寸和定位,這樣會消耗更多的系統資源,所以 IE 設計者默認只爲一部分的元素觸發 hasLayout (即默認有部分元素會觸發 hasLayout ,這與 BFC 基本徹底由開發者經過特定 CSS 觸發並不同),這部分元素以下:
<html>
, <body>
<table>
, <tr>
, <th>
, <td>
<img>
<hr>
<input>
, <button>
, <select>
, <textarea>
, <fieldset>
, <legend>
<iframe>
, <embed>
, <object>
, <applet>
<marquee>
除了 IE 默認會觸發 hasLayout 的元素外,Web 開發者還可使用特定的 CSS 觸發元素的 hasLayout 。
經過爲元素設置如下任一 CSS ,能夠觸發 hasLayout (即把元素的 hasLayout 屬性設置爲 true)。
display: inline-block
height: (除 auto 外任何值)
width: (除 auto 外任何值)
float: (left 或 right)
position: absolute
writing-mode: tb-rl
zoom: (除 normal 外任意值)
min-height: (任意值)
min-width: (任意值)
max-height: (除 none 外任意值)
max-width: (除 none 外任意值)
overflow: (除 visible 外任意值,僅用於塊級元素)
overflow-x: (除 visible 外任意值,僅用於塊級元素)
overflow-y: (除visible 外任意值,僅用於塊級元素)
position: fixed複製代碼
對於內聯元素(能夠是默認被瀏覽器認爲是內聯元素的 span 元素,也能夠是設置了 display: inline 的元素),width 和 height 只在IE5.x 下和 IE6 或更新版本的 quirks 模式下能觸發元素的 hasLayout ,可是對於 IE6,若是瀏覽器運行於標準兼容模式下,內聯元素會忽略 width 或 height 屬性,因此設置 width 或 height 不能在此種狀況下令該元素觸發 hasLayout 。但 zoom 除了在 IE 5.0 中外,老是能觸發 hasLayout 。zoom 用於設置或檢索元素的縮放比例,爲元素設置 zoom: 1 既能夠觸發元素的 hasLayout 同時不會對元素形成多餘的影響。所以綜合考慮瀏覽器之間的兼容和對元素的影響, 建議使用 zoom: 1 來觸發元素的 hasLayout。
hasLayout表現出來的特性跟BFC很類似,因此能夠認爲是IE中的BFC。上面的規則幾乎都遵循,因此上面的問題在IE裏均可以經過觸發hasLayout來解決。
雖然 hasLayout 也會像 BFC 那樣影響着元素的尺寸和定位,但它卻又不是一套完整的標準,而且因爲它默認只爲某些元素觸發,這致使了 IE 下不少前端開發的 bugs ,觸發 hasLayout 更大的意義在於解決一些 IE 下的 bugs ,而不是利用它的一些「反作用」來達到某些效果。另外因爲觸發 hasLayout 的元素會出現一些跟觸發 BFC 的元素類似的效果,所以爲了統一元素在 IE 與支持 BFC 的瀏覽器下的表現,Kayo 建議爲觸發了 BFC 的元素同時觸發 hasLayout ,固然還須要考慮實際的狀況,也有可能只需觸發其中一個就能夠達到表現統一,下面會舉例介紹。
這裏首先列出觸發 hasLayout 元素的一些效果:
如上面例子:
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>BFC6</title>
<style>
html,body{
height: 100%;
}
*{
padding: 0;
margin: 0;
color: #fff;
text-decoration: none;
list-style: none;
font-family: "微軟雅黑";
}
.mg{
zoom: 1;
}
.rowone{
background: #f00;
height: 100px;
margin-bottom: 20px;
}
.rowtwo{
background: #090;
height: 100px;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="mg">
<div class="rowone"></div>
</div>
<div class="mg">
<div class="rowtwo"></div>
</div>
</body>
</html>複製代碼
須要觸發.mg的layout才能解決margin重疊問題(ie7/ie6)
運行效果以下:
上面有關BFC所舉的例子,在IE6/7(及其如下)中觸發layout均可以解決,能夠本身動手試一下,這裏就不重複舉例了。