hasLayout與Block formatting contexts的學習(下)

BFC佈局規則css

  • 內部的Box會在垂直方向,一個接一個地放置。
  • Box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰Box的margin會發生重疊
  • 每一個元素的margin box的左邊, 與包含塊border box的左邊相接觸(對於從左往右的格式化,不然相反)。即便存在浮動也是如此。
  • BFC的區域不會與float box重疊。
  • BFC就是頁面上的一個隔離的獨立容器,容器裏面的子元素不會影響到外面的元素。反之也如此。
  • 計算BFC的高度時,浮動元素也參與計算。
  • 在CSS3中,對這個概念作了改動:http://www.w3.org/TR/css3-box/#block-level0
    在CSS3中,將BFC 叫作 flow root。

簡單示例:
1.自適應兩欄佈局
代碼以下:html

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BFC</title>
        <style>
            body{
                width:350px;
                position:relative;
            }
            div.sidebar{
                float:left;
                width:100px;
                height:200px;
                background-color:#9deaf1;
            }
            div.main{
                height:300px;
                background-color:#5dc2f6;
            }
        </style>
    </head>
    <body>
        <div class="sidebar"></div>
        <div class="main"></div>
    </body>
    </html>

頁面效果圖:css3

上述示例,正好反映了BFC佈局規則:每一個元素的margin box的左邊, 與包含塊border box的左邊相接觸(對於從左往右的格式化,不然相反)。即便存在浮動也是如此。
因此,sidebar雖然存在浮動,但main的左邊依然與包含塊的左邊相接觸。瀏覽器

2.BFC的區域不會與float box重疊。示例以下:app

代碼:ide

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BFC</title>
        <style>
            body{
                width:350px;
                position:relative;
            }
            div.sidebar{
                float:left;
                width:100px;
                height:200px;
                background-color:#9deaf1;
                
            }
            div.main{
                height:300px;
                background-color:#5dc2f6;
                overflow:hidden;
            }
        </style>
    </head>
    <body>
        <div class="sidebar"></div>
        <div class="main"></div>
    </body>
    </html>

頁面效果圖:

經過overflow:hidden;觸發main的BFC,main區域沒有與float的sidebar重疊。說明了BFC的區域不會與float box重疊。佈局

3.計算BFC的高度時,浮動元素也參與計算。url

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BFC</title>
        <style>
            div.wrapper{
                width:300px;
                border:2px solid #5dc2f6;
            }
            div.box{
                width:100px;
                height:200px;
                background-color:#9deaf1;
                border:2px solid #5dc2f6;
                float:left;
            }
        </style>
    </head>
    <body>
        <div class="wrapper">
            <div class="box"></div>
            <div class="box"></div>
        </div>
    </body>
    </html>

頁面效果圖:spa

咱們經過設計

div.wrapper{
        width:300px;
        border:2px solid #5dc2f6;
        overflow:hidden;
}

overflow:hidden; 觸發wrapper的BFC,
清除box的浮動帶來的影響,獲得的頁面效果圖以下:


所以說明:計算BFC的高度時,浮動元素也參與計算。

4.清除垂直邊距重疊

代碼:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BFC</title>
        <style>
            div.box{
                width:100px;
                height:100px;
                background-color:#9deaf1;
                border:2px solid #5dc2f6;
            }
            div.m50{
                margin-bottom:50px;
            }
            div.m100{
                margin-top:100px;
            }
        </style>
    </head>
    <body>
        <div class="box m50"></div>
        <div class="box m100"></div>
    </body>
    </html>

頁面效果圖以下:

如圖所示,Box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰Box的margin會發生重疊。因此,兩個div的垂直距離變成了100px,而不是150px了。

若是咱們給第二個div套上一層wrapper,而且觸發外層的BFC,那麼兩個div就不是同一個BFC的兩個相鄰的Box了,而是變成兩個獨立的BFC。

