我對BFC的理解

  最初這篇文章打算回答寒冬大神的第一問,談談CSS佈局。原本呢我覺得佈局主要涉及float跟display相關屬性,以及他們的包含框、靜態位置等等。後來看了大神的一片面試文章,嗯?這裏怎麼還有個BFC,這是神馬東東。待我搜索一下,薩薩薩,不看不知道,越看越糊塗,這究竟是個神馬東東。。。通過一個周時間的查閱資料和自我思考,在此總結一下我對BFC的認識,願與各位道友分享,歡迎拍磚!css

 

  對CSS有了解的道友們確定都知道盒式模型這個概念,對一個元素設置CSS,首先須要知道這個元素是block仍是inline類型。而BFC就是用來格式化塊級盒子,一樣管理inline類型的盒子還有IFC,以及其餘的FC。那首先咱們就來看一下FC的概念。html

   Formatting Context:指頁面中的一個渲染區域,而且擁有一套渲染規則,他決定了其子元素如何定位,以及與其餘元素的相互關係和做用。面試

  BFC:塊級格式化上下文,它是指一個獨立的塊級渲染區域,只有Block-level BOX參與,該區域擁有一套渲染規則來約束塊級盒子的佈局,且與區域外部無關。chrome

 

  BFC的生成瀏覽器

 

  既然上文提到BFC是一塊渲染區域,那這塊渲染區域到底在哪,它又是有多大,這些由生成BFC的元素決定,CSS2.1中規定知足下列CSS聲明之一的元素便會生成BFC。數據結構

  • 根元素
  • float的值不爲none
  • overflow的值不爲visible
  • display的值爲inline-block、table-cell、table-caption
  • position的值爲absolute或fixed

  看到有道友文章中把display:table也認爲能夠生成BFC,其實這裏的主要緣由在於Table會默認生成一個匿名的table-cell,正是這個匿名的table-ccell生成了BFCide

 

  BFC的約束規則佈局

 瀏覽器對於BFC這塊區域的約束規則以下:學習

  • 生成BFC元素的子元素會一個接一個的放置。垂直方向上他們的起點是一個包含塊的頂部,兩個相鄰子元素之間的垂直距離取決於元素的margin特性。在BFC中相鄰的塊級元素外邊距會摺疊。
  • 生成BFC元素的子元素中,每個子元素作外邊距與包含塊的左邊界相接觸,(對於從右到左的格式化,右外邊距接觸右邊界),即便浮動元素也是如此(儘管子元素的內容區域會因爲浮動而壓縮),除非這個子元素也建立了一個新的BFC(如它自身也是一個浮動元素)。

  有道友對它作了分解,咱們直接拿來:測試

  1. 內部的Box會在垂直方向上一個接一個的放置
  2. 垂直方向上的距離由margin決定。(完整的說法是:屬於同一個BFC的兩個相鄰Box的margin會發生重疊,與方向無關。)
  3. 每一個元素的左外邊距與包含塊的左邊界相接觸(從左向右),即便浮動元素也是如此。(這說明BFC中子元素不會超出他的包含塊,而position爲absolute的元素能夠超出他的包含塊邊界)
  4. BFC的區域不會與float的元素區域重疊
  5. 計算BFC的高度時,浮動子元素也參與計算
  6. BFC就是頁面上的一個隔離的獨立容器,容器裏面的子元素不會影響到外面元素,反之亦然

  看到以上的幾條約束,讓我想起學習css時的幾條規則

  • Block元素會擴展到與父元素同寬,因此block元素會垂直排列
  • 垂直方向上的兩個相鄰DIV的margin會重疊,而水平方向不會(此規則並不徹底正確)
  • 浮動元素會盡可能接近往左上方(或右上方)
  • 爲父元素設置overflow:hidden或浮動父元素,則會包含浮動元素
  • ......

  哈哈,一股恍然大悟的感受有木有,原來這些規則的背後都有更深層的概念,冥冥之中自有定數。。。

  

  BFC在佈局中的應用

  上面說了那麼多,那BFC究竟有何用處,畢竟再好的東西也要爲我所用才行。

  防止margin重疊:

  同一個BFC中的兩個相鄰Box纔會發生重疊與方向無關,不過因爲上文提到的第一條限制,咱們甚少看到水平方向的margin重疊。這在IE中是個例外,IE能夠設置write-mode。下面這個demo來自寒冬大神的博客

  

