BFC原理剖析

本文講了BFC的概念是什麼; BFC的約束規則;咋樣才能觸發生成新的BFC;BFC在佈局中的應用:防止margin重疊(塌陷,以最大的爲準); 清除內部浮動;自適應兩(多)欄佈局。css

1. BFC是什麼?html

Block fomatting context = block-level box + Formatting Context瀏覽器

Box:ide

  Box即盒子模型;佈局

  • block-level box即塊級元素

display屬性爲block, list-item, table的元素,會生成block-level box;而且參與 block fomatting context;學習

  • inline-level box即行內元素

display 屬性爲 inline, inline-block, inline-table的元素,會生成inline-level box。而且參與 inline formatting context;flex

Formatting contextui

  Formatting context是W3C CSS2.1規範中的一個概念。它是頁面中的一塊渲染區域,而且有一套渲染規則,它決定了其子元素將如何定位,以及和其餘元素的關係、相互做用。最多見的 Formatting context 有 Block fomatting context (簡稱BFC)和 Inline formatting context(簡稱IFC)。scala

  CSS2.1 中只有BFC和IFC, CSS3中還增長了G(grid)FC和F(flex)FC。   3d

BFC 定義

  BFC(Block formatting context)直譯爲"塊級格式化上下文"。它是一個獨立的渲染區域,只有Block-level box參與, 它規定了內部的Block-level Box如何佈局,而且與這個區域外部絕不相干。    

2.BFC的生成

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

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

display:table也認爲能夠生成BFC,其實這裏的主要緣由在於Table會默認生成一個匿名的table-cell,正是這個匿名的table-cell生成了BFC

  • position的值爲absolute或fixed

3. BFC的約束規則

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

看到以上的幾條約束,想一想咱們學習css時的幾條規則

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

4. BFC在佈局中的應用

4.1  防止margin重疊(塌陷):

兩個相鄰Box垂直方向margin重疊

<style>

    p {

        color: #f55;

        background: #fcc;

        width: 200px;

        line-height: 100px;

        text-align:center;

        margin: 100px;

    }

</style>

<body>

    <p>Haha</p>

    <p>Hehe</p>

</body>

 

 兩個p之間的距離爲100px,發送了margin重疊(塌陷),以最大的爲準,若是第一個P的margin爲80的話,兩個P之間的距離仍是100,以最大的爲準。

根據BFC佈局規則第二條:

Box垂直方向的距離由margin決定。屬於同一個BFC(上例中是body根元素的BFC)的兩個相鄰Box的margin會發生重疊

咱們能夠在p外面包裹一層容器,並觸發該容器生成一個新BFC。那麼兩個P便不屬於同一個BFC,就不會發生margin重疊了。

代碼:

<style>

    .wrap {

        overflow: hidden;// 新的BFC

    }

    p {

        color: #f55;

        background: #fcc;

        width: 200px;

        line-height: 100px;

        text-align:center;

        margin: 100px;

    }

</style>

<body>

    <p>Haha</p>

    <div class="wrap">

        <p>Hehe</p>

    </div>

</body>

 

相鄰Box水平方向margin重疊

<!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發生了重疊。

咱們能夠給div加個display:inline-block,觸每一個div容器生成一個BFC。那麼三個DIV便不屬於同一個BFC(這個只body根元素造成的BFC),就不會發生margin重疊了。

 

嵌套元素的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>

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

 

要阻止嵌套元素的margin重疊,只需讓ul生成BFC便可(將上例中的註釋去掉),這樣div、ul、li之間便不會發生重疊現象。

 

而li位於同一BFC內因此仍然存在重疊現象。

 給li設置line-block從新生成一個bfc就不存在重疊現象了。

 

須要注意的是:

若是爲ul設置了border或padding,那元素的margin便會被包含在父元素的盒式模型內,不會與外部div重疊。

《CSS權威指南》中提到塊級正常流元素的高度設置爲auto,並且只有塊級子元素,其默認高度將是從最高塊級子元素的外邊框邊界到最低塊級子元素外邊框邊界之間的距離。若是塊級元素右上內邊距或下內邊距,或者有上邊框或下邊框,其高度是從其最高子元素的上外邊距邊界到其最低子元素的下外邊距邊界之間的距離。

 

4.2 清除內部浮動

<style>

    .par {

        border: 5px solid #fcc;

        width: 300px;

    }

 

    .child {

        border: 5px solid #f66;

        width:100px;

        height: 100px;

        float: left;

    }

</style>

<body>

    <div class="par">

        <div class="child"></div>

        <div class="child"></div>

    </div>

</body>

頁面:

根據BFC佈局規則第六條:

計算BFC的高度時,浮動元素也參與計算

爲達到清除內部浮動,咱們能夠觸發par生成BFC,那麼par在計算高度時,par內部的浮動元素child也會參與計算。

.par {

    overflow: hidden;

}

 

4.3 自適應多欄佈局的

4.3.1 自適應兩欄佈局

<style>

    body {

        width: 300px;

        position: relative;

    }

 

    .aside {

        width: 100px;

        height: 150px;

        float: left;

        background: #f66;

    }

 

    .main {

        height: 200px;

        background: #fcc;

    }

</style>

<body>

    <div class="aside"></div>

    <div class="main"></div>

</body>

根據BFC佈局規則第3條:

每一個元素的margin box的左邊, 與包含塊border box的左邊相接觸(對於從左往右的格式化,不然相反)。即便存在浮動也是如此。

      所以,雖然存在浮動的元素aslide,但main的左邊依然會與包含塊的左邊相接觸。

根據BFC佈局規則第四條:

BFC的區域不會與float box重疊。

咱們能夠經過經過觸發main生成BFC, 來實現自適應兩欄佈局。

.main {

    overflow: hidden;

}

當觸發main生成BFC後,這個新的BFC不會與浮動的aside重疊。所以會根據包含塊的寬度,和aside的寬度,自動變窄。效果以下:

 

4.3.2 自適應兩欄佈局

<!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>

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

 

4. 總結

其實以上的幾個例子都體現了BFC佈局規則第五條:

BFC就是頁面上的一個隔離的獨立容器,容器裏面的子元素不會影響到外面的元素。反之也如此。

由於BFC內部的元素和外部的元素絕對不會互相影響,所以,

當BFC外部存在浮動時,它不該該影響BFC內部Box的佈局,BFC會經過變窄,而不與浮動有重疊。 一樣的,當BFC內部有浮動時,爲了避免影響外部元素的佈局,BFC計算高度時會包括浮動的高度。 避免margin重疊也是這樣的一個道理。  

相關文章
相關標籤/搜索