談談BFC與ie特有屬性hasLayout

發現我很久沒更新博文了=-=這裏把我以前在博客園寫過的一篇關於BFC的文章粘貼過來,順便本身也再次作個總結。css


最近看了一篇總結ie常見bug的文章,裏面提到ie多數的bug源於她的特有屬性:hasLayout。這個屬性之前也瞭解過一點,但沒有深刻去理解,因而查閱了一些相關的資料,如今在此來對這個屬性做一下總結。html

haslayout的廣泛定義

洋洋灑灑一大篇。這裏的內容若是以爲很差懂的話建議能夠先看看後文提到的BFC屬性。chrome

在ie中,一個元素要麼本身對自身的內容進行計算大小和組織,要麼依賴於父元素來計算尺寸和組織內容。爲了調節這兩個不一樣的概念,渲染引擎採用了
hasLayout 的屬性,屬性值能夠爲true或false。當一個元素的
hasLayout屬性值爲true時,咱們說這個元素有一個佈局(layout)。瀏覽器

若是它設置成了true,它就不得不去渲染它本身,所以元素不得不擴展去包含它的流出的內容。例如浮動或者很長很長的沒有截斷的單詞,若是haslayout沒有被設置成true,那麼元素得依靠某個祖先元素來渲染它。這就是不少的ie
bugs誕生的地方。sass

當一個元素有一個佈局時,它負責對本身和可能的子孫元素進行尺寸計算和定位。簡單來講,這意味着這個元素須要花更多的代價來維護自身和裏面的內容,而不是依賴於祖先元素來完成這些工做。所以,一些元素默認會有一個佈局。當咱們說一個元素「擁有layout」或 「獲得layout,ide

或者說一個元素「has layout」 的時候,咱們的意思是指它的微軟專有屬性 hasLayout 被設爲了 true。經過IE Developer Toolbar 能夠查看 IE 下 HTML元素是否擁有haslayout,在 IE Developer Toolbar 下,擁有 haslayout的元素,一般顯示爲「haslayout = -1」。佈局

  值得注意的是,css下是沒有haslayout這一個屬性的,只能經過把某些屬性設置特定值來使ie下的hasLayout屬性觸發。這個屬性在ie8及之後版本中被拋棄。測試

激活「haslayout」的方式——調整下列css屬性:flex

  • width:非auto任意值——優先考慮spa

  • height:非auto任意值——對 IE6 及更早版原本說很經常使用,該方法被稱爲霍莉破解(Holly hack),即設定這個元素的高度爲 1% (height:1%;)。可是要注意,當這個元素的 overflow 屬性被設置爲 visible 時,這個方法就失效了。

  • zoom:非normal任意值——該屬性也爲ie特有屬性。通常測試的時候用zoom:1。能夠避免改變其餘屬性破壞佈局。

  • position:absolute——可能引起新問題。

  • float:left/right——ie 常見bug不少都由於元素設置了浮動而觸發haslayout產生的。

  • display:inline-block——當一個內聯元素想得到layout就要使用這個屬性。

  • min-heightmax-height(除none)、min-widthmax-width(除none)設置任意值——針對ie7。

  • overflowoverflow-xoverflow-yvisible外任意值——針對ie7。

  • position:fixed——針對ie7。

重置「haslayout」:須要沒有其餘屬性激活haslayout的前提下。

  • width, height (設爲 "auto")

  • max-width, max-height (設爲 "none")(在 IE 7 中)

  • position (設爲 "static")

  • float (設爲 "none")

  • overflow (設爲 "visible") (在 IE 7 中)

  • zoom (設爲 "normal")

  • writing-mode (從 "tb-rl" 設爲 "lr-t")

注意:當用inline-block激活了haslayout 屬性時,就算在一條獨立的規則中覆蓋這個屬性爲blockinline,haslayout 這個標誌位也不會被重置爲 false。把 min-width, min-height 設爲它們的默認值"0"仍然會賦予 hasLayout,可是 IE 7 卻能夠接受一個不合法的屬性auto來重置 hasLayout。


塊級格式化上下文BFC

BFC是W3C CSS 2.1
規範中的一個概念,它決定了元素如何對其內容進行定位,以及與其餘元素的關係和相互做用。當涉及到可視化佈局的時候,Block Formatting Context提供了一個環境,HTML元素在這個環境中按照必定規則進行佈局。一個環境中的元素不會影響到其它環境中的佈局。