<!doctype HTML>
<html>
<head>
<style type="text/css">

    #green {
        margin:10px 10px 10px 10px
    }
    #blue {
        margin:10px 10px 10px 10px
    }
    #red {
        margin:10px 10px 10px 10px
    }
    body {
        writing-mode:tb-rl;
    }

</style>
</head>
<body>

<div id="green" style="background:lightgreen;height:100px;width:100px;"></div>
<div id="blue" style="background:lightblue;height:100px;width:100px;"></div>
<div id="red" style="background:pink;height:100px;width:100px;"></div>

</body>
</html>
margin水平重疊

  能夠看到水平方向的margin發生了重疊。  

  要阻止margin重疊,只要將兩個元素別放在一個BFC中便可(能夠用上文提到的方式讓相鄰元素其中一個生成BFC)。阻止兩個相鄰元素的margin重疊看起來沒有什麼意義,主要用於嵌套元素。

<!DOCTYPE html>
<html>  
<head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <!--The viewport meta tag is used to improve the presentation and behavior of the samples 
    on iOS devices-->
  <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
  <title></title>

  <style> 
    html, body { height: 100%; width: 100%; margin: 0; padding: 0; }
    #map{
      padding:0;
    }
    .first{
      margin:20px;
      background:lightgreen;
      width:100px;
      height:100px;
    }
    ul{
      /*display:inline-block;*/
      margin:10px;
      background:lightblue;
    }
    li{
      margin:25px;
    }
  </style> 
  
  
</head> 

<body class="claro"> 
  <div class="first"></div>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
  </ul>
</body> 

</html>
margin嵌套重疊

  此時div與ul之間的垂直距離,取div、ul、li三者之間的最大外邊距。

  要阻止嵌套元素的重疊,只需讓ul生成BFC便可(將上例中的註釋去掉),這樣div、ul、li之間便不會發生重疊現象。而li位於同一BFC內因此仍然存在重疊現象。

  須要注意的是:

  • 若是將爲ul使用overflow:hidden的方式,ul生成BFC不該該再發生重疊現象但是我在chrome、firefox、ie上的測試結果都有發生重疊現象。這個問題,我沒找到答案,還請道友們給解答一下
  • 若是爲ul設置了border或padding,那元素的margin便會被包含在父元素的盒式模型內,不會與外部div重疊。《CSS權威指南》中提到塊級正常流元素的高度設置爲auto,並且只有塊級子元素,其默認高度將是從最高塊級子元素的外邊框邊界到最低塊級子元素外邊框邊界之間的距離。若是塊級元素右上內邊距或下內邊距,或者有上邊框或下邊框,其高度是從其最高子元素的上外邊距邊界到其最低子元素的下外邊距邊界之間的距離。

  浮動相關問題:

  使得父元素包含子元素,常見的方式是爲父元素設置overflow:hidden或浮動父元素。根本緣由在於建立BFC的元素,子浮動元素也會參與其高度計算,即不會產生高度塌陷問題。實際上只要讓父元素生成BFC便可,並不僅有這兩種方式。

<!DOCTYPE html>
<html>  
<head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <!--The viewport meta tag is used to improve the presentation and behavior of the samples 
    on iOS devices-->
  <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
  <title></title>

  <style> 
    html, body { height: 100%; width: 100%; margin: 0; padding: 0; }
    #map{
      padding:0;
    }
    .first{
      margin:20px;
      background:lightgreen;
      border: 2px solid lightgreen;
      /*display:inline-block;*/
      /*overflow:hidden;*/
      /*float: left;*/
      /*position: absolute;*/
    }
    ul{
      overflow:hidden;
      margin:10px;
      background:lightblue;
      width:100px;
      height:200px;
      float: left;
    }
    li{
      margin:25px;
    }
  </style> 
  
  
</head> 

