CSS學習:On having layout

來源:互聯網
上載者:User
css

英文原文在此:
http://www.satzansatz.de/cssd/onhavinglayout.htm

文中所有的 layout 這個單詞都未作翻譯,一來本身這個單詞意思就比較多,翻成啥都覺得彆扭,二來它也是專有的屬性,所以就意會一下吧。水平有限,很多地方都是模模糊糊地意譯,發現錯誤歡迎留言指出。

引用一段來自Dean Edwards的評價:
I recommend that every CSS designer and DOM scripter read this. Understanding “layout” gives a huge insight into lots of other IE bugs and idiosyncrasies.
(Dean Edwards)

4月16日修訂的內容:
將quirks模式這一部分單獨移動到一篇文章中講述。
添加:邊緣裁切。
添加:收縮包圍(shrink-wrapping)現象。

5月17日修訂的內容:
重寫了了浮動元素旁邊的元素這一部分。
部分章節小的修正:屬性,有關內聯層級元素,CSS hacks。
重新整理了部分章節的語言:定義,資料,問題種種,分析,清除浮動和自動擴充適應高度,絕對位置元素。

On having layout

本文修訂中
目前的版本:Rev. 7 2006–05–17
修訂曆史
各種語言版本
目錄

介紹

Internet Explorer 中有很多奇怪的渲染問題可以通過賦予其“layout”得到解決。John Gallant 和 Holly Bergevin 把這些問題歸類為“尺寸bug(dimensional bugs)”,意思是這些 bug 可以通過賦予相應元素某個寬度或高度解決。這便引出關於“layout”的一個問題:為什麼它會改變元素的渲染特性,為什麼它會影響到元素之間的關係?這個問題問得很好,但卻很難回答。在這篇文章中,我們專註於這個複雜問題會有那些方面的表現,某一方面的具體討論和範例請參考文中給出的相關連結。

hasLayout — 定義

“Layout”是一個 IE/Win 的私人概念,它決定了一個元素如何顯示以及約束其包含的內容、如何與其他元素互動和建立聯絡、如何響應和傳遞應用程式事件/使用者事件等。
這種渲染特性可以通過某些 CSS 屬性被無法復原轉地觸發。而有些 HTML 元素則預設就具有“layout”。
微軟的開發人員們認為元素都應該可以擁有一個“屬性(property)”(這是物件導向編程中的一個概念),於是他們便使用了 hasLayout,這種渲染特性生效時也就是將 hasLayout 設成了 true 之時。
術語
當我們說一個元素“得到 layout”,或者說一個元素“擁有 layout” 的時候,我們的意思是指它的微軟專有屬性 hasLayout  為此被設為了 true 。一個“layout元素”可以是一個預設就擁有 layout 的元素或者是一個通過設定某些 CSS 屬性得到 layout 的元素。
而“無layout元素”,是指 hasLayout 未被觸發的元素,比如一個未設定寬高尺寸的乾淨 div 元素就可以做為一個“無layout祖先”。
給一個預設沒有 layout 的元素賦予 layout 的方法包括設定可觸發 hasLayout = true 的 CSS 屬性。參考預設 layout 元素以及這些屬性列表。沒有辦法設定 hasLayout = false , 除非把一開始那些觸發 hasLayout = true 的 CSS 屬性去除。

問題種種

hasLayout 的問題不管新手還是老手,不管設計師或者程式員可能都遇到過。Layout 在顯示盒子時有著不同尋常而且難以預料的效果,而且有時甚至會牽連到他們的孩子項目。
一個元素是否具有“layout”可能會引發如下的一些問題:
IE 很多常見的浮動 bug 。
元素本身對一些基本屬性的異常處理問題。
容器和其子孫之間的邊距重疊(margin collapsing)問題。
使用列表時遇到的諸多問題。
背景映像的定位偏差問題。
使用指令碼時遇到的瀏覽器之間處理不一致的問題。

