IE Layout詳解

 在web前端面試的時候常常會被問及IE的hasLayout問題,有些書籍講解的不是很清楚(害死人了),在網絡上收集一些資料,我認爲比較好的有下面兩篇。

     淘寶KongXin的IE Layout詳解(http://www.kongxin.info/archives/75.html);吾心飛揚的IE之hasLayout(http://hi.baidu.com/daijun2007/blog/item/f36de54b8be240fe83025c49.html)。兩篇文章拷貝如下:

  

   

IE layout詳解

四 12th, 2010

在初學css的時候,很鬱悶的發現同樣的代碼在IE裏和其他的瀏覽器裏表現的判若兩人,很是惱火,費解,調整費時費力,後來才知道IE有一個單獨的屬性:layout,這篇文章仔細的分析一下IE layout,以求能更加深入的瞭解一下,參考文章:http://www.satzansatz.de/cssd/onhavinglayout.html#toc,同時還借鑑了不一樣的蚊子的這篇翻譯IE Haslayout詳解,其中沒有翻譯完,我再完整一下:

引言:

Internet Explorer 中有很多奇怪的渲染問題可以給他一個”layout”得到解決,John Gallant 和 Holly Bergevin把他歸類爲“dimensional bugs”(尺寸bug或者尺寸臭蟲),意思是可以給對應的元素賦予寬度和高度解決;這給我們帶來了一個問題:爲什麼layout可以改變渲染模式和元素之間的關係?

hasLayout定義:

layout是IE/WIN裏面的私有概念,它決定了一個元素如何顯示以及約束其包含的內容、如何和其他元素進行相互作用和聯繫、如何響應和傳遞應用程序事件、用戶事件等;

layout的特性可以被某些css樣式屬性不可扭轉的觸發,一些html元素本身擁有layout缺省(默認)屬性;

Microsoft的開發者們決定一些元素應該獲得一個“屬性”(在面向對象的編程裏),他們用了“hasLayout”屬性,當渲染特性生效時,他的值被設置成true;

當Microsoft的私有屬性hasLayout被設置成true時,我們說這個元素獲得了佈局(layout)或者說這個元素擁有了佈局(layout),佈局元素可以是他們中的任何之一,如果那些元素擁有默認的 layout佈局或者通過設置合適的css屬性使其獲得佈局(layout);

在非佈局元素(non-layout)中,hasLayout不會被觸發,比如說一個沒有設置寬度和高度(沒有尺寸定義)的div,他是所有非佈局元素的祖宗;

給一個默認沒有 layout 的元素賦予 layout 的方法包括設置可觸發 hasLayout = true 的 CSS 屬性。參考默認 layout 元素以及這些屬性列表。沒有辦法設置 hasLayout = false , 除非把一開始那些觸發 hasLayout = true 的 CSS 屬性刪除或重置。

我們遇到的問題:

hasLayout問題,影響那些有經驗的設計師和代碼人員,layout有許多不同尋常且難以預料的作用在盒子模型的展示,甚至有時會牽連他們的後代元素;

一個元素有或者沒有“layout”會引發下列問題:

  1. 許多平常的IE浮動(float)bug;
  2. 元素本身對一些基本屬性的異常處理問題;
  3. 容器和他的後代之間的外邊距重疊(被隨壞)問題;
  4. 各種各樣的列表問題;
  5. 背景圖像的定位偏差問題。
  6. 使用腳本時遇到的瀏覽器之間處理不一致的問題。

以上所列只是一個摘要和不完整的;

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專有屬性。
  • overflow: hidden|scroll|auto
    在 IE7 中,overflow 也變成了一個 layout 觸發器,這個屬性在之前版本 IE 中沒有觸發 layout 的功能,除非這個元素被其他情況觸發添加到了一個盒子中;
  • overflow-x|-y: hidden|scroll|auto
    overflow-x 和 overflow-y 是 CSS3 盒模型中的屬性,尚未得到瀏覽器的廣泛支持。他們在之前版本IE中沒有觸發 layout 的功能。
  • 另外 IE7 的熒幕上又新添了幾個 haslayout 的演員,如果只從 hasLayout 這個方面考慮,min/max 和 width/height 的表現類似,position 的 fixed 和 absolute 也是一模一樣。
  • position: fixed
  • min-width: 任意值
    就算設爲0也可以讓該元素獲得 layout。
  • max-width: 除 “none” 之外的任意值
  • min-height: 任意值
    即使設爲0也可以讓該元素的 haslayout=true
  • max-height: 除 “none” 之外的任意值

有關內聯元素:

對於內聯元素(可以是默認即爲內聯的比如 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。

重置HasLayout:

如果沒有其他屬性再添加 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)

使用者必須小心使用這些重置屬性。

display 屬性的不同:當用”inline-block”設置了 haslayout = true 時,就算在一條獨立的規則中覆蓋這個屬性爲”block”或”inline”,haslayout 這個標誌也不會被重置爲 false。

把 mid-width, mid-height 設爲它們的默認值”0″仍然會賦予 hasLayout,但是 IE 7 卻可以接受一個不合法的屬性”auto”來重置 hasLayout。

hasLayout腳本屬性:

我們已經選擇參考把“hasLayout”屬性作爲一個腳本屬性,以便把他與我們熟悉的CSS屬性區分開來;

並沒有方法可以直接設置或者重置hasLayout屬性;

hasLayout屬性可以用來檢查該元素是否有layout,例如它有一個ID=“eid”,然後可以直接在IE5.5地址欄裏敲:

javascript: alert(eid.currentStyle.hasLayout)

這樣就可以檢測出它的狀態;

IE的Developer Toolbar允許你動態的檢查當前元素的樣式,當hasLayout的值爲“true”時,它的值被呈現爲“-1”,例如,如果你想編輯一個節點的屬性的時候,你可以CSS的“zoom”屬性爲“1”(zoom=1),這樣可以觸發那個hasLayout屬性,以便dubug它;

另一件需要考慮的是:layout怎麼作用和影響腳本(script),例如:那些沒有layout特性的元素的 clientWidth/clientHeight屬性總是返回0,這對於新手來說是難以理解並且是莫名其妙的,並且它和 Mozilla(firefox)瀏覽器的作用有很大出入,我們能利用這個事實來爲IE5.0做決定,就像這樣,如果那個clientWidth是0,那麼我們說這個元素沒有layout;

CSS Hacks

在IE7和它以前的版本里,下面的這些hack已經得到了驗證:

John Gallant 和 Holly Bergevin在2003年發佈了這個Holly hack


* html .gainlayout { height: 1%; }

  • 除了IE6下的標準模式裏的行內元素,在IE5-6的所有版本里,這個hack都會觸發所有元素的layout;
  • 除了某些極稀少的height:0或者1px,它通常工作的很好;
  • 除了在IE6的標準模式下(height:1%轉化爲height:auto,除非它的父元素有一個明確的高度),其他都與overflow:hidden是不相容的;
  • 在IE7的標準模式下*html不會選擇任何一個元素,它是沒有任何效果的;

給IE6以及它以下的版本layout,也可以用這個underscore hack:

.gainlayout { _height: 0; }

並且爲了給IE7layout,我們可以用min-hight屬性:

.gainlayout { min-height: 0; }

二者選一的,這是比較有效的功能,就是conditional comments:

<!–[if lte IE 6]>
<style>
.gainlayout { height: 1px; }
</style>
<![endif]–>

在外部樣式表引入之時,插入一條受限制的註釋,是比較簡潔和可靠的解決辦法:

<link rel=”stylesheet” href=”allbrowsers.css” type=”text/css” />

<!–[if lte IE 7]>
<link rel=”stylesheet” href=”iefix.css” type=”text/css” />
<![endif]–>

給IE6及他以下的版本設定高度總是被用到的,除非他和某些特性衝突(overflow:hidden);那些1%,1px或者0基本上都是相等的,但是那個1%有時候會出現一些問題(即使極少碰到);

在標準模式下給元素設定高度是不可用的,在IE7裏應該儘可能避免(或者小心的使用:兩個條件:<1>只能是百分值<2>其父元素必須沒有確定的高度),鑑於這些原因,我們喜歡用:dispaly:inline-block或者zoom:1;

我們已經對那些浮動(float)元素試驗了“holy”hacks,或者那些已經擁有寬度(width)的元素,記住這個目標就是:不能運用這些hacks在擁有height的元素上,因爲這樣會觸發hasLayout=ture;

不要對所有的元素這樣:

* {_height: 1px;}

這樣是不合適的,因爲它不僅僅讓擁有layout的沒有變好,反而改變了那些基本元素的渲染和展示;

hack管理(management):

儘管IE7已經發布了,但是我們仍然不能預見將來的IE版本是否繼續需要hasLayout來修復bug和他們是怎麼相互作用的,所以用MS的私有屬性zoom或者有田間的條件註釋是明智的:

<!–[if lt IE 7]><style>

.gainlayout { height: 0; }
</style><![endif]–>

<!–[if IE 7]><style>
.gainlayout { zoom: 1; }
</style><![endif]–>

  • zoom:1,它給IE5.5以上的所有版本里的任何元素layout(包括行內元素),但是這個規則在IE5.0裏沒有效果;
  • 未知的副作用(儘管行內元素表現的像行內塊元素);
  • 如果一定要確定,zoom一定要被有條件的註釋隱藏;

如果想得到一個更詳盡的hasLayout觸發和hasLayout在不同的IE版本里的比較的話,請參考這裏:Thoughts on IE hack management.

IE Mac簡短介紹:

IE Mac和IE for Windows是十分不同的,每一種都有自己的渲染引擎,IE Mac用任何方式都不知道hasLayout的行爲,IE Mac渲染引擎是在向標準遵循模式靠近;

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章