<body class="claro"> 
  <div class="first">
    <ul>
      <li>1</li>
      <li>2</li>
      <li>3</li>
    </ul>
  </div>
  
</body> 

</html>
包圍浮動

  

  將上例中first中任意一項註釋去掉均可以獲得包圍浮動的效果,其中overflow:hidden方式,與正常流最接近。

     

  關於清除浮動更詳盡的方式,請你們參考這篇文章此處,dolphinX道友的博客簡潔明瞭。

  多欄佈局的一種方式

  上文提到的一條規則:與浮動元素相鄰的已生成BFC的元素不能與浮動元素相互覆蓋。利用該特性能夠做爲多欄佈局的一種實現方式。

<!DOCTYPE html>
<html>  
<head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <!--The viewport meta tag is used to improve the presentation and behavior of the samples 
    on iOS devices-->
  <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
  <title></title>

  <style> 
    html, body { height: 100%; width: 100%; margin: 0; padding: 0; }
    .left{
      background:pink;
      float: left;
      width:180px;
    }
    .center{
      background:lightyellow;
      overflow:hidden;
      
    }
    .right{
      background: lightblue;
      width:180px;
      float:right;
    }
  </style> 
  
  
</head> 

<body class="claro"> 
  <div class="container">
    <div class="left">
      <pre>
  .left{
    background:pink;
    float: left;
    width:180px;
  }
      </pre>
    </div>
    <div class="right">
       <pre>
  .right{
    background:lightblue;
    width:180px;
    float:right;
  }
      </pre>
    </div>
    <div class="center">
    <pre>
  .center{
    background:lightyellow;
    overflow:hidden;
    height:116px;
  }
      </pre>
    </div>
  </div>

</html>
多欄佈局

  這種佈局的特色在於左右兩欄寬度固定,中間欄能夠根據瀏覽器寬度自適應。

  

  IE中也有與BFC相似的概念成爲hasLayout,我平時工做最低也是使用IE8,並無涉及到這部分因此還請道友們查詢其餘資料。

  總結

  在我第一次接觸到BFC時常常有一個疑問,BFC的結構是什麼樣的,像DOM同樣的樹狀結構,仍是一個BFC集合。其實咱們不須要關心BFC的具體結構,這要看瀏覽器的具體實現採用什麼樣的數據結構。對於BFC咱們只須要知道使用必定的CSS聲明能夠生成BFC,瀏覽器對生成的BFC有一系列的渲染規則,利用這些渲染規則能夠達到必定的佈局效果,爲了達到特定的佈局效果咱們讓元素生成BFC。

  對於CSS新手來講不建議涉獵BFC,仍是應該去看看相應的CSS佈局規則,像《CSS設計指南》、《CSS權威指南》這兩本都很不錯,達到必定積累再來看BFC,說不定會有一種豁然開朗的感受。BFC中幾乎涉及到CSS佈局的全部重要屬性,這也是BFC的難點和咱們須要掌握BFC的意義所在。

  文章中的部份內容可能與道友看到的其餘博客有所出入,畢竟每一個人的工做經驗、所遇問題跟測試方法不同,差別在所不免,探討技術的樂趣在於不斷的總結積累與自我推翻,只要大方向正確細節問題能夠慢慢探索。

 

   參考文章

  http://www.cnblogs.com/winter-cn/archive/2012/11/16/2772562.html

  http://f2e-js.com/?p=2599

  http://www.cnblogs.com/dolphinX/p/3508869.html

  http://wenku.baidu.com/link?url=yRqbHnEVEL58mfPg1KDneWqX5AjcL34U70ANznTaWU6DUcTx6yaEcKBbDjPxyP3GVoNN7-GdTSPbEmty6RmCTJ3qY6FzPqSB7TvwbmFayYO

  http://reference.sitepoint.com/css/blockformatting

  http://www.yuiblog.com/blog/2010/05/19/css-101-block-formatting-contexts/

  http://www.cnblogs.com/winter-cn/archive/2013/05/11/3072929.html

 

  到了各位道友點評時間,若有錯誤,還請不吝指正。。。

相關文章
相關標籤/搜索