上面的列表只是列出一個大概,也不完善。下面的文章將儘可能詳細徹底的描述有無“layout”所帶來的各種問題。

Layout 從何而來

不同於標準屬性,也不像某些瀏覽器的私人 CSS 屬性,layout 無法通過某一個 CSS 聲明直接設定 。也就是說沒有“layout屬性”這麼一個東西,元素要麼本身自動擁有 layout,要麼藉助一些 CSS 聲明悄悄地獲得 layout。
預設layout元素
下列元素應該是預設具有 layout 的:
<html>, <body> <table>, <tr>, <th>, <td> <img> <hr> <input>, <select>, <textarea>, <button> <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” 外的任意值 (MSDN)
MS專有屬性,無法通過校正。 不過 zoom: 1 可以臨時用做調試。
writing-mode: tb-rl (MSDN)
MS專有屬性,無法通過校正。

·在 IE7 中,overflow 也變成了一個 layout 觸發器:

overflow: hidden|scroll|auto
這個屬性在之前版本 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” 之外的任意值
./.

以上結論藉助 IE Developer Toobar 以及預先測試得出。

有關內聯層級元素

對於內嵌元素(可以是預設即為內聯的比如 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 為“指令碼屬性”是為了和我們熟知的 CSS 屬性相區別。

注意一旦一個元素擁有了 layout,就沒有辦法再將其設成 hasLayout = False 了。

hasLayout-property 可以用來檢測一個元素是否擁有 layout:舉個例子,如果它的 id 是“eid”,那麼只要在

IE5.5+ 的地址欄裡輸入 javascript: alert(eid.currentStyle.hasLayout) 即可檢測它的狀態。
IE的 Developer Toolbar 可以即時檢查一個元素的當前樣式;如果 hasLayout 是 true ,那麼它的值顯示為 “-1”。 我們可以通過即時修改一個元素的屬性將“zoom(css)”設定為“1”來觸發 hasLayout 以便調試。

另外一個需要注意的是“layout”會影響指令碼編程。如果一個元素沒有“layout”,那麼clientWidth/clientHeight 總是返回0。這會讓一些指令碼新手感到困惑,而且這和 Mozilla 瀏覽器的處理方式也不一樣。不過我們可以利用這一點在 IE5.0 中檢測“layout”:如果 clientWidth 是零那麼這個元素就沒有 layout。

CSS hacks

下面用於觸發 haslayout 的 hack 已經經過 IE6 及以下版本測試。今後版本的IE有可能會對此做不同處理。如果新版本瀏覽器發布我們會重新整理這部分內容。
John Gallant 和 Holly Bergevin 在2003年發布的 Holly hack

/* \*/  * html .gainlayout { height: 1%; }  /* */

·可以讓 IE5+ 的任意元素獲得 layout,除了標準相容模式 IE6 中的內嵌元素。
·一般都很有效,除了在某些極少情況下,需要用 height:0 或者 1px 更好一些。
·和 overflow: hidden 不相容,除非在 IE6 的標註相容模式下(因為這時如果父元素沒有定高,那麼height: 1% 會被變回 height: auto)。

或者我們可以用 underscore hack:

.gainlayout { _height: 0; }

另外,更具有向後相容性的方法是使用 條件注釋(conditional comments):

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

在條件注釋中連結一個專門對 IE/Win 做修正的外部樣式表檔案,也不失為一個安全有效好方法:

<link rel="stylesheet" href="allbrowsers.css" type="text/css" />
 
<!--[if lte IE 6]>
<link rel="stylesheet" href="iefix.css" type="text/css" />
<![endif]-->

我們更傾向於使用 height: 0 和 1px —— 並主張始終使用 height 除非它和別的什麼東西衝突 (overflow: hidden)。對於取值,我們則傾向於避免 1% ,因為它可能會(雖然很少)引起一些問題

height 不能應用於標準模式下的內嵌元素。在這種情況下我們可以用 display: inline-block 或 zoom: 1。

我們曾看過一些把 Holly hack 真的當作 holy(神聖的) hack 盲目使用的情況,比如對浮動元素使用或者對已經具有特定寬度的元素也使用這個 hack。要記住這個 hack 的目的不是要給某個元素加一個高度,而只是要觸發 hasLayout = True 而已。

不要給所有元素設定 layout:* {_height: 1px;}。所謂過猶不及,獲得 layout 不等於獲得靈丹妙藥,它只是用來改變渲染模式。

Hack整理

但是瀏覽器總是會變的,我們需要面對很多問題,比如一些依賴 IE6 的 bug 所做的 hack 會在 IE7 或更高版本的新瀏覽器中因 bug 修複而失效(甚至有害)的問題;比如新版本瀏覽器中類似的布局 bug 依然存在但用於 hack 的過濾器比如 * html 卻不能正常工作的問題。這種情況下,MS專有屬性 zoom 就可以考慮使用了。

<!--[if lt IE 7]><style>
/* IE 6 + IE5.5 + IE5.0 所用樣式*/
.gainlayout { height: 0; }
</style><![endif]-->
 
<!--[if IE 7]><style>
.gainlayout { zoom: 1;}
/* 或者其他任何以後可能需要的東西 */
</style><![endif]-->

·zoom: 1; 可以讓 IE5.5+ 的任何元素(包括內嵌元素)獲得 layout,但是在 IE5.0 中無效。
·沒有其他附帶效果(內嵌元素會變成 inline-block,這個當然)。
·如果需要通過驗證,應該用條件注釋將 zoom 隱藏起來。

其實當我們考慮到“向後相容”時是很自相矛盾的,我們強烈建議頁面設計者回過頭看一下自己頁面中用的到的明顯的或是不明顯的“hacks”,並用條件注釋針對不同瀏覽器重新處理以保萬無一失。

關於IE Mac 的小問題

IE Mac 和 windows 下的 IE 是完全不同的兩個東西,它們各自擁有自己的渲染引擎,IE Mac 就全然不知“hasLayout”(或contenteditable)所謂何物。相比之下 IE Mac 的渲染引擎要更標準相容一點,比如 height 就是被當作 height 處理,沒有別的效果。因此針對“hasLayout”的 hacks 和別的解決方案(特別是通過使用 height 或 width 屬性的)往往對 IE Mac 來說是有害的,所以需要對其隱藏。更多的關於 IE Mac 相關的問題可以在 IE Mac, bugs and oddities pages 找到。

MSDN 文檔

MSDN 中涉及到 hasLayout 這個 MS 屬性的地方寥寥無幾,而具體解釋 layout 和 IE 渲染模型之間關係的則少之又少。
在IE4的時候,除了未經絕對位置也未指定寬高的內嵌元素,幾乎所有元素都有某種 layout(MSDN)。在這種早期的layout概念中,像 border, margin, padding 這些屬性被稱作“layout屬性”,它們是不能應用到一個簡單的內嵌元素上的。換句話說,“擁有layout”就可以粗略理解成:“可以擁有這幾個屬性”。

MSDN 上仍然使用 layout 屬性這種說法, 只是含義變了,它們和擁有 layout 的元素已經沒有什麼關係了。在 IE5.5 中方才引入了 MS 的這個專有屬性 hasLayout,也只是某種內部的標誌位而已。

在 IE5.5 中,MSHTML Editing Platform(即可以通過設定來允許使用者即時編輯、拖動 layout 元素以及調整其尺寸等)的文檔中描述了三個和 layout 相關的重要特性:

·如果一個 layout 元素中有內容,內容的排版布局將由它的邊界矩形框決定。
·擁有 layout 的意思基本上就是表示某元素是一個矩形。
·從內部來說,擁有 layout 意思就是一個元素將自己負責繪製其內部內容。

                       (Editing Platform)

和 layout 自身相關的內部工作機制直到2005年8月才有相應文檔描述,當時由於 The Web Standards Project和微軟的特別工作小組的原因,Markus Mielke [MSFT] 開啟了深入討論的大門:

一般來說,在 Internet Explorer 的 DHTML 引擎中,元素是不對自己的位置安排負責的。雖然一個 div 或者一個 p 元素都在源碼中有一個位置,在文檔流有一個位置,但是它們的內容卻是由它們最近的一個 layout 祖先(經常是 body)控制安排的。這些元素依賴它們祖先的 layout 來為他們處理諸如決定大小尺寸和測量資訊等諸多繁重的工作。

分析

我們的分析試圖解釋在已知案例下發生了什麼事情,這種分析也應該可以作為未知案例下的指導。但我們這種試圖利用種種測試案例投石探路的黑箱測試方法,是註定無法消除黑箱的神秘感的——我們無法回答“為什麼”的問題。我們只能去嘗試瞭解整個“hasLayout”模式的工作架構,以及它會怎樣影響網頁文檔的渲染。因此,最終我們只能提供一些指導方針(而且只能是指導方針,而不是絕對的解決方案)。
我們認為他們所指的是一個小表單。一個 layout 元素的內部內容是完全獨立的,而且也無法影響其邊界外的任何內容。
而 MS 屬性 layout 只是某種標誌位:一旦它被設定,這個元素就會擁有 layout“特性”,這包括體現在其自身以及其非 layout 孩子項目身上的特殊效能——比如浮動和層疊等。
這種獨立性也許正可以解釋為什麼 layout 元素通常比較穩定,而且它們可以讓某些 bug 消失。這種情況的代價有二,一是偏離了標準,二是它沒有考慮到今後可能因此出現的 bug 和問題。
MS 的“頁面”模式,從符號學角度考慮,可以看做是由很多互不相關的小的區塊構成,而 HTML 和 W3C 的模式則認為“頁面”模式應該是敘述完備的,故事性的相關資訊區塊構成的。

各種情況的詳細說明

清除浮動和自動擴充適應高度

浮動元素會被 layou 元素自動包含。這是很多新手經常遇到的問題:在 IE 下完成的頁面到了標準相容瀏覽器下所有未清除的浮動元素都伸出了其包含容器之外

·Containing Floats
·how to clear floats without structural markup

相反的情況:如果確實需要一個浮動元素伸出其包含容器,也就是自動包含不是想要的效果時,該怎麼辦?你很可能也會遇到這種頭疼的問題,下面的深入討論就是一個例子:

·acidic float tests

在IE中,一個浮動元素總是“隸屬於”它的 layout 包含容器。而後面的元素會受這個 layout 包含容器影響而不是這個浮動元素影響。

這個特性和IE6的那個自動擴充以適應內部內容寬度的特性,都可以看成是受這個規則影響的:“由它的邊界矩形框決定”。

更糟的問題:clear 無法影響其 layout 包含容器之外的 float 元素。如果依賴這個 bug 在 IE 中布局的頁面要轉到標準相容瀏覽器中,只有全部重做。

IE 的自動包含浮動元素也是經常需要的效果,它在其他瀏覽器中也可以達到:參考我們的 “和 CSS 規範類似的地方” 這一部分來瞭解一下包含浮動元素的相關內容。

浮動元素旁邊的元素

當一個區塊層級元素緊跟在一個左浮動元素之後時,它應該——作為一個區塊層級元素——忽略這個浮動元素,而它的內容則應該因這個浮動元素而移位:一個緊跟在左浮動元素後的區塊層級元素內的文字內容,應該沿著浮動元素的右邊順序排列並會(如果它的長度超過浮動元素)繼續排列到浮動元素下方。但是如果這個區塊層級元素有 layout,比如由於某種原因被設定了寬度,那麼這整個元素則會因浮動元素而移位,就好像它自己也是一個浮動元素一樣,因此其中的文字就不再環繞這個左浮動元素了(而會形成一個矩形地區,保持在它的右邊。)
在 IE5 中一個區塊層級元素的百分比寬度是基於浮動元素旁邊的剩餘空間計算的,而在 IE6 中則是依照整個父區塊層級元素的可用空間計算的。所以在 IE6 中設定 width: 100% 會導致某種浮動元素旁邊的溢出現象,於是各種布局問題也會因此而來。
一些關於浮動塊旁邊的 hasLayout 塊的測試案例:

·by using width
·by using min-width (IE 7) and zoom (IE 6)

與此類似,和浮動元素相鄰的相對定位元素,它的位置位移量應該參照的是父元素的補白(padding)邊緣(例如,left: 0; 應該將一個相對定位元素疊放於它前面的浮動元素之上)。在 IE6 中,位移量 left: value; 是從浮動元素的右邊距(margin)邊緣開始算起的,這會因浮動元素所佔的寬度變化導致水平方向的錯位(一個解決方案是用 margin-left 代替,但是也要注意如使用百分值時會有一些怪異問題)。

·layout blocks with relative positioning adjacent to floated blocks

根據規範所述,浮動元素應該與其後的盒子交織在一起。而對於沒有交叉的二維空間中的矩形而言這是無法實現的。
如果誰真的需要向 IE 的這種不當行為屈服,那麼如何讓標準相容瀏覽器中的盒子也有類似行為——即類似於 layout 盒子會自動“收縮”而給其前置的浮動元素讓出空間的行為——就是一個問題了。我們給出的方法是跟著一個浮動元素建立一個新的塊級格式化範圍(block formatting context),這在我們的“和 CSS 規範類似的地方” 有討論。
可以(再次)訪問下面這個頁面:

·three pixel text-jog

我們可以看到跟在一個浮動元素後的 layout 元素不會顯示這個3px間隙的 bug,因為浮動元素外圍的3px硬邊無法影響一個 layout 元素的內部內容,所以這個硬邊將整個 layout 元素右推了3px。好比一個防護罩,layout 可以保護其內部內容不受影響,但是浮動元素的力量卻將整個防護罩推了開來。

列表

無論是列表本身(ol, ul) 還是單個的列表元素(li),擁有 layout 後都會影響列表的表現。不同版本 IE 的表現又有不同。最明顯的效果就體現在列表符號上(如果你的列表自訂了列表符號則不會受這個問題影響)。這些符號很可能是通過某種內部機制附到列表元素上的(通常是附著在它們外面)。不幸的是,由於是通過“內部機制”添加的,我們無法訪問它們也無法修正它們的錯誤表現。
最明顯的效果有:

·列表獲得 layout 後,列表符號會消失或者被放置在不同的或者錯誤的位置。

有時它們又可以通過改變列表元素的邊距而重新出現。這看起來似乎是以下事實導致的結果:layout 元素會試圖裁掉超出其邊界的內部內容。

·列表元素獲得 layout 之後,會有和上面一樣的問題出現,更多參考 (extra vertical space between list items)http://www.brunildo.org/test/IEWlispace.php

進一步又有一個問題就是(在有序列表中)任何具有 layout 的列表元素似乎都有自己獨立的計數器。比如我們有一個含五個列表元素的有序列表,只有第三個列表元素有 layout。我們會看到這樣:
1… 2… 1… 4… 5…

·此外,如果一個有 layout 的列表元素跨行顯示時,列表符號會底部對齊(而不是按照預料的頂部對齊)。

·以上某些問題還是無法解決的,所以如果需要列表符號的時候最好避免讓列表和列表元素獲得 layout。如果需要限定尺寸,最好給別的元素設定尺寸,比如給整個列表外面套一個元素並設定它的寬度,又或者比如給每個列表元素中的內容設定高度等等。

·另一個IE中列表的常見問題出現在當某個 li 中的內容是一個 display: block 的錨點(anchor)時。在這種情況下,列表元素之間的空格將不會被忽略而且通常會顯示成額外的一行夾在每個 li 之間。一種避免這種豎直方向多餘空白的解決方案是賦予這些錨點 layout。這樣還有一個好處就是可以讓整個錨點的矩形地區都可以響應滑鼠點擊。

表格

table 總是有 layout 的,它總表現為一個已定義寬度的對象。在IE6中,table-layout: fixed 通常和一個寬度設為100%的表格相同,同時這也會帶來很多問題(一些計算方面的錯誤)。另外在IE5.5和IE6的quirks模式下還有一些別的需要注意的情況

相對定位元素(r.p.)

注意,由於 position: relative 並不觸發 hasLayout,所以很多諸如內容消失或錯位的渲染錯誤就會因此而起。這些現象可能會在重新整理頁面、調整視窗大小、滾動頁面、選中內容等情況下出現。原因是 IE 在據這個屬性對元素做位移處理時,卻似乎忘了發出訊號讓其 layout 孩子項目進行“重繪”(而如果是一個layout元素,那麼在其重繪事件的訊號鏈中,這個傳給其孩子的訊號是會正常發出的)。

·r.p. parent and disappearing floated child
·disappearing list-background bug

以上是一些相關問題的描述。作為經驗之談,相對定位一個元素時最好給予其 layout。再有,我們也需要檢查擁有這種結構的父元素是否也需要 layout 或者position: relative亦或二者都需要,如果涉及到浮動元素這點就十分重要。

絕對位置元素(a.p.):
包含區塊,什麼是包含區塊?

理解 CSS 的包含區塊概念很重要,它回答了絕對位置元素是相對哪裡定位的問題:包含區塊決定了位移起點,包含區塊定義了百分比長度的計算參考。

對於絕對位置元素,包含區塊是由其最近的定位祖先決定的。如果其祖先都沒有被定位,那麼就使用初始包含區塊 html。

通常情況下我們會用 position: relative 來設定任意包含區塊。這就是說,我們可以讓一個絕對位置元素所參考的原點和長度等不依賴於元素的排列順序,這可以滿足諸如“內容優先”這種可訪問性概念的需要,也可以給複雜的浮動布局帶來方便。

但是由於 layout 概念的存在,這種設計理念的效果在IE中就要打個問號了:因為在IE中絕對位置只有當其包含元素擁有 layout 時才會計算正確,而且絕對位置元素的百分比寬度參考也搞錯了對象。這裡 IE5 和 IE6 的行為不同但都有問題。IE7b2 的行為就要好很多,雖然有些小地方還是有錯誤。總之儘可能的讓絕對元素的包含區塊擁有 layout,而且盡量讓其就是絕對位置元素的父級元素(也就是說這個包換元素和絕對位置元素之間沒有絕對位置元素的別的祖先了)。

假設一個無 layout 的父元素被相對定位了——我們就得給它賦予 layout 才能使位移量起作用:

·Absolutely Buggy II

假設一個未定位的父元素需要特定尺寸,而且頁面設計是基於百分比寬度的——我們就可以放棄這個想法了,因為瀏覽器支援不佳:

·absolutely positioned element and percentage width

濾鏡

MS專有的濾鏡屬性 filter 是只適用於 layout 元素的。有些濾鏡擴充了對象的邊界。它們會顯示出自身特有的缺陷

對已渲染元素的重排(re-flow)

當所有元素都已渲染完成時,如果有一個因滑鼠經過而引起的變化產生(比如某個連結的 background 有變化),IE會對其 layout 包含區塊進行重排。有時一些元素就會因此被排到了新的位置,因為當這個滑鼠經過發生時,IE已經知道了所有相關元素的寬度、位移量等資料了。這在文檔首次載入時則不會發生,那時由於自動擴張的特性,寬度還無法確定。這種情況會導致在滑鼠經過時頁面出現跳變。

·Jump on :hover
·quirky percentages: the reflow

這些和重排問題相關的 bug 會給百分比邊距和補白使用較多的流動布局帶來不少麻煩。

背景原點

MS專有的這個 hasLayout 還會影響背景的定位和擴充。比如,根據 CSS 規範,background-position: 0 0 應該指元素的“補白邊緣(padding edge)”。而在 IE/Win 下,如果 hasLayout = false 則指的是“邊框邊緣(border edge)”,當 hasLayout=true 時指的才是補白邊緣:

·Background, Border, hasLayout

邊距重疊

hasLayout 會影響一個盒子和其子孫的邊距重疊。根據規範,一個盒子如果沒有上補白和上邊框,那麼它的上邊距應該和其文檔流中的第一個孩子項目的上邊距重疊:

·Collapsing Margins
·Uncollapsing Margins

在 IE/Win 中如果這個盒子有 layout 那麼這種現象就不會發生了:似乎擁有 layout 會阻止其孩子的邊距伸出包含容器之外。此外當 hasLayout = true 時,不論包含容器還是孩子項目,都會有邊距計算錯誤的問題出現。

·Margin collapsing and hasLayout 

塊層級的連結

hasLayout 會影響一個塊層級連結的滑鼠響應地區(可點擊地區)。通常 hasLayout = false 時只有文字覆蓋地區才能響應。而 hasLayout = true 則整個塊狀地區都可響應。添加了 onclick/onmouseover 等事件的任意區塊層級元素也有同樣的現象。

·Block anchors and hasLayout

在頁面內使用鍵盤瀏覽:探索中
當使用 tab 在頁面中瀏覽時,如果進入了一個頁內連結(in-page link),那麼接下來再按的 tab 鍵就不會正常繼續了:

·hasLayout Property Characterizes IE6 Bug
·Keyboard Navigation and Internet Explorer

tab 鍵會把使用者帶到(這通常是錯誤的)其最近的 layout 祖先中的第一個目標(如果這個祖先是由 table, div, span 或某些別的標籤構成)。

收縮包圍(shrink-wrapping)現象

給已經有 width: auto 的元素添加某些屬性會導致它們在計算自身寬度時使用一種收縮包圍的演算法。比如這些屬性 float: left|right, position: absolute|fixed, display: table|table-cell|inline-block|inline-table.

這些屬性造成的現象在IE/Win中也存在,當然這是只對那些它支援的屬性而言。但是當一個應該收縮包圍的元素中包含一個擁有“layout”的區塊層級元素時,在絕大多數情況下,這個孩子項目的寬度會儘可能地擴充而與其中包含的內容無關,同時也阻止了父元素的收縮包圍現象。

例子:
一個浮動的縱嚮導航無序列表並沒有收縮包圍,因為其中的連結為了消除列表的多餘空白bug並擴充可點擊地區而擁有了 layout:a {display: block; zoom: 1;}。

這時收縮包圍現象只有在以下情況仍然有效:擁有 layout 的孩子項目同時也被賦予了一個特定寬度,或者這個孩子項目本身也是一個具有收縮包圍特性的元素,比如浮動元素。

邊緣裁切

通常而言,當一個盒子包含了諸如伸出其邊緣的內容這種更複雜的結構時,這個容器就經常需要“hasLayout”來避免一些渲染錯誤。但使用這種常用方法又會在邊界處理時左右為難,因為一個獲得“layout”的元素會變成某種自封閉的盒子。
內部的內容盒子會被裁切,比如使用負邊距向外移動時。

·Clipping of negative margined blocks in a hasLayout container

被裁掉的部分當內容盒子觸發了“layout”時可以再次出現,但在 IE6 中需要同時擁有 position: relative 才行。IE7 在這方面要略有改觀,它不再需要額外的 position: relative 了。



相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.