要更好地理解BFC,要先來談談Box和Formatting Context的概念。咱們知道網頁佈局是由不少盒子組成的,這些塊就是Box。元素的類型和 display 屬性,決定了這個 Box 的類型。 不一樣類型的 Box, 會參與不一樣的 Formatting Context(決定如何渲染文檔的格式結構),所以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;

而Formatting Context是一塊渲染區域,它決定了其子元素如何定位,以及與其餘元素的位置關係。

根據上述的一些基本概念,我把BFC簡單理解成一種屬性,在具備BFC屬性的容器中,元素按照BFC的規則實現佈局。好比浮動元素會造成BFC,這就是爲何咱們看到浮動元素佈局跟普通文檔流下的佈局有所差異的緣由。

BFC的規則

  • 內部的Box會在垂直方向,一個接一個地放置。

  • Box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰Box的margin會發生重疊

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

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

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

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

哪些元素會造成BFC

  • 根元素

  • float屬性不爲none

  • position爲absolute或fixed

  • display爲inline-block, table-cell, table-caption, flex, inline-flex

  • overflow不爲visible
     

BFC在佈局中的做用

  • 解決兩元素margin重疊的問題

    要想兩個相鄰的元素不發生垂直方向上的margin重疊,須要將他們兩定義在不一樣的BFC中。解決方法即在其中一個元素外包裹一層元素,再對那層包裹的元素進行BFC觸發。(這裏能夠加入上述的css屬性。)

  • 解決因爲浮動形成的重疊問題

    通常狀況下,浮動元素會脫離文檔流,即不佔位置。它的兄弟元素會與它在左上角重疊。可是若是兩個相鄰元素都設置了浮動,那麼意味着它們都是以BFC的規則渲染,根據上述第四條規則,BFC區域不會相互重疊,因此便能理解爲何設置浮動後元素能獨佔空間了。

  • 解決容器因爲擁有浮動元素形成高度塌陷的問題

    在普通容器中,若是裏面有浮動元素,在不設置高度的狀況下,容器是不能被撐起來的,這時候經過設置overflow:hidden把其變爲BFC,那麼就能夠包含浮動元素了。


BFC的說明到此就告一段落了,如今回到最初討論的haslayout的問題。ie7及如下ie版本不支持BFC的,但有私有屬性haslayout,因而咱們能夠經過觸發元素的haslayout來達成bfc的類似效果。

IE下由於haslayout致使的bug

一、浮動元素與普通元素之間產生3px bug

//代碼以下
<style>
.test {width: 800px;margin: 10px auto;border: 1px solid brown;height: 30px;}
.float {float: left;background: saddlebrown;color: #fff;}
}
</style>

<div class="test">
    <div class="float">我是浮動元素</div>我是後面的文字,用來測試3px的bug
</div>

正常狀況:
clipboard.png

ie6下:
clipboard.png

解決方式:加一個ie6的hack:*margin-right:-3px;

不僅是文字,ie6的浮動元素也會和內聯元素產生3px的margin值。

正常狀況:
clipboard.png

ie6,7下:
clipboard.png

解決方式同上。

二、塊級元素與浮動元素不會重疊

<style>
    .test {width: 800px;margin: 10px auto;border: 1px solid brown;height: 30px;}
    .float {float: left;background: saddlebrown;color: #fff;}
    }
   </style>

    <div class="test">
        <div class="float">我是浮動元素</div>
        <div style="background: #0079F5;height: 30px;">我是浮動元素後面的塊級元素</div>
    </div>

正常狀況:
clipboard.png

ie6,7:
clipboard.png

能夠明顯地發現ie6,7下塊級元素跟浮動元素不能重疊。爲何會發生這種狀況呢?是由於我在塊級元素上設置了高度。激活了ie下的haslayout屬性。因而ie6把它以BFC相似的方式進行渲染。

解決方式:在塊級元素外再包裹一層DIV。而且把內部DIVbackground的屬性寫在外層DIV上。

三、浮動閉合元素
這個問題其實不少人會遇到,上文也提到過,只是可能叫法不一樣。