代碼:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BFC</title>
        <style>
            div.box{
                width:100px;
                height:100px;
                background-color:#9deaf1;
                border:2px solid #5dc2f6;
            }
            div.wrapper{
                overflow:hidden;
            }
            div.m50{
                margin-bottom:50px;
            }
            div.m100{
                margin-top:100px;
            }
        </style>
    </head>
    <body>
        <div class="box m50"></div>
        <div class="wrapper">
            <div class="box m100"></div>
        </div>
    </body>
    </html>

頁面效果圖以下:

垂直邊距再也不重疊,不是100px,而是150px了。

  • 總結

    以上事例都證實了:BFC就是頁面上的一個隔離的獨立容器,容器裏面的子元素不會影響到外面的元素。反之也如此。
    
      由於BFC內部的元素和外部的元素絕對不會互相影響,所以, 當BFC外部存在浮動時,它不該該影響BFC內部Box的佈局,因此BFC經過改變本身的寬度,實現不與浮動box有重疊。一樣的,當BFC內部有浮動時,爲了避免影響外部元素的佈局,BFC計算高度時會包括浮動的高度。避免margin重疊也是這樣的一個道理。

hasLayout與Block formatting contexts的實例分析

一. 在觸發 hasLayout 的元素和建立了 Block Formatting Contexts 的元素中,浮動元素參與高度的計算

狀況1:沒有建立 Block formatting contexts 的塊級非替換元素,觸發了 IE 的 hasLayout。

分析如下代碼:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>hasLayout 和 BFC</title>
        <style>
            div.wrapper{
                width:300px;
            }
            div#container{
                background-color:#9deaf1;
                zoom:1;
            }
            span#span1{
                background-color:#5dc2f6;
            }
            div#div1{
                width:150px;
                height:50px;
                background-color:#0576b0;
            }
            div#div2{
                float:left;
                background-color:#4dd5b3;
            }
        </style>
    </head>
    <body>
        <div class="wrapper">
                <div id="container">
                    <span id="span1">simple text</span>
                    <div id="div1">in flow</div>
                    <div id="div2">float:left</div>
            </div>
        </div>
    </body>
    </html>
  • container 沒有建立 Block formatting contexts。
  • container 的 'zoom:1'設置,是爲了觸發 IE 中的 hasLayout;
  • container 的高度值爲 auto,而且 'overflow' 的值爲默認的 'visible';
  • span1是一個行內元素, div1 是一個處於普通流中的塊元素;
  • div2 是一個浮動的塊級元素。

根據 CSS2.1 規範第 10.6.3部分的高度計算規則,在進行普通流中的塊級非替換元素的高度計算時,浮動子元素不參與計算。

因此,在進行 container 高度計算時,只受 span1 和 div1的影響,應該是它們兩個的高度之和,因此最終container 的高度不包括div2的高度。

頁面效果圖在各瀏覽器的效果以下:
IE6 IE7:

IE8 Firefox Chrome Safari Opera:

當去掉container的zoom:1;各瀏覽器表現一致:

狀況2:建立了 BFC的塊級非替換元素,未觸發 IE 的 hasLayout。

代碼以下:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>hasLayout 和 BFC</title>
        <style>
            div.wrapper{
                width:300px;
            }
            div#container{
                background-color:#9deaf1;
                overflow:hidden;
            }
            span#span1{
                background-color:#5dc2f6;
            }
            div#div1{
                width:150px;
                height:50px;
                background-color:#0576b0;
            }
            div#div2{
                float:left;
                background-color:#4dd5b3;
            }
        </style>
    </head>
    <body>
        <div class="wrapper">
                <div id="container">
                        <span id="span1">simple text</span>
                <div id="div1">in flow</div>
                <div id="div2">float:left</div>
            </div>
        </div>
    </body>
    </html>
  • container 的 ‘overflow:hidden;’ 建立了BFC;
  • container 的 ‘overflow:hidden;’,在 IE6 中未觸發 hasLayout,但在 IE7中觸發了 hasLayout;
  • container 的高度值爲 ‘auto’;
  • span1是一個行內元素,div1是一個處於普通流中的塊元素;
  • div2是一個浮動的塊級元素。

