標籤:
一、BFC(Block Formatting Context)
相關網址:http://www.cnblogs.com/dolphinX/p/3508869.html
1. 怎樣才能形成BFC
- float的值不為none。
- overflow的值不為visible。
- display的值為table-cell, table-caption, inline-block中的任何一個。
- position的值不為relative和static。
2.BFC的作用
不和浮動元素重疊
如果一個浮動元素後面跟著一個非浮動的元素,那麼就會產生一個覆蓋的現象,很多自適應的兩欄布局就是這麼做的。
清除元素內部浮動
只要把父元素設為BFC就可以清理子項目的浮動了,最常見的用法就是在父元素上設定overflow: hidden樣式,對於IE6加上zoom:1就可以了(IE Haslayout)。
嵌套元素Margin邊距摺疊問題的解決
按照BFC的定義,只有同屬於一個BFC時,兩個元素才有可能發生垂直Margin的重疊,這個包括相鄰元素,嵌套元素,只要他們之間沒有阻擋(例如邊框,非空內容,padding等)就會發生margin重疊。
因此要解決margin重疊問題,只要讓它們不在同一個BFC就行了,但是對於兩個相鄰元素來說,意義不大,沒有必要給它們加個外殼,但是對於嵌套元素來說就很有必要了,只要把父元素設為BFC就可以了。這樣子項目的margin就不會和父元素的margin發生重疊了。
二、IE HasLayout
1. hasLayout概述
“Layout”是一個 Internet Explorer for Windows的私人概念,它決定了一個元素如何顯示以及約束其包含的內容、如何與其他元素互動和建立聯絡、如何響應和傳遞應用程式事件、使用者事件等。這種渲染特性可以通過某些 CSS 屬性被無法復原轉地觸發。而有些 HTML 元素則預設就具有”layout”。
微軟的開發人員們認為元素都應該可以擁有一個”屬性(property)”(這是物件導向編程中的一個概念),於是他們便使用了 hasLayout,這種渲染特性生效時也就是將 hasLayout 設成了 true 之時。瞭解hasLayout將對IE的臭蟲會有更多深入的體會甚至解決方案。
2. HasLayout定義
一個元素”得到 layout”,或者說一個元素”擁有 layout” 的時候,是指它的微軟專有屬性 hasLayout 為此被設為了 true 。一個”layout元素”可以是一個預設就擁有 layout 的元素或者是一個通過設定某些 CSS 屬性得到 layout 的元素。
而”無layout元素”,是指 hasLayout 未被觸發的元素,比如一個未設定寬高尺寸的乾淨 div 元素就可以做為一個”無layout祖先”。
給一個預設沒有 layout 的元素賦予 layout 的方法包括設定可觸發 hasLayout = true 的 CSS 屬性。參考預設 layout 元素以及這些屬性列表。沒有辦法設定 hasLayout = false , 除非把一開始那些觸發 hasLayout = true 的 CSS 屬性去除或重設。
3. Layout的由來
不同於標準屬性,也不像某些瀏覽器的私人 CSS 屬性,layout 無法通過某一個 CSS 聲明直接設定 。也就是說沒有”layout屬性”這麼一個東西,元素要麼本身自動擁有 layout,要麼藉助一些 CSS 聲明悄悄地獲得 layout。
下列元素應該是預設具有 layout 的:
- <html>, <body>
- <table>, <tr>, <th>, <td>
- <img>
- <hr>
- <input>, <button>, <select>, <textarea>, <fieldset>, <legend>
- <iframe>, <embed>, <object>, <applet>
- <marquee>
下列 CSS 屬性和取值將會讓一個元素獲得 layout:
- position: absolute
絕對位置元素的包含區塊(containing block)就會經常在這一方面出問題。
- float: left|right
由於 layout 元素的特性,浮動模型會有很多怪異的表現。
- display: inline-block
當一個內聯層級的元素需要 layout 的時候往往就要用到它,這也可能也是這個 CSS 屬性的唯一效果–讓某個元素擁有 layout。”inline-block行為”在IE中是可以實現的,但是非常與眾不同: IE/Win: inline-block and hasLayout 。
- width: 除 “auto” 外的任意值
很多人遇到 layout 相關問題發生時,一般都會先嘗試用這個來修複。
- height: 除 “auto” 外的任意值
height: 1% 就在 Holly Hack 中用到。
- zoom: 除 “normal” 外的任意值
IE專有屬性。不過 zoom: 1 可以臨時用做調試。
- writing-mode: tb-rl
MS專有屬性。
IE7中引入的hasLayout成員
-
- overflow: hidden|scroll|auto
在 IE7 中,overflow 也變成了一個 layout 觸發器,這個屬性在之前版本 IE 中沒有觸發 layout 的功能。
- position: fixed
- min-width: 任意值
就算設為0也可以讓該元素獲得 layout。
- max-width: 除 “none” 之外的任意值
- min-height: 任意值
即使設為0也可以讓該元素的 haslayout=true
- max-height: 除 “none” 之外的任意值
4. 有關內聯層級元素
對於內嵌元素(可以是預設即為內聯的比如 span 元素,也可以是 display: inline 的元素)
- width 和 height 只在 IE5.x 下和 IE6 或更新版本的 quirks 模式下觸發 hasLayout 。而對於 IE6,如果瀏覽器運行於標準相容模式下,內嵌元素會忽略 width 或 height 屬性,所以設定 width 或 height 不能在此種情況下令該元素具有 layout。
- zoom 總是可以觸發 hasLayout,但是在 IE5.0 中不支援。
具有”layout” 的元素如果同時也 display: inline ,那麼它的行為就和標準中所說的 inline-block 很類似了:在段落中和普通文字一樣在水平方向和連續排列,受 vertical-align 影響,並且大小可以根據內容自適應調整。這也可以解釋為什麼單單在 IE/Win 中內嵌元素可以包含區塊層級元素而少出問題,因為在別的瀏覽器中 display: inline 就是內聯,不像 IE/Win 一旦內嵌元素擁有 layout 還會變成 inline-block。
5. 重設 hasLayout
沒有辦法設定 hasLayout = false, 除非把一開始那些觸發hasLayout = true的CSS屬性去除。
display 屬性的不同:當用”inline-block”設定了 haslayout = true 時,就算在一條獨立的規則中覆蓋這個屬性為”block”或”inline”,haslayout 這個標誌位也不會被重設為 false。
6. CSS hacks,如何觸發hasLayout
比較常用的是zoom: 1,這是微軟的專有屬性,可以在IE6,IE7上工作,無附作用,唯一的缺點是無法通過W3C的語法驗證。所以調試的時候可以先加zoom:1試試看問題是否是hasLayout的問題,如果是換成其它對應的屬性。
最常用的就是Holly Hack,簡單點講就是添加height: 1%。如果它的父元素不能定高,這種方法就會自動轉換為height: auto,但是hasLayout被觸發了。優點就是這是標準的屬性,可以通過W3C驗證。
還有一種也經常用到的就是height: 0或者height: 1px,但是這種方法只能用在IE6上面,因為IE6以及更低的版本會把height作為min-heigth那樣對待,所以把height設得很小對於顯示沒有任何影響。這種方法不能和overflow:hidden同時使用。
7. HasLayout的影響及作用清除浮動
效果同BFC,就是自動清除它的浮動的直接子項目。
對於IE6和IE7,我發現即使浮動元素的父元素沒有hasLayout,父元素的高度也是有的,可以通過js輸出或者IEDeveloper查看,但是在IE8和其它瀏覽器裡是沒有高度的(值為0)。但是實際效果卻是沒有清除浮動的效果,即該父元素的實際高度為0,只要在後面跟個元素就可以看出來了,後面的元素會和前面的元素重疊。這點讓我迷惑好大一會。
不和浮動元素重疊
效果同BFC。
列表
無論是列表本身(ol, ul) 還是單個的列表元素(li),擁有 layout 後都會影響列表的表現。不同版本 IE 的表現又有不同。最明顯的效果就體現在列表符號上(如果你的列表自訂了列表符號則不會受這個問題影響)。這些符號很可能是通過某種內部機制附到列表元素 上的(通常是附著在它們外面)。不幸的是,由於是通過“內部機制”添加的,我們無法訪問它們也無法修正它們的錯誤表現。
相對定位元素(r.p.)
注意,由於 position: relative 並不觸發 hasLayout,所以很多諸如內容消失或錯位的渲染錯誤就會因此而起。這些現象可能會在重新整理頁面、調整視窗大小、滾動頁面、選中內容等情況下出現。原 因是 IE 在據這個屬性對元素做位移處理時,卻似乎忘了發出訊號讓其 layout 孩子項目進行“重繪”(而如果是一個layout元素,那麼在其重繪事件的訊號鏈中,這個傳給其孩子的訊號是會正常發出的)。所以調試的時候可以嘗試給相對定位元素觸發它的hasLayout。
濾鏡
MS專有的濾鏡屬性 filter 是只適用於 layout 元素的。比如透明效果。
背景原點
MS專有的這個 hasLayout 還會影響背景的定位和擴充。比如,根據 CSS 規範,background-position : 0 0 應該指元素的“補白邊緣(padding edge)”。而在 IE/Win 下,如果 hasLayout = false 則指的是“邊框邊緣(border edge)”,當 hasLayout=true 時指的才是補白邊緣:
嵌套元素邊距摺疊問題的解決
同BFC
相對容器中的絕對位置(主要是IE6)
對於絕對位置元素,包含區塊是由其最近的定位祖先決定的。如果其祖先都沒有被定位,那麼就使用初始包含區塊 html。
通常情況下我們會用 position: relative 來設定任意包含區塊。這就是說,我們可以讓一個絕對位置元素所參考的原點和長度等不依賴於元素的排列順序,這可以滿足諸如“內容優先”這種可訪問性概念的需要,也可以給複雜的浮動布局帶來方便。
但是由於 layout 概念的存在,這種設計理念的效果在IE中就要打個問號了:因為在IE中絕對位置只有當其包含元素擁有 layout 時才會計算正確,而且絕對位置元素的百分比寬度參考也搞錯了對象。這裡 IE5 和 IE6 的行為不同但都有問題。IE7b2 的行為就要好很多,雖然有些小地方還是有錯誤。總之儘可能的讓絕對元素的包含區塊擁有 layout,而且盡量讓其就是絕對位置元素的父級元素(也就是說這個包換元素和絕對位置元素之間沒有絕對位置元素的別的祖先了)。
塊層級的連結
hasLayout 會影響一個塊層級連結的滑鼠響應地區(可點擊地區)。通常 hasLayout = false 時只有文字覆蓋地區才能響應。而 hasLayout = true 則整個塊狀地區都可響應。添加了 onclick/onmouseover 等事件的任意區塊層級元素也有同樣的現象。我沒能重現這個問題。
邊緣裁切
通常而言,當一個盒子包含了諸如伸出其邊緣的內容這種更複雜的結構時,這個容器就經常需要“hasLayout”來避免一些渲染錯誤。但使用這種常用方法又會在邊界處理時左右為難,因為一個獲得“layout”的元素會變成某種自封閉的盒子。內部的內容盒子會被裁切,比如使用負邊距向外移動時。
被裁掉的部分當內容盒子觸發了“layout”時可以再次出現,但在 IE6 中需要同時擁有 position: relative 才行。IE7 在這方面要略有改觀,它不再需要額外的 position: relative 了。
案例分析1. 清除浮動
最原始的用法<div style="clear: both"></div>,這種用法的缺點是添加了無意義的空白標籤。
overflow: hidden, 這也是經常使用的一種方式,但事實它的原理就是對於非IE6和IE7瀏覽器來說產生了BFC,對於IE7瀏覽器來說是產生了hasLayout。但是這種方式的缺點就是如果子項目超出父元素的範圍會被截取。對於IE6無效,可以用zoom:1。我剛學CSS的時候一直很好奇為什麼overflow:hidden可以清理浮動。
現在最流行也最無害的一種方式就是:
.clearfix:after { content: " "; display: block; clear: both; height: 0; } .clearfix { *height: 1%; }
程式碼分析:對於非IE6和IE7等支援:after的瀏覽器來說,在內容的最後面添加了一個空白元素,然後把它隱藏掉,同時添加clear: both屬性,達到清理浮動的目的,對於不支援:after的瀏覽器來說(主要就是IE6和IE7),設定height: 1%可以觸發hasLayout從而達到清理浮動的目的。
2. 水平兩欄自適應排版
見BFC不和浮動元素重疊那一節。就是第一個元素是浮動,第二個元素要觸發BFC或者hasLayout來避免被浮動元素覆蓋
.second-item { overflow: hidden; *zoom: 1;//IE6 } 跨瀏覽器的inline-block
對於支援inline-block的瀏覽器來說,display: inline-block就可以了,對於不支援的瀏覽器(IE6和IE7)來說,實現方法是將元素設定成display: inline,同時觸發它的hasLayout就可以了。
#item { display: inline-block; } #item { *display: inline; }
這個地方需要注意的是這兩條一定要分開寫,不能放在同一個選取器中,否則hasLayout就會被取消,那樣的話就需要zoom:1,所以如果非要寫在一起的話,代碼如下:
#item { display: inline-block; *display: inline; *zoom: 1; }
事實上,在IE中,只要是觸發了BFC的都可以設定寬高,如果是內嵌元素則就是inline-block的效果了,而擁有了BFC的元素則都可以設定寬高,除了overflow:hidden;
CSS BFC和IE Haslayout