CSS BFC和IE Haslayout介紹

BFC(Block Formatting Context)

1. BFC的定義

是 W3C CSS 2.1 規範中的一個概念,它決定了元素如何對其內容進行定位,以及與其餘元素的關係和相互做用。 html

在建立了 Block Formatting Context 的元素中,其子元素會一個接一個地放置。垂直方向上他們的起點是一個包含塊的頂部,兩個相鄰的元素之間的垂直距離取決於 ‘margin’ 特性。在 Block Formatting Context 中相鄰的塊級元素的垂直邊距會摺疊(collapse)。 編程

在 Block Formatting Context 中,每個元素左外邊與包含塊的左邊相接觸(對於從右到左的格式化,右外邊接觸右邊), 即便存在浮動也是如此(儘管一個元素的內容區域會因爲浮動而壓縮),除非這個元素也建立了一個新的 Block Formatting Context 。 瀏覽器

從上面的定義咱們能夠看到Document顯示HTML元素的方式和BFC的定義很像,其實咱們能夠認爲Document就是最大的一個擁有BFC的元素了。 app

2. BFC究竟是什麼?

當涉及到可視化佈局的時候,Block Formatting Context提供了一個環境,HTML元素在這個環境中按照必定規則進行佈局。一個環境中的元素不會影響到其它環境中的佈局。好比浮動元素會造成BFC,浮動元素內部子元素的主要受該浮動元素影響,兩個浮動元素之間是互不影響的。這裏有點相似一個BFC就是一個獨立的行政單位的意思。一個大的行政單位能夠包含若干個小的行政單位。 佈局

3. 怎樣才能造成BFC

  • float的值不爲none。
  • overflow的值不爲visible。
  • display的值爲table-cell, table-caption, inline-block中的任何一個。
  • position的值不爲relative和static。

4. BFC的做用

不和浮動元素重疊

若是一個浮動元素後面跟着一個非浮動的元素,那麼就會產生一個覆蓋的現象,不少自適應的兩欄佈局就是這麼作的。好比下圖的效果,參考例子 ui

<div style="float:left; border: 2px solid red"> 123</div>
               <span style="border: 2px solid blue;display:block;overflow:hidden;*zoom:1">
               The quick brown fox jumped over the lazy dog's back.
               The quick brown fox jumped over the lazy dog's back.
               The quick brown fox jumped over the lazy dog's back.
               The quick brown fox jumped over the lazy dog's back.
               The quick brown fox jumped over the lazy dog's back.
              </span>

清除元素內部浮動

只要把父元素設爲BFC就能夠清理子元素的浮動了,最多見的用法就是在父元素上設置overflow: hidden樣式,對於IE6加上zoom:1就能夠了(IE Haslayout)。 spa

3.嵌套元素Margin邊距摺疊問題的解決

按照BFC的定義,只有同屬於一個BFC時,兩個元素纔有可能發生垂直Margin的重疊,這個包括相鄰元素,嵌套元素,只要他們之間沒有阻擋(例如邊框,非空內容,padding等)就會發生margin重疊。 .net

所以要解決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;



相關文章
相關標籤/搜索