頁面效果圖以下:

IE6:

IE7/IE8/Firefox/Chrome/Safari/Opera

可見,只要 container 建立了 BFC,其浮動子元素就會參與其高度計算(IE7是因爲觸發了hasLayout 致使與其它瀏覽器的效果相同)。

二.與浮動元素相鄰的、觸發了 hasLayout 的元素或建立了 BFC 的元素,都不能與浮動元素相互覆蓋。

與浮動元素相鄰的、觸發了 hasLayout 的元素或建立了 Block formatting contexts的元素,都不能與浮動元素相互覆蓋。若是浮動元素的兩側有足夠的空間放置該元素,則元素會緊鄰浮動元素放置,必要時,該元素的寬度將會被壓縮。不然它們可能會定位到浮動元素的下方。

狀況1:沒有建立BFC的塊級非替換元素,觸發了 IE 的 hasLayout。

代碼:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>hasLayout 和 BFC</title>
        <style>
            div#container{
                border:2px solid #ddd;
                width:300px;
                height:150px;
                background:url("http://images0.cnblogs.com/
                blog2015/790006/201508/041827351894332.png") repeat;
            }
            div#div1{
                width:100px;
                height:100px;
                background-color:#9deaf1;
                float:left;
                filter:alpha("opacity=50");
                opacity: 0.5;
            }
            div#div2{
                background-color:green;
                zoom:1;
            }
        </style>
    </head>
    <body>
        <div id="container">
            <div id="div1">
                Float Block
            </div>
            <div id="div2"> 
                懷才就象懷孕,時間久了會讓人看出來。
            </div>
        </div>
    </body>
    </html>

IE6:

IE7/IE8

Firefox/Chrome/Safari/Opera

根據 CSS 2.1 9.5 Floats 中的描述,浮動元素會覆蓋普通流中的塊容器。因此,div2 應該有一部分被 div1 覆蓋。

狀況2:建立了 BFC的塊級非替換元素,未觸發 IE 的 hasLayout。
代碼:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>hasLayout 和 BFC</title>
        <style>
            div#container{
                border:2px solid #ddd;
                width:300px;
                height:150px;
                background:url("http://images0.cnblogs.com/
                blog2015/790006/201508/041827351894332.png") repeat;
            }
            div#div1{
                width:100px;
                height:100px;
                background-color:#9deaf1;
                float:left;
                filter:alpha("opacity=50");
                opacity: 0.5;
            }
            div#div2{
                background-color:green;
                overflow:hidden;
            }
        </style>
</head>
<body>
    <div id="container">
        <div id="div1">
            Float Block
        </div>
        <div id="div2"> 
            懷才就象懷孕,時間久了會讓人看出來。
        </div>
    </div>
</body>
</html>

Firefox/Chrome/Safari/Opera:

IE6:

IE7/IE8

  • div1 是一個浮動元素,背景是50%的透明
  • div2 的 ‘overflow:hidden;’ 在 IE6 中未觸發 hasLayout,但在 IE7 中觸發了 hasLayout。
    根據 CSS 2.1 9.5 Floats 中的描述,建立了BFC的元素不能與浮動元素重疊, 因此,div2 應該有一部分被 div1 覆蓋。

三. 觸發 hasLayout 的元素和建立了 BFC的元素不會與它們的子元素髮生外邊距摺疊

狀況1:沒有生成BFC的塊級非替換元素,觸發了 IE 的 hasLayout。

代碼:

<!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>hasLayout和BFC</title>
            <style>
                div.box{
                    width:100px;
                    height:100px;
                    background-color:#9deaf1;
                    border:2px solid #5dc2f6;
                }
                div.wrapper{
                    zoom:1;
                }
                div.m50{
                    margin-bottom:50px;
                }
                div.m100{
                    margin-top:100px;
                }
            </style>
        </head>
        <body>
            <div class="box m50"></div>
            <div class="wrapper">
                <div class="box m100"></div>
            </div>
        </body>
        </html>