<style>
.test {width: 800px;margin: 10px auto;border: 1px solid brown;}
.float {float: left;background: saddlebrown;color: #fff;}
</style>

<div class="test">
    <div class="float">我浮動啦!</div>
</div>

正常狀況:
clipboard.png
注意那一條橫線是.test的border,由於浮動元素脫離了文檔流,故.test不能被撐起來。

ie6,7
clipboard.png

ie彷佛妥妥的。其實不少狀況下,咱們想要的是ie這種效果。在ie中,一個浮動元素老是隸屬於包含它的容器。是由於.test設置了寬度,激活了haslayout屬性。而在非ie瀏覽器中,咱們想要得到這種效果通常是在父盒子上加一個:after的僞對象來清除浮動,或者設置overflow:hidden來觸發BFC。

插入提一下閉合浮動的廣泛作法:
爲須要閉合浮動的父元素加入clearfix的類。

.clearfix::after {content:"";display:block;height:0;clear:both;}
.clearfix {zoom: 1;} //兼容ie6,7

四、ie下margin不塌陷

<style>
.test {width: 800px;margin: 10px auto;}
.float {float: left;background: saddlebrown;color: #fff;}
</style>

<div class="test">
    <div class="float">我浮動啦!</div>
    <div style="margin-top:30px;">測試margin-top在ie下是否塌陷</div>
</div>

正常狀況:
clipboard.png

ie6,7
clipboard.png

float是浮動元素,她脫離了文檔流,因此第二個DIV的margin-top相對的是其上級.test做用的。但咱們只是對第二個DIV設置margin-top。結果在chrome下,怎麼連float也「產生了margin-top」呢。對比ie和chrome下的效果,是否是以爲IE下的 解析會比較合理呢?

可是。別忘了影響margin-top/bottom的一個重要規則——margin塌陷(margin collapsing)。

提到了margin塌陷,咱們來看看margin垂直方向上塌陷的一些條件: 

  • 水平margin不會合並。

  • 兩個上下渲染相鄰(不必定是兄弟節點)的塊狀元素在正常頁面流狀況下會發生 margin 合併。

  • 浮動元素不會和任何元素(包括子孫節點)發生 margin 合併。

  • overflow!=visible的元素不和任何元素髮生margin合併。

  • 絕對定位的元素不和任何元素髮生margin合併。

  • inline-block 的元素不和任何元素髮生margin合併。

  • 設置 clear 屬性的元素不和任何元素髮生margin合併。

  • 根元素不和任何元素髮生margin合併。

  • 父節點和第一個子節點發生margin-top合併。

  • 若是最後一個子節點沒有border以及padding,則和其父節點發生margin-bottom合併。

注意低版本IE下特別是hasLayout對於margin合併也有影響,從而也形成了包含的絕對定位元素的位置差別。

在現代瀏覽器下.test塊的高度並無被子元素第二個DIV的margin-top撐開。反而自身擁有了30px的margin-top
而浮動塊儘管脫離了文檔流,但仍是受其父級限制的(這跟absolute定位的元素層受限於其定義爲relative的父級同樣)。因此float仍是包含在test之中,這樣在chrome下看起來浮動塊也擁有margin-top,而事實上是由於test高度不撐開的結果。

這麼說,chrome並無錯咯,那麼IE下又是怎麼避開margin塌陷的呢?問題就出在浮動上面,在ie下,元素浮動將觸發其haslayout。就是這個緣由,使得在ie下意外(意外?)的就避開了margin塌陷。

可是奇怪的是,若是給.test加上border,chrome的渲染狀況就跟ie同樣了,float沒有擁有與第二個DIV相同的margin-top值。而是緊貼.test的頂部。以下圖:

chrome:
clipboard.png

ie6,7:
clipboard.png

這個問題的緣由還須要研究一下。。。。若是有知道緣由的大神麻煩給留個言,,感激!

五、ie下margin-left/right失效

<style>
.test {margin: 10px auto;border:1px solid darkred;}
</style>

<div class="test">
    <div style="height:30px;margin:0 20px;border-bottom: 3px solid sandybrown;">測試失效的margin-left</div>
</div>

正常狀況:
clipboard.png

ie6:
clipboard.png

根據上圖能夠發現,ie下咱們爲子DIV設置的margin失效了。爲何會發生這種狀況,一樣是是由於子DIV設置了高度,激活了haslayout。

解決辦法:不爲子DIV設置高度,或者把父盒子的haslayout也激活。

參考資料:
http://cssass.com/blog/2009/147.html
http://www.cnblogs.com/lhb25/p/inside-block-formatting-ontext.html
http://www.cnblogs.com/pigtail/archive/2013/01/23/2871627.html

原文連接:
http://www.cnblogs.com/Remix/articles/4777257.html

相關文章
相關標籤/搜索