文中所有的 layout 這個(gè)單詞都未作翻譯,一來(lái)本身這個(gè)單詞意思就比較多,翻成啥都覺得別扭,二來(lái)它也是專有的屬性,所以就意會(huì)一下吧。水平有限,很多地方都是模模糊糊地意譯,發(fā)現(xiàn)錯(cuò)誤歡迎留言指出。
引用一段來(lái)自Dean Edwards的評(píng)價(jià):
I recommend that every CSS designer and DOM scripter read this. Understanding “l(fā)ayout” gives a huge insight into lots of other IE bugs and idiosyncrasies.
(Dean Edwards)
Internet Explorer 中有很多奇怪的渲染問題可以通過(guò)賦予其“l(fā)ayout”得到解決。John Gallant 和 Holly Bergevin 把這些問題歸類為“尺寸bug(dimensional bugs)”,意思是這些 bug 可以通過(guò)賦予相應(yīng)元素某個(gè)寬度或高度解決。這便引出關(guān)于“l(fā)ayout”的一個(gè)問題:為什么它會(huì)改變?cè)氐匿秩咎匦?,為什么它?huì)影響到元素之間的關(guān)系?這個(gè)問題問得很好,但卻很難回答。在這篇文章中,我們專注于這個(gè)復(fù)雜問題會(huì)有那些方面的表現(xiàn),某一方面的具體討論和范例請(qǐng)參考文中給出的相關(guān)鏈接。
“Layout”是一個(gè) IE/Win 的私有概念,它決定了一個(gè)元素如何顯示以及約束其包含的內(nèi)容、如何與其他元素交互和建立聯(lián)系、如何響應(yīng)和傳遞應(yīng)用程序事件/用戶事件等,這有點(diǎn)類似于一個(gè)窗體的概念。
微軟的開發(fā)者們認(rèn)為盒狀元素(box-type elements)應(yīng)該具有一個(gè)“屬性(property)”(這是面向?qū)ο缶幊讨械囊粋€(gè)概念),于是他們便使用了 layout
, 也就是 hasLayout
。
hasLayout
其實(shí)既不是一個(gè)屬性更不是一個(gè)行為,而是 IE 這個(gè)渲染引擎代代繼承一貫擁有的一個(gè)渲染概念,在這個(gè)概念下渲染的元素將具有一種特性。
實(shí)際上這種渲染特性在有些 HTML 元素中與身俱來(lái),而在另外一些元素中也可以通過(guò)一些 CSS 屬性將其觸發(fā)為 true
,且一旦觸發(fā)將不可逆轉(zhuǎn)。
當(dāng)我們說(shuō)一個(gè)元素“擁有l(wèi)ayout”或“得到layout”,或者說(shuō)一個(gè)元素“has layout” 的時(shí)候,我們的意思是指它的微軟專有屬性 hasLayout
被設(shè)為了 true
。一個(gè)“l(fā)ayout元素”可以是一個(gè)默認(rèn)就擁有 layout 的元素或者是一個(gè)通過(guò)設(shè)置某些 CSS 屬性得到 layout 的元素。
而“無(wú)layout元素”,是指 hasLayout 未被觸發(fā)的元素,比如一個(gè)未設(shè)定寬高尺寸的干凈 div 元素就可以做為一個(gè) “無(wú)layout祖先”。
給一個(gè)默認(rèn)沒有 layout 的元素賦予 layout 的方法包括設(shè)置可觸發(fā) hasLayout = true
的 CSS 屬性。參考默認(rèn) layout 元素以及這些屬性列表。沒有辦法設(shè)置 hasLayout = false
, 除非把一開始那些觸發(fā) hasLayout = true
的 CSS 屬性去除。
hasLayout
的問題不管新手還是老手,不管設(shè)計(jì)師或者程序員可能都遇到過(guò)。具有 layout 的元素通常有著不同尋常而且難以預(yù)料的的顯示效果,而且有時(shí)甚至?xí)窟B到他們的孩子元素。
一個(gè)元素是否具有“l(fā)ayout”可能會(huì)引發(fā)如下的一些問題:
上面的列表只是列出一個(gè)大概,也不完善。下面的文章將盡可能詳細(xì)徹底的描述有無(wú)“l(fā)ayout”所帶來(lái)的各種問題。
不同于標(biāo)準(zhǔn)屬性,也不像某些瀏覽器的私有 CSS 屬性,layout 無(wú)法通過(guò)某一個(gè) CSS 聲明直接設(shè)定 。也就是說(shuō)沒有“l(fā)ayout屬性”這么一個(gè)東西,元素要么本身自動(dòng)擁有 layout,要么借助一些 CSS 聲明悄悄地獲得 layout。
下列元素應(yīng)該是默認(rèn)具有 layout 的:
html>, body>
table>, tr>, th>, td>
img>
hr>
input>, select>, textarea>, button>
iframe>, embed>, object>, applet>
marquee>
下列 CSS 屬性和取值將會(huì)讓一個(gè)元素獲得 layout:
position: absolute
float: left|right
display: inline-block
width: 任意值
height: 任意值
zoom: 任意值
(MSDN)
zoom: 1
可以臨時(shí)用做調(diào)試。
writing-mode: tb-rl
(MSDN)
在 IE7 中,overflow 也變成了一個(gè) layout 觸發(fā)器:
overflow: hidden|scroll|auto
overflow-x|-y: hidden|scroll|auto
另外 IE7 的熒幕上又新添了幾個(gè) haslayout 的演員,如果只從 hasLayout 這個(gè)方面考慮,min/max 和 width/height 的表現(xiàn)類似,position 的 fixed 和 absolute 也是一模一樣。
position: fixed
min-width: 任意值
max-width: 除 none 之外的任意值
min-height: 任意值
max-height: 除 none 之外的任意值
以上結(jié)論借助 IE Developer Toobar 以及預(yù)先測(cè)試得出。
對(duì)于內(nèi)聯(lián)元素(可以是默認(rèn)即為內(nèi)聯(lián)的比如 span
元素,也可以是 display: inline
的元素)
width
和 height
只在 IE5.x 下和 IE6 的 quirks 模式下觸發(fā) hasLayout
。因?yàn)樵?IE6 中,如果瀏覽器運(yùn)行于標(biāo)準(zhǔn)兼容模式下,內(nèi)聯(lián)元素會(huì)忽略 width 或 height 屬性,所以設(shè)置 width 或 height 不能在此種情況下令該元素具有 layout。
zoom
總是可以觸發(fā) hasLayout
,但是在 IE5.0 中不支持。 具有“l(fā)ayout” 的元素如果同時(shí)也 display: inline
,那么它的行為就和標(biāo)準(zhǔn)中所說(shuō)的 inline-block 很類似了:在段落中和普通文字一樣在水平方向和連續(xù)排列,受 vertical-align 影響,并且大小可以根據(jù)內(nèi)容自適應(yīng)調(diào)整。這也可以解釋為什么單單在 IE/Win 中內(nèi)聯(lián)元素可以包含塊級(jí)元素而少出問題,因?yàn)樵趧e的瀏覽器中 display: inline
就是內(nèi)聯(lián),不像 IE/Win 一旦內(nèi)聯(lián)元素?fù)碛?layout 還會(huì)變成 inline-block。
我們這里稱 hasLayout 為“腳本屬性”是為了和我們熟知的 CSS 屬性相區(qū)別。
注意一旦一個(gè)元素?fù)碛辛?layout,就沒有辦法再將其設(shè)成 hasLayout = False
了。
hasLayout-property 可以用來(lái)檢測(cè)一個(gè)元素是否擁有 layout:舉個(gè)例子,如果它的 id
是“eid”,那么只要在 IE5.5+ 的地址欄里輸入 javascript: alert(eid.currentStyle.hasLayout)
即可檢測(cè)它的狀態(tài)。
IE的 Developer Toolbar 可以實(shí)時(shí)檢查一個(gè)元素的當(dāng)前樣式;如果 hasLayout
是 true ,那么它的值顯示為 “-1”。 我們可以通過(guò)實(shí)時(shí)修改一個(gè)元素的屬性將“zoom(css)”設(shè)置為“1”來(lái)觸發(fā) hasLayout
以便調(diào)試。
另外一個(gè)需要注意的是“l(fā)ayout”會(huì)影響腳本編程。如果一個(gè)元素沒有“l(fā)ayout”,那么clientWidth
/clientHeight
總是返回0。這會(huì)讓一些腳本新手感到困惑,而且這和 Mozilla 瀏覽器的處理方式也不一樣。不過(guò)我們可以利用這一點(diǎn)在 IE5.0 中檢測(cè)“l(fā)ayout”:如果 clientWidth
是零那么這個(gè)元素就沒有 layout。
下面用于觸發(fā) haslayout
的 hack 已經(jīng)經(jīng)過(guò) IE6 及以下版本測(cè)試。今后版本的IE有可能會(huì)對(duì)此做不同處理。如果新版本瀏覽器發(fā)布我們會(huì)重新整理這部分內(nèi)容。
John Gallant 和 Holly Bergevin 在2003年發(fā)布的 Holly hack :
/* \*/ * html .gainlayout { height: 1%; } /* */
overflow: hidden
不相容,除非在 IE6 的標(biāo)注兼容模式下(因?yàn)檫@時(shí)如果父元素沒有定高,那么height: 1%
會(huì)被變回 height: auto
)。 或者我們可以用 underscore hack:
.gainlayout { _height: 0; }
另外,更具有向后兼容性的方法是使用 條件注釋(conditional comments):
!--[if lte IE 6]> style> .gainlayout { height: 1px; } /style> ![endif]-->
在條件注釋中鏈接一個(gè)專門對(duì) IE/Win 做修正的外部樣式表文件,也不失為一個(gè)安全有效的好方法:
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
)。對(duì)于取值,我們則傾向于避免 1%
,因?yàn)樗赡軙?huì)(雖然很少)引起一些問題。
一個(gè)需要注意的情況是如果我們希望一個(gè)元素保持內(nèi)聯(lián),那么就不能使用 height
了,這時(shí)可以用 display: inline-block
。我們只在早期調(diào)試階段用 zoom: 1
來(lái)避免一些渲染錯(cuò)誤。
我們?cè)催^(guò)一些把 Holly hack 真的當(dāng)作 holy(神圣的) hack 盲目使用的情況,比如對(duì)浮動(dòng)元素使用或者對(duì)已經(jīng)具有特定寬度的元素也使用這個(gè) hack。要記住這個(gè) hack 的目的不是要給某個(gè)元素加一個(gè)高度,而只是要觸發(fā) hasLayout = True
而已。
不要給所有元素設(shè)置 layout:* {_height: 1px;}
。所謂過(guò)猶不及,獲得 layout 不等于獲得靈丹妙藥,它只是用來(lái)改變渲染模式。
但是瀏覽器總是會(huì)變的,我們需要面對(duì)很多問題,比如一些依賴 IE6 的 bug 所做的 hack 會(huì)在 IE7 或更高版本的新瀏覽器中因 bug 修復(fù)而失效(甚至有害)的問題;比如新版本瀏覽器中類似的布局 bug 依然存在但用于 hack 的過(guò)濾器比如 * 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+ 的任何元素(包括內(nèi)聯(lián)元素)獲得 layout,但是在 IE5.0 中無(wú)效。
zoom
隱藏起來(lái)。 其實(shí)當(dāng)我們考慮到“向后兼容”時(shí)是很自相矛盾的,我們強(qiáng)烈建議頁(yè)面設(shè)計(jì)者回過(guò)頭看一下自己頁(yè)面中用的到的明顯的或是不明顯的“hacks”,并用條件注釋針對(duì)不同瀏覽器重新處理以保萬(wàn)無(wú)一失。
IE Mac 和 windows 下的 IE 是完全不同的兩個(gè)東西,它們各自擁有自己的渲染引擎,IE Mac 就全然不知“hasLayout”(或contenteditable)所謂何物。相比之下 IE Mac 的渲染引擎要更標(biāo)準(zhǔn)兼容一點(diǎn),比如 height
就是被當(dāng)作 height
處理,沒有別的效果。因此針對(duì)“hasLayout”的 hacks 和別的解決方法(特別是通過(guò)使用 height
或 width
屬性的)往往對(duì) IE Mac 來(lái)說(shuō)是有害的,所以需要對(duì)其隱藏。更多的關(guān)于 IE Mac 相關(guān)的問題可以在 IE Mac, bugs and oddities pages 找到。
MSDN 中涉及到 hasLayout 這個(gè) MS 屬性的地方寥寥無(wú)幾,而具體解釋 layout 和 IE 渲染模型之間關(guān)系的則少之又少。
在IE4的時(shí)候,除了未經(jīng)絕對(duì)定位也未指定寬高的內(nèi)聯(lián)元素,幾乎所有元素都有某種 layout(MSDN)。在這種早期的layout概念中,像 border, margin, padding
這些屬性被稱作“l(fā)ayout屬性”,它們是不能應(yīng)用到一個(gè)簡(jiǎn)單的內(nèi)聯(lián)元素上的。換句話說(shuō),“擁有l(wèi)ayout”就可以粗略理解成:“可以擁有這幾個(gè)屬性”。
MSDN 上仍然使用 layout 屬性這種說(shuō)法, 只是含義變了,它們和擁有 layout 的元素已經(jīng)沒有什么關(guān)系了。在 IE5.5 中方才引入了 MS 的這個(gè)專有屬性 hasLayout
,也只是某種內(nèi)部的標(biāo)志位而已。
在 IE5.5 中,MSHTML Editing Platform(即可以通過(guò)設(shè)置body contenteditable=true>
來(lái)允許用戶實(shí)時(shí)編輯、拖動(dòng) layout 元素以及調(diào)整其尺寸等)的文檔中描述了三個(gè)和 layout 相關(guān)的重要特性:
如果一個(gè) layout 元素中有內(nèi)容,內(nèi)容的排版布局將由它的邊界矩形框決定。
擁有 layout 的意思基本上就是表示某元素是一個(gè)矩形。
從內(nèi)部來(lái)說(shuō),擁有 layout 意思就是一個(gè)元素將自己負(fù)責(zé)繪制其內(nèi)部?jī)?nèi)容。
(Editing Platform)
和 layout 自身相關(guān)的內(nèi)部工作機(jī)制直到2005年8月才有相應(yīng)文檔描述,當(dāng)時(shí)由于 The Web Standards Project 和微軟的特別工作小組的原因,Markus Mielke [MSFT] 打開了深入討論的大門:
一般來(lái)說(shuō),在 Internet Explorer 的 DHTML 引擎中,元素是不對(duì)自己的位置安排負(fù)責(zé)的。雖然一個(gè) div 或者一個(gè) p 元素都在源碼中有一個(gè)位置,在文檔流有一個(gè)位置,但是它們的內(nèi)容卻是由它們最近的一個(gè) layout 祖先(經(jīng)常是 body)控制安排的。這些元素依賴它們祖先的 layout 來(lái)為他們處理諸如決定大小尺寸和測(cè)量信息等諸多繁重的工作。
(HasLayout概述)
我們的分析試圖解釋在已知案例下發(fā)生了什么事情,這種分析也應(yīng)該可以作為未知案例下的指導(dǎo)。但我們這種試圖利用種種測(cè)試案例投石探路的黑箱測(cè)試方法,是注定無(wú)法消除黑箱的神秘感的——我們無(wú)法回答“為什么”的問題。我們只能去嘗試了解整個(gè)“hasLayout”模式的工作框架,以及它會(huì)怎樣影響網(wǎng)頁(yè)文檔的渲染。因此,最終我們只能提供一些指導(dǎo)方針(而且只能是指導(dǎo)方針,而不是絕對(duì)的解決方案)。
我們認(rèn)為他們所指的是一個(gè)小窗體。一個(gè) layout 元素的內(nèi)部?jī)?nèi)容是完全獨(dú)立的,而且也無(wú)法影響其邊界外的任何內(nèi)容。
而 MS 屬性 layout 只是某種標(biāo)志位:一旦它被設(shè)定,這個(gè)元素就會(huì)擁有其特殊的 layout“特性”,這包括體現(xiàn)在其自身以及其非 layout 孩子身上的浮動(dòng)、清除浮動(dòng)、層疊、計(jì)數(shù)等等諸多方面的特殊性能。
這種獨(dú)立性也許正可以解釋為什么 layout 元素通常比較穩(wěn)定,而且它們可以讓某些 bug 消失。這種情況的代價(jià)有二,一是偏離了標(biāo)準(zhǔn),二是它沒有考慮到今后可能因此出現(xiàn)的 bug 和問題。
MS 的“頁(yè)面”模式,從符號(hào)學(xué)角度考慮,可以看做是由很多互不相關(guān)的小的區(qū)塊構(gòu)成,而 HTML 和 W3C 的模式則認(rèn)為“頁(yè)面”模式應(yīng)該是敘述完備的,故事性的相關(guān)信息區(qū)塊構(gòu)成的。
浮動(dòng)元素會(huì)被 layou 元素自動(dòng)包含。這是很多新手經(jīng)常遇到的問題:在 IE 下完成的頁(yè)面到了標(biāo)準(zhǔn)兼容瀏覽器下所有未清除的浮動(dòng)元素都伸出了其包含容器之外。
相反的情況:如果確實(shí)需要一個(gè)浮動(dòng)元素伸出其包含容器,也就是自動(dòng)包含不是想要的效果時(shí),該怎么辦?你很可能也會(huì)遇到這種頭疼的問題,下面的深入討論就是一個(gè)例子:
在IE中,一個(gè)浮動(dòng)元素總是“隸屬于”它的 layout 包含容器。而后面的元素會(huì)受這個(gè) layout 包含容器影響而不是這個(gè)浮動(dòng)元素影響。
這個(gè)特性和IE6的那個(gè)自動(dòng)擴(kuò)展以適應(yīng)內(nèi)部?jī)?nèi)容寬度的特性,都可以看成是受這個(gè)規(guī)則影響的:“由它的邊界矩形框決定”。
更糟的問題:clear
無(wú)法影響其 layout 包含容器之外的 float 元素。如果依賴這個(gè) bug 在 IE 中布局的頁(yè)面要轉(zhuǎn)到標(biāo)準(zhǔn)兼容瀏覽器中,只有全部重做。
更多相關(guān)信息查看本文 “和 CSS 規(guī)范類似的地方” 這一部分。
當(dāng)一個(gè)塊級(jí)元素緊跟在一個(gè)左浮動(dòng)元素之后時(shí),其中的文字內(nèi)容應(yīng)該沿著浮動(dòng)元素的右邊順序排列并會(huì)滑到浮動(dòng)元素下方。但是如果這個(gè)塊級(jí)元素有 layout,比如由于某種原因被設(shè)置了寬度,那么這個(gè) layout 元素就會(huì)表現(xiàn)為一個(gè)矩形,其中文字不會(huì)滑向浮動(dòng)元素下方。其寬度也被錯(cuò)誤計(jì)算——從浮動(dòng)元素的右邊開始算起了,所以如果給它設(shè)置 width: 100%
將會(huì)導(dǎo)致顯示時(shí)這個(gè) block 的寬度加上了浮動(dòng)元素的寬度而出現(xiàn)橫向滾動(dòng)條。這種表現(xiàn)就和規(guī)范中描述的相去甚遠(yuǎn)了。
與此類似,和浮動(dòng)元素相鄰的相對(duì)定位元素,它的位置偏移量應(yīng)該參照的是父元素的補(bǔ)白(padding)邊緣(例如,left: 0;
應(yīng)該將一個(gè)相對(duì)定位元素疊放于它前面的浮動(dòng)元素之上)。在IE中,偏移量 left: value;
是從浮動(dòng)元素的右邊距(margin)邊緣開始算起的,這會(huì)因浮動(dòng)元素所占的寬度變化導(dǎo)致水平方向的錯(cuò)位(一個(gè)解決方法是用 margin-left
代替,但是也要注意如使用百分值時(shí)會(huì)有一些怪異問題)。
根據(jù)規(guī)范所述,浮動(dòng)元素應(yīng)該與其后的盒子交織在一起。而對(duì)于沒有交叉的二維空間中的矩形而言這是無(wú)法實(shí)現(xiàn)的。
可以(再次)訪問下面這個(gè)頁(yè)面:
我們可以看到跟在一個(gè)浮動(dòng)元素后的 layout 元素不會(huì)顯示這個(gè)3px間隙的 bug,因?yàn)楦?dòng)元素外圍的3px硬邊無(wú)法影響一個(gè) layout 元素的內(nèi)部?jī)?nèi)容,所以這個(gè)硬邊將整個(gè) layout 元素右推了3px。好比一個(gè)防護(hù)罩,layout 可以保護(hù)其內(nèi)部?jī)?nèi)容不受影響,但是浮動(dòng)元素的力量卻將整個(gè)防護(hù)罩推了開來(lái)。
更多相關(guān)信息查看本文 “和 CSS 規(guī)范類似的地方” 這一部分
無(wú)論是列表本身(ol, ul
) 還是單個(gè)的列表元素(li
),擁有 layout 后都會(huì)影響列表的表現(xiàn)。不同版本 IE 的表現(xiàn)又有不同。最明顯的效果就體現(xiàn)在列表符號(hào)上(如果你的列表自定義了列表符號(hào)則不會(huì)受這個(gè)問題影響)。這些符號(hào)很可能是通過(guò)某種內(nèi)部機(jī)制附到列表元素上的(通常是附著在它們外面)。不幸的是,由于是通過(guò)“內(nèi)部機(jī)制”添加的,我們無(wú)法訪問它們也無(wú)法修正它們的錯(cuò)誤表現(xiàn)。
最明顯的效果有:
有時(shí)它們又可以通過(guò)改變列表元素的邊距而重新出現(xiàn)。這看起來(lái)似乎是以下事實(shí)導(dǎo)致的結(jié)果:layout 元素會(huì)試圖裁掉超出其邊界的內(nèi)部?jī)?nèi)容。
進(jìn)一步又有一個(gè)問題就是(在有序列表中)任何具有 layout 的列表元素似乎都有自己獨(dú)立的計(jì)數(shù)器。比如我們有一個(gè)含五個(gè)列表元素的有序列表,只有第三個(gè)列表元素有 layout。我們會(huì)看到這樣:
1… 2… 1… 4… 5…
此外,如果一個(gè)有 layout 的列表元素跨行顯示時(shí),列表符號(hào)會(huì)底部對(duì)齊(而不是按照預(yù)料的頂部對(duì)齊)。
以上某些問題還是無(wú)法解決的,所以如果需要列表符號(hào)的時(shí)候最好避免讓列表和列表元素獲得 layout。如果需要限定尺寸,最好給別的元素設(shè)定尺寸,比如給整個(gè)列表外面套一個(gè)元素并設(shè)定它的寬度,又或者比如給每個(gè)列表元素中的內(nèi)容設(shè)定高度等等。
另一個(gè)IE中列表的常見問題出現(xiàn)在當(dāng)某個(gè) li
中的內(nèi)容是一個(gè) display: block
的錨點(diǎn)(anchor)時(shí)。在這種情況下,列表元素之間的空格將不會(huì)被忽略而且通常會(huì)顯示成額外的一行夾在每個(gè) li
之間。一種避免這種豎直方向多余空白的解決方法是賦予這些錨點(diǎn) layout。這樣還有一個(gè)好處就是可以讓整個(gè)錨點(diǎn)的矩形區(qū)域都可以響應(yīng)鼠標(biāo)點(diǎn)擊。
table
總是有 layout 的,它總表現(xiàn)為一個(gè)已定義寬度的對(duì)象。在IE6中,table-layout: fixed
通常和一個(gè)寬度設(shè)為100%的表格相同,同時(shí)這也會(huì)帶來(lái)很多問題(一些計(jì)算方面的錯(cuò)誤)。另外在IE5.5和IE6的quirks模式下還有一些別的需要注意的情況。
注意,由于 position: relative
并不觸發(fā) hasLayout,所以很多諸如內(nèi)容消失或錯(cuò)位的渲染錯(cuò)誤就會(huì)因此而起。這些現(xiàn)象可能會(huì)在刷新頁(yè)面、調(diào)整窗口大小、滾動(dòng)頁(yè)面、選中內(nèi)容等情況下出現(xiàn)。原因是 IE 在據(jù)這個(gè)屬性對(duì)元素做偏移處理時(shí),卻似乎忘了發(fā)出信號(hào)讓其 layout 孩子元素進(jìn)行“重繪”(而如果是一個(gè)layout元素,那么在其重繪事件的信號(hào)鏈中,這個(gè)傳給其孩子的信號(hào)是會(huì)正常發(fā)出的)。
以上是一些相關(guān)問題的描述。作為經(jīng)驗(yàn)之談,相對(duì)定位一個(gè)元素時(shí)最好給予其 layout。再有,我們也需要檢查擁有這種結(jié)構(gòu)的父元素是否也需要 layout 或者position: relative
亦或二者都需要,如果涉及到浮動(dòng)元素這點(diǎn)就十分重要。
理解 CSS 的包含區(qū)塊概念很重要,它回答了絕對(duì)定位元素是相對(duì)哪里定位的問題:包含區(qū)塊決定了偏移起點(diǎn),包含區(qū)塊定義了百分比長(zhǎng)度的計(jì)算參考。
對(duì)于絕對(duì)定位元素,包含區(qū)塊是由其最近的定位祖先決定的。如果其祖先都沒有被定位,那么就使用初始包含區(qū)塊 html
。
通常情況下我們會(huì)用 position: relative
來(lái)設(shè)定任意包含區(qū)塊。這就是說(shuō),我們可以讓一個(gè)絕對(duì)定位元素所參考的原點(diǎn)和長(zhǎng)度等不依賴于元素的排列順序,這可以滿足諸如“內(nèi)容優(yōu)先”這種可訪問性概念的需要,也可以給復(fù)雜的浮動(dòng)布局帶來(lái)方便。
但是由于 layout 概念的存在,這種設(shè)計(jì)理念的效果在IE中就要打個(gè)問號(hào)了。因?yàn)樵贗E中絕對(duì)定位的元素是相對(duì)于其最近的 layout 定位祖先而做偏移的,而百分比的尺寸卻是參考這個(gè) layout 定位祖先的下一個(gè) layout 祖先計(jì)算的。注意這里的小差別,還有剛才提到 position: relative
是不會(huì)觸發(fā) hasLayout 的。
假設(shè)一個(gè)無(wú) layout 的父元素被相對(duì)定位了——我們就得給它賦予 layout 才能使偏移量起作用:
假設(shè)一個(gè)未定位的父元素需要特定尺寸,而且頁(yè)面設(shè)計(jì)是基于百分比寬度的——我們就可以放棄這個(gè)想法了,因?yàn)闉g覽器支持不佳:
MS專有的濾鏡屬性 filter 是只適用于 layout 元素的。有些濾鏡擴(kuò)展了對(duì)象的邊界。它們會(huì)顯示出自身特有的缺陷。
當(dāng)所有元素都已渲染完成時(shí),如果有一個(gè)因鼠標(biāo)經(jīng)過(guò)而引起的變化產(chǎn)生(比如某個(gè)鏈接的 background
有變化),IE會(huì)對(duì)其 layout 包含區(qū)塊進(jìn)行重排。有時(shí)一些元素就會(huì)因此被排到了新的位置,因?yàn)楫?dāng)這個(gè)鼠標(biāo)經(jīng)過(guò)發(fā)生時(shí),IE已經(jīng)知道了所有相關(guān)元素的寬度、偏移量等數(shù)據(jù)了。這在文檔首次載入時(shí)則不會(huì)發(fā)生,那時(shí)由于自動(dòng)擴(kuò)張的特性,寬度還無(wú)法確定。這種情況會(huì)導(dǎo)致在鼠標(biāo)經(jīng)過(guò)時(shí)頁(yè)面出現(xiàn)跳變。
這些和重排問題相關(guān)的 bug 會(huì)給百分比邊距和補(bǔ)白使用較多的流動(dòng)布局帶來(lái)不少麻煩。
MS專有的這個(gè) hasLayout 還會(huì)影響背景的定位和擴(kuò)展。比如,根據(jù) CSS 規(guī)范,background-position: 0 0
應(yīng)該指元素的“補(bǔ)白邊緣(padding edge)”。而在 IE/Win 下,如果 hasLayout = false
則指的是“邊框邊緣(border edge)”,當(dāng) hasLayout=true
時(shí)指的才是補(bǔ)白邊緣:
hasLayout
會(huì)影響一個(gè)盒子和其子孫的邊距重疊。根據(jù)規(guī)范,一個(gè)盒子如果沒有上補(bǔ)白和上邊框,那么它的上邊距應(yīng)該和其文檔流中的第一個(gè)孩子元素的上邊距重疊:
在 IE/Win 中如果這個(gè)盒子有 layout 那么這種現(xiàn)象就不會(huì)發(fā)生了:似乎擁有 layout 會(huì)阻止其孩子的邊距伸出包含容器之外。此外當(dāng) hasLayout = true
時(shí),不論包含容器還是孩子元素,都會(huì)有邊距計(jì)算錯(cuò)誤的問題出現(xiàn)。
hasLayout 會(huì)影響一個(gè)塊級(jí)別鏈接的鼠標(biāo)響應(yīng)區(qū)域(可點(diǎn)擊區(qū)域)。通常 hasLayout = false 時(shí)只有文字覆蓋區(qū)域才能響應(yīng)。而 hasLayout = true 則整個(gè)塊狀區(qū)域都可響應(yīng)。添加了 onclick/onmouseover 等事件的任意塊級(jí)元素也有同樣的現(xiàn)象。
當(dāng)使用 tab 在頁(yè)面中瀏覽時(shí),如果進(jìn)入了一個(gè)頁(yè)內(nèi)鏈接(in-page link),那么接下來(lái)再按的 tab 鍵就不會(huì)正常繼續(xù)了:
tab 鍵會(huì)把用戶帶到(這通常是錯(cuò)誤的)其最近的 layout 祖先中的第一個(gè)目標(biāo)(如果這個(gè)祖先是由 table
, div
, span
或某些別的標(biāo)簽構(gòu)成)。
IE/Win 中似乎有兩種分層和堆疊順序:
兩種堆疊模式雖互不相容,但卻共存于IE的渲染引擎中。經(jīng)驗(yàn)之談:調(diào)試的時(shí)候,兩種情況都要考慮到。我們可能會(huì)有規(guī)律地在下拉菜單或者類似的復(fù)雜菜單中看到相關(guān)問題,因?yàn)樗鼈兺鶢可娴蕉询B,定位和浮動(dòng)等諸多令人頭疼的問題。給那些 z-index 定位的元素 layout 是一種可能的修正方法,不過(guò)也不限于此,這里只是提醒一下。
如果給一個(gè) HTML 標(biāo)簽設(shè)定 contenteditable=true
屬性,比如body contenteditable=true>
,將會(huì)允許對(duì)該元素以及其 layout 子元素進(jìn)行實(shí)時(shí)的編輯、拖動(dòng)改變尺寸等操作。你可以把這屬性用在浮動(dòng)元素或者一個(gè)有序列表中的 layout 列表元素上看看效果。
為了對(duì)元素進(jìn)行操作(編輯它們),“contenteditable”和“hasLayout”為那些 hasLayout
返回 true
的元素引入了一套單獨(dú)的堆疊順序。
Editing Platform 繼承了 layout 概念,對(duì) layout 的誤解多是因 contenteditable 而起即可作為證明(那些某種程度上集成了IE編輯引擎的應(yīng)用軟件多暗含著對(duì)layout概念的某種強(qiáng)制向后兼容性)。
你的 MSIE 頁(yè)面在別的瀏覽器中一團(tuán)糟?我們可沒必要讓這種事情發(fā)生。如果使用恰當(dāng),任何好的瀏覽器都能擺平 MSIE 的頁(yè)面——只要你使用一些正確的 CSS。
利用 hasLayout
和“新的塊級(jí)格式內(nèi)容”之間的細(xì)微相似之處,我們可以有幾種方法在標(biāo)準(zhǔn)兼容瀏覽器中重新實(shí)現(xiàn) hasLayout
的“包含浮動(dòng)元素”效果,和一些“浮動(dòng)元素旁邊的元素”所特有的效果。
某些 doctype,或者 xml>
聲明,在 IE6 中會(huì)觸發(fā)“quirks模式”或曰向后兼容模式。在這種模式下,IE6 就像 IE5.5,并且和它老弟擁有一樣的bug,一樣的問題和一樣的行為。
而對(duì)于IE7,xml>
聲明不會(huì)再改變渲染模式了;要觸發(fā) quirks 模式,我們不得不插入一個(gè)注釋才行。(IE7 的 quirks 模式和 IE6 的 quirks 模式是否一樣還有待驗(yàn)證)
?xml version="1.0" encoding="utf-8"?> !-- ... 讓 IE7 運(yùn)行在 quirks 模式 --> !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
整個(gè) layout 概念和一些基本 CSS 概念是不兼容的,即包含,排列,浮動(dòng),定位和層疊等。
由于頁(yè)面中元素或有或沒有 layout,會(huì)導(dǎo)致 IE/Win 的行為和 CSS 規(guī)范相違背。
IE 的對(duì)象模型看起來(lái)是文檔模型和他們傳統(tǒng)的應(yīng)用程序模型的糅合。我之所以提到這點(diǎn)是因?yàn)樗鼘?duì)于理解IE如何渲染頁(yè)面很重要。而從文檔模型切換到應(yīng)用程序模型的開關(guān)就是給一個(gè)元素“l(fā)ayout”。
(Dean Edwards)
有時(shí)候要解釋清楚某種行為是不可能的:就比如 hasLayout,會(huì)根據(jù)它的狀態(tài)選擇兩種不同渲染引擎的一種使用,而且每一種都有其自己的 bug 和怪異之處。
軟件 bug 是由于在制作過(guò)程中對(duì)完整性和邏輯問題考慮不周等人為錯(cuò)誤而導(dǎo)致的。這是人類的固有缺陷,目前還沒有什么好的解決方法。
同樣由于這種缺陷,任何試圖不重寫軟件而修復(fù) bug 的做法,都將會(huì)不可避免的導(dǎo)致軟件中出現(xiàn)更復(fù)雜的bug。
所有依賴別的軟件的軟件——當(dāng)然包括依賴操作系統(tǒng),也會(huì)同樣依賴他們的 bug。于是我們會(huì)從所有關(guān)聯(lián)的軟件中得到一連串的 bug,這也更說(shuō)明找到一個(gè)無(wú) bug 軟件是幾乎不可能的。
(Molly, the cat?)
本文創(chuàng)建于2005年6月30日,最后一次修改于2006年4月2日。
標(biāo)簽:滄州 海西 佛山 欽州 泰州 呂梁 攀枝花 仙桃
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《轉(zhuǎn)載:On having layout》,本文關(guān)鍵詞 轉(zhuǎn)載,having,layout,轉(zhuǎn)載,having,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。