根據 CSS 2.1 8.3.1 Collapsing margins 第一條,兩個相鄰的普通流中的塊框在垂直位置的空白邊會發生摺疊現象。
經過zoom:1;在IE中觸發了hasLayout,因此,垂直邊距不重疊,爲150px。
而BFC未觸發,因此垂直邊距重疊,爲100px;

IE6/IE7:

IE8/Firefox/Chrome/Safari/Opera:

狀況2:生成 BFC的塊級非替換元素,未觸發 IE 的 hasLayout。
代碼:

<!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>BFC</title>
                <style>
                    div.box{
                        width:100px;
                        height:100px;
                        background-color:#9deaf1;
                        border:2px solid #5dc2f6;
                    }
                    div.wrapper{
                        overflow:hidden;
                    }
                    div.m50{
                        margin-bottom:50px;
                    }
                    div.m100{
                        margin-top:100px;
                    }
                </style>
            </head>
            <body>
                <div class="box m50"></div>
                <div class="wrapper">
                    <div class="box m100"></div>
                </div>
            </body>
            </html>

IE6:

IE7/IE8/Firefox/Chrome/Safari/Opera:

IE7此時觸發了hasLayout,但IE6沒有觸發hasLayout。

hasLayout 和 BFC 的異同及可能產生的問題

區別

  • 在 IE8以前的版本中,沒有規範中說起的 Block formatting contexts 和 Inline formatting contexts概念,而是用 hasLayout 來達到類似的目的。
  • 在 IE 中可經過設置 ‘width’、’height’、’min-width’、’min-height’、’max-width’、’max-height’、 ‘zoom’、’writing-mode’ 來觸發 hasLayout,而這些特性值的設置不可以使元素建立 BFC。
  • 在 IE 中不少元素默認就是擁有佈局的,如 IPUNT, BUTTON, SELECT, TEXTAREA 等,可是這些元素在標準中會造成 Inline formatting contexts。

共同點

  • 二者都是決定了對內容如何定位及大小計算的規則。
  • 二者都決定了與其餘元素的相互做用的規則。
  • ‘table-cell’ 和 ‘table-caption’ 既是 hasLayout 的元素,又是能夠建立 BFC 的元素。
  • 浮動元素,絕對定位元素,inline-block 元素以及除 ‘visible’ 外任意值的 overflow(IE7) 在 IE 中能夠觸發 hasLayout,同時在標準中,又能夠建立BFC。

可能產生的兼容性問題:

因爲 hasLayout 和 BFC是對一類事物的不一樣理解,而且他們的啓用條件不盡相同,所以若是一個元素設計時,在 IE 早期版本中觸發了 hasLayout ,但在其餘瀏覽器中又沒有建立BFC,或者相反,一個元素在 IE 早期版本中沒有觸發 hasLayout ,在其餘瀏覽器中卻建立了 BFC(如設置了 ‘overflow:hidden’ ),將致使頁面佈局的重大差別。

解決方案

僅當一個元素即在 IE 早期版本中觸發了 hasLayout,又在其餘瀏覽器中建立了BFC時,才能避免上述問題的發生。即同時啓用上述二者以保證各瀏覽器的兼容,或者相反,二者皆不啓用。
        
    使元素即生成了BFC,又觸發了 hasLayout
    對於觸發 hasLayout 的元素,經過 CSS 設置,使它產生BFC;
    生成 BFC可是沒有觸發 hasLayout 的元素,經過設置 ‘zoom:1’,使其觸發       hasLayout。
    使元素即沒有觸發 hasLayout,又沒有建立 BFC。

若有錯誤或者不足的地方,還望指正!----妙瞳

文章參考資料:
http://www.cnblogs.com/lhb25/p/inside-block-formatting-ontext.html
http://w3help.org/zh-cn/causes/RM8002

相關文章
相關標籤/搜索