主頁 > 知識(shí)庫 > 轉(zhuǎn)載:On having layout

轉(zhuǎn)載:On having layout

熱門標(biāo)簽:外呼系統(tǒng)號(hào)碼顯示 地圖標(biāo)注多家店 無錫電銷外呼系統(tǒng)代理 什么行業(yè)需要電話機(jī)器人 中山外呼系統(tǒng)中間件 天津企業(yè)外呼系統(tǒng)代理商 廣州ai外呼系統(tǒng)業(yè)務(wù) 南昌crm外呼系統(tǒng)如何 車載電話機(jī)器人
譯者注:一篇很好的文章,很久以前在blog上就推薦過,這兩天斷斷續(xù)續(xù)花了點(diǎn)時(shí)間翻譯了一下,推薦讀讀。英文原文在此。

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

  引用一段來自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 中有很多奇怪的渲染問題可以通過賦予其“l(fā)ayout”得到解決。John Gallant 和 Holly Bergevin 把這些問題歸類為“尺寸bug(dimensional bugs)”,意思是這些 bug 可以通過賦予相應(yīng)元素某個(gè)寬度或高度解決。這便引出關(guān)于“l(fā)ayout”的一個(gè)問題:為什么它會(huì)改變?cè)氐匿秩咎匦?,為什么它?huì)影響到元素之間的關(guān)系?這個(gè)問題問得很好,但卻很難回答。在這篇文章中,我們專注于這個(gè)復(fù)雜問題會(huì)有那些方面的表現(xiàn),某一方面的具體討論和范例請(qǐng)參考文中給出的相關(guān)鏈接。

hasLayout — 定義

  “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 元素中與身俱來,而在另外一些元素中也可以通過一些 CSS 屬性將其觸發(fā)為 true ,且一旦觸發(fā)將不可逆轉(zhuǎn)。

術(shù)語

  當(dāng)我們說一個(gè)元素“擁有l(wèi)ayout”或“得到layout”,或者說一個(gè)元素“has layout” 的時(shí)候,我們的意思是指它的微軟專有屬性 hasLayout 被設(shè)為了 true 。一個(gè)“l(fā)ayout元素”可以是一個(gè)默認(rèn)就擁有 layout 的元素或者是一個(gè)通過設(shè)置某些 CSS 屬性得到 layout 的元素。

  而“無layout元素”,是指 hasLayout 未被觸發(fā)的元素,比如一個(gè)未設(shè)定寬高尺寸的干凈 div 元素就可以做為一個(gè) “無layout祖先”。

  給一個(gè)默認(rèn)沒有 layout 的元素賦予 layout 的方法包括設(shè)置可觸發(fā) hasLayout = true 的 CSS 屬性。參考默認(rèn) layout 元素以及這些屬性列表。沒有辦法設(shè)置 hasLayout = false , 除非把一開始那些觸發(fā) hasLayout = true 的 CSS 屬性去除。

問題種種

  hasLayout 的問題不管新手還是老手,不管設(shè)計(jì)師或者程序員可能都遇到過。具有 layout 的元素通常有著不同尋常而且難以預(yù)料的的顯示效果,而且有時(shí)甚至?xí)窟B到他們的孩子元素。

  一個(gè)元素是否具有“l(fā)ayout”可能會(huì)引發(fā)如下的一些問題:

  • IE 很多常見的浮動(dòng) bug 。
  • 元素本身對(duì)一些基本屬性的異常處理問題。
  • 容器和其子孫之間的邊距重疊(margin collapsing)問題。
  • 使用列表時(shí)遇到的諸多問題。
  • 背景圖像的定位偏差問題。
  • 使用腳本時(shí)遇到的瀏覽器之間處理不一致的問題。

  上面的列表只是列出一個(gè)大概,也不完善。下面的文章將盡可能詳細(xì)徹底的描述有無“l(fā)ayout”所帶來的各種問題。

Layout 從何而來

  不同于標(biāo)準(zhǔn)屬性,也不像某些瀏覽器的私有 CSS 屬性,layout 無法通過某一個(gè) CSS 聲明直接設(shè)定 。也就是說沒有“l(fā)ayout屬性”這么一個(gè)東西,元素要么本身自動(dòng)擁有 layout,要么借助一些 CSS 聲明悄悄地獲得 layout。

默認(rèn)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
絕對(duì)定位元素的包含區(qū)塊(containing block)就會(huì)經(jīng)常在這一方面出問題。
float: left|right
由于 layout 元素的特性,浮動(dòng)模型會(huì)有很多怪異的表現(xiàn)。
display: inline-block
當(dāng)一個(gè)內(nèi)聯(lián)級(jí)別的元素需要 layout 的時(shí)候往往就要用到它,這也可能也是這個(gè) CSS 屬性的唯一效果——讓某個(gè)元素?fù)碛?layout?!癷nline-block行為”在IE中是可以實(shí)現(xiàn)的,但是非常與眾不同: IE/Win: inline-block and hasLayout 。
width: 任意值
很多人遇到 layout 相關(guān)問題發(fā)生時(shí),一般都會(huì)先嘗試用這個(gè)來修復(fù)。
height: 任意值
height: 1% 就在 Holly Hack 中用到。
zoom: 任意值 (MSDN)
MS專有屬性,無法通過校驗(yàn)。 不過 zoom: 1 可以臨時(shí)用做調(diào)試。
writing-mode: tb-rl (MSDN)
MS專有屬性,無法通過校驗(yàn)。

  在 IE7 中,overflow 也變成了一個(gè) layout 觸發(fā)器:

overflow: hidden|scroll|auto
這個(gè)屬性在之前版本 IE 中沒有觸發(fā) layout 的功能。
overflow-x|-y: hidden|scroll|auto
overflow-x 和 overflow-y 是 CSS3 盒模型中的屬性,尚未得到瀏覽器的廣泛支持。他們?cè)谥鞍姹綢E中沒有觸發(fā) layout 的功能。

  另外 IE7 的熒幕上又新添了幾個(gè) haslayout 的演員,如果只從 hasLayout 這個(gè)方面考慮,min/max 和 width/height 的表現(xiàn)類似,position 的 fixed 和 absolute 也是一模一樣。

position: fixed
./.
min-width: 任意值
就算設(shè)為0也可以讓該元素獲得 layout。
max-width: 除 none 之外的任意值
./.
min-height: 任意值
即使設(shè)為0也可以讓該元素的 haslayout=true
max-height: 除 none 之外的任意值
./.

  以上結(jié)論借助 IE Developer Toobar 以及預(yù)先測(cè)試得出。

有關(guān)內(nèi)聯(lián)級(jí)別元素

  對(duì)于內(nèi)聯(lián)元素(可以是默認(rèn)即為內(nèi)聯(lián)的比如 span 元素,也可以是 display: inline 的元素)

  • widthheight 只在 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)中所說的 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

  我們這里稱 hasLayout 為“腳本屬性”是為了和我們熟知的 CSS 屬性相區(qū)別。

  注意一旦一個(gè)元素?fù)碛辛?layout,就沒有辦法再將其設(shè)成 hasLayout = False 了。

  hasLayout-property 可以用來檢測(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”。 我們可以通過實(shí)時(shí)修改一個(gè)元素的屬性將“zoom(css)”設(shè)置為“1”來觸發(fā) hasLayout 以便調(diào)試。

  另外一個(gè)需要注意的是“l(fā)ayout”會(huì)影響腳本編程。如果一個(gè)元素沒有“l(fā)ayout”,那么clientWidth/clientHeight 總是返回0。這會(huì)讓一些腳本新手感到困惑,而且這和 Mozilla 瀏覽器的處理方式也不一樣。不過我們可以利用這一點(diǎn)在 IE5.0 中檢測(cè)“l(fā)ayout”:如果 clientWidth 是零那么這個(gè)元素就沒有 layout。

CSS hacks

  下面用于觸發(fā) haslayout 的 hack 已經(jīng)經(jīng)過 IE6 及以下版本測(cè)試。今后版本的IE有可能會(huì)對(duì)此做不同處理。如果新版本瀏覽器發(fā)布我們會(huì)重新整理這部分內(nèi)容。

  John Gallant 和 Holly Bergevin 在2003年發(fā)布的 Holly hack :

/* \*/
* html .gainlayout { height: 1%; }
/* */	
  • 可以讓 IE5+ 的任意元素獲得 layout,除了標(biāo)準(zhǔn)兼容模式 IE6 中的內(nèi)聯(lián)元素。
  • 一般都很有效,除了在某些極少情況下,需要用 height:0 或者 1px 更好一些。
  • 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: 01px —— 并主張始終使用 height 除非它和別的什么東西沖突 (overflow: hidden)。對(duì)于取值,我們則傾向于避免 1% ,因?yàn)樗赡軙?huì)(雖然很少)引起一些問題。

  一個(gè)需要注意的情況是如果我們希望一個(gè)元素保持內(nèi)聯(lián),那么就不能使用 height 了,這時(shí)可以用 display: inline-block 。我們只在早期調(diào)試階段用 zoom: 1 來避免一些渲染錯(cuò)誤。

  我們?cè)催^一些把 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;}。所謂過猶不及,獲得 layout 不等于獲得靈丹妙藥,它只是用來改變渲染模式。

Hack整理

  但是瀏覽器總是會(huì)變的,我們需要面對(duì)很多問題,比如一些依賴 IE6 的 bug 所做的 hack 會(huì)在 IE7 或更高版本的新瀏覽器中因 bug 修復(fù)而失效(甚至有害)的問題;比如新版本瀏覽器中類似的布局 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+ 的任何元素(包括內(nèi)聯(lián)元素)獲得 layout,但是在 IE5.0 中無效。
  • 沒有其他附帶效果(內(nèi)聯(lián)元素會(huì)變成 inline-block,這個(gè)當(dāng)然)。
  • 如果需要通過驗(yàn)證,應(yīng)該用條件注釋將 zoom 隱藏起來。

  其實(shí)當(dāng)我們考慮到“向后兼容”時(shí)是很自相矛盾的,我們強(qiáng)烈建議頁面設(shè)計(jì)者回過頭看一下自己頁面中用的到的明顯的或是不明顯的“hacks”,并用條件注釋針對(duì)不同瀏覽器重新處理以保萬無一失。

關(guān)于IE Mac 的小問題

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

MSDN 文檔

  MSDN 中涉及到 hasLayout 這個(gè) MS 屬性的地方寥寥無幾,而具體解釋 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)元素上的。換句話說,“擁有l(wèi)ayout”就可以粗略理解成:“可以擁有這幾個(gè)屬性”。

  MSDN 上仍然使用 layout 屬性這種說法, 只是含義變了,它們和擁有 layout 的元素已經(jīng)沒有什么關(guān)系了。在 IE5.5 中方才引入了 MS 的這個(gè)專有屬性 hasLayout,也只是某種內(nèi)部的標(biāo)志位而已。

  在 IE5.5 中,MSHTML Editing Platform(即可以通過設(shè)置body contenteditable=true>來允許用戶實(shí)時(shí)編輯、拖動(dòng) layout 元素以及調(diào)整其尺寸等)的文檔中描述了三個(gè)和 layout 相關(guān)的重要特性:

  如果一個(gè) layout 元素中有內(nèi)容,內(nèi)容的排版布局將由它的邊界矩形框決定。

  擁有 layout 的意思基本上就是表示某元素是一個(gè)矩形。

  從內(nèi)部來說,擁有 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] 打開了深入討論的大門:

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

(HasLayout概述)

分析

  我們的分析試圖解釋在已知案例下發(fā)生了什么事情,這種分析也應(yīng)該可以作為未知案例下的指導(dǎo)。但我們這種試圖利用種種測(cè)試案例投石探路的黑箱測(cè)試方法,是注定無法消除黑箱的神秘感的——我們無法回答“為什么”的問題。我們只能去嘗試了解整個(gè)“hasLayout”模式的工作框架,以及它會(huì)怎樣影響網(wǎng)頁文檔的渲染。因此,最終我們只能提供一些指導(dǎo)方針(而且只能是指導(dǎo)方針,而不是絕對(duì)的解決方案)。

  我們認(rèn)為他們所指的是一個(gè)小窗體。一個(gè) layout 元素的內(nèi)部?jī)?nèi)容是完全獨(dú)立的,而且也無法影響其邊界外的任何內(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 的“頁面”模式,從符號(hào)學(xué)角度考慮,可以看做是由很多互不相關(guān)的小的區(qū)塊構(gòu)成,而 HTML 和 W3C 的模式則認(rèn)為“頁面”模式應(yīng)該是敘述完備的,故事性的相關(guān)信息區(qū)塊構(gòu)成的。

各種情況的詳細(xì)說明

清除浮動(dòng)和自動(dòng)擴(kuò)展適應(yīng)高度

  浮動(dòng)元素會(huì)被 layou 元素自動(dòng)包含。這是很多新手經(jīng)常遇到的問題:在 IE 下完成的頁面到了標(biāo)準(zhǔn)兼容瀏覽器下所有未清除的浮動(dòng)元素都伸出了其包含容器之外。

  • Containing Floats
  • how to clear floats without structural markup

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

  • acidic float tests

  在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 無法影響其 layout 包含容器之外的 float 元素。如果依賴這個(gè) bug 在 IE 中布局的頁面要轉(zhuǎn)到標(biāo)準(zhǔn)兼容瀏覽器中,只有全部重做。

  更多相關(guān)信息查看本文 “和 CSS 規(guī)范類似的地方” 這一部分。

浮動(dòng)元素旁邊的元素

  當(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ì)于沒有交叉的二維空間中的矩形而言這是無法實(shí)現(xiàn)的。

  可以(再次)訪問下面這個(gè)頁面:

  • three pixel text-jog

  我們可以看到跟在一個(gè)浮動(dòng)元素后的 layout 元素不會(huì)顯示這個(gè)3px間隙的 bug,因?yàn)楦?dòng)元素外圍的3px硬邊無法影響一個(gè) layout 元素的內(nèi)部?jī)?nèi)容,所以這個(gè)硬邊將整個(gè) layout 元素右推了3px。好比一個(gè)防護(hù)罩,layout 可以保護(hù)其內(nèi)部?jī)?nèi)容不受影響,但是浮動(dòng)元素的力量卻將整個(gè)防護(hù)罩推了開來。

  更多相關(guān)信息查看本文 “和 CSS 規(guī)范類似的地方” 這一部分

列表

  無論是列表本身(ol, ul) 還是單個(gè)的列表元素(li),擁有 layout 后都會(huì)影響列表的表現(xiàn)。不同版本 IE 的表現(xiàn)又有不同。最明顯的效果就體現(xiàn)在列表符號(hào)上(如果你的列表自定義了列表符號(hào)則不會(huì)受這個(gè)問題影響)。這些符號(hào)很可能是通過某種內(nèi)部機(jī)制附到列表元素上的(通常是附著在它們外面)。不幸的是,由于是通過“內(nèi)部機(jī)制”添加的,我們無法訪問它們也無法修正它們的錯(cuò)誤表現(xiàn)。

  最明顯的效果有:

  • 列表獲得 layout 后,列表符號(hào)會(huì)消失或者被放置在不同的或者錯(cuò)誤的位置。

  有時(shí)它們又可以通過改變列表元素的邊距而重新出現(xiàn)。這看起來似乎是以下事實(shí)導(dǎo)致的結(jié)果:layout 元素會(huì)試圖裁掉超出其邊界的內(nèi)部?jī)?nèi)容。

  • 列表元素獲得 layout 之后,會(huì)有和上面一樣的問題出現(xiàn),更多參考 (extra vertical space between list items)

  進(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ì)齊)。

  以上某些問題還是無法解決的,所以如果需要列表符號(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ì)帶來很多問題(一些計(jì)算方面的錯(cuò)誤)。另外在IE5.5和IE6的quirks模式下還有一些別的需要注意的情況。

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

  注意,由于 position: relative 并不觸發(fā) hasLayout,所以很多諸如內(nèi)容消失或錯(cuò)位的渲染錯(cuò)誤就會(huì)因此而起。這些現(xiàn)象可能會(huì)在刷新頁面、調(diào)整窗口大小、滾動(dòng)頁面、選中內(nèi)容等情況下出現(xiàn)。原因是 IE 在據(jù)這個(gè)屬性對(duì)元素做偏移處理時(shí),卻似乎忘了發(fā)出信號(hào)讓其 layout 孩子元素進(jìn)行“重繪”(而如果是一個(gè)layout元素,那么在其重繪事件的信號(hào)鏈中,這個(gè)傳給其孩子的信號(hào)是會(huì)正常發(fā)出的)。

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

  以上是一些相關(guān)問題的描述。作為經(jīng)驗(yàn)之談,相對(duì)定位一個(gè)元素時(shí)最好給予其 layout。再有,我們也需要檢查擁有這種結(jié)構(gòu)的父元素是否也需要 layout 或者position: relative亦或二者都需要,如果涉及到浮動(dòng)元素這點(diǎn)就十分重要。

絕對(duì)定位元素(a.p.):
包含區(qū)塊,什么是包含區(qū)塊?

  理解 CSS 的包含區(qū)塊概念很重要,它回答了絕對(duì)定位元素是相對(duì)哪里定位的問題:包含區(qū)塊決定了偏移起點(diǎn),包含區(qū)塊定義了百分比長(zhǎng)度的計(jì)算參考。

  對(duì)于絕對(duì)定位元素,包含區(qū)塊是由其最近的定位祖先決定的。如果其祖先都沒有被定位,那么就使用初始包含區(qū)塊 html。

  通常情況下我們會(huì)用 position: relative 來設(shè)定任意包含區(qū)塊。這就是說,我們可以讓一個(gè)絕對(duì)定位元素所參考的原點(diǎn)和長(zhǎng)度等不依賴于元素的排列順序,這可以滿足諸如“內(nèi)容優(yōu)先”這種可訪問性概念的需要,也可以給復(fù)雜的浮動(dòng)布局帶來方便。

  但是由于 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è)無 layout 的父元素被相對(duì)定位了——我們就得給它賦予 layout 才能使偏移量起作用:

  • Absolutely Buggy II

  假設(shè)一個(gè)未定位的父元素需要特定尺寸,而且頁面設(shè)計(jì)是基于百分比寬度的——我們就可以放棄這個(gè)想法了,因?yàn)闉g覽器支持不佳:

  • absolutely positioned element and percentage width
濾鏡

  MS專有的濾鏡屬性 filter 是只適用于 layout 元素的。有些濾鏡擴(kuò)展了對(duì)象的邊界。它們會(huì)顯示出自身特有的缺陷。

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

  當(dāng)所有元素都已渲染完成時(shí),如果有一個(gè)因鼠標(biāo)經(jīng)過而引起的變化產(chǎn)生(比如某個(gè)鏈接的 background 有變化),IE會(huì)對(duì)其 layout 包含區(qū)塊進(jìn)行重排。有時(shí)一些元素就會(huì)因此被排到了新的位置,因?yàn)楫?dāng)這個(gè)鼠標(biāo)經(jīng)過發(fā)生時(shí),IE已經(jīng)知道了所有相關(guān)元素的寬度、偏移量等數(shù)據(jù)了。這在文檔首次載入時(shí)則不會(huì)發(fā)生,那時(shí)由于自動(dòng)擴(kuò)張的特性,寬度還無法確定。這種情況會(huì)導(dǎo)致在鼠標(biāo)經(jīng)過時(shí)頁面出現(xiàn)跳變。

  • Jump on :hover
  • quirky percentages: the reflow

  這些和重排問題相關(guān)的 bug 會(huì)給百分比邊距和補(bǔ)白使用較多的流動(dòng)布局帶來不少麻煩。

背景原點(diǎn)

  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ǔ)白邊緣:

  • Background, Border, hasLayout
邊距重疊

  hasLayout 會(huì)影響一個(gè)盒子和其子孫的邊距重疊。根據(jù)規(guī)范,一個(gè)盒子如果沒有上補(bǔ)白和上邊框,那么它的上邊距應(yīng)該和其文檔流中的第一個(gè)孩子元素的上邊距重疊:

  • Collapsing Margins
  • Uncollapsing Margins

  在 IE/Win 中如果這個(gè)盒子有 layout 那么這種現(xiàn)象就不會(huì)發(fā)生了:似乎擁有 layout 會(huì)阻止其孩子的邊距伸出包含容器之外。此外當(dāng) hasLayout = true 時(shí),不論包含容器還是孩子元素,都會(huì)有邊距計(jì)算錯(cuò)誤的問題出現(xiàn)。

  • Margin collapsing and hasLayout

  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)象。

  • Block anchors and hasLayout
在頁面內(nèi)使用鍵盤瀏覽:探索中

  當(dāng)使用 tab 在頁面中瀏覽時(shí),如果進(jìn)入了一個(gè)頁內(nèi)鏈接(in-page link),那么接下來再按的 tab 鍵就不會(huì)正常繼續(xù)了:

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

  tab 鍵會(huì)把用戶帶到(這通常是錯(cuò)誤的)其最近的 layout 祖先中的第一個(gè)目標(biāo)(如果這個(gè)祖先是由 tablediv, span 或某些別的標(biāo)簽構(gòu)成)。

堆疊,分層和 layout

  IE/Win 中似乎有兩種分層和堆疊順序:

  • 一種是(偽)試圖采用CSS的模式:Effect of z-index value to RP and AP blocks
  • 還有一種是由“hasLayout”及其孿生兄弟“contenteditable”的行為產(chǎn)生的堆疊順序。正如在上面相對(duì)定位的例子中展現(xiàn)的那樣,在 layout 影響下的堆疊現(xiàn)象就好像 Harry Houdini (譯者注:魔術(shù)師,以紙牌魔術(shù)成名)的拿手戲法兒一樣。

  兩種堆疊模式雖互不相容,但卻共存于IE的渲染引擎中。經(jīng)驗(yàn)之談:調(diào)試的時(shí)候,兩種情況都要考慮到。我們可能會(huì)有規(guī)律地在下拉菜單或者類似的復(fù)雜菜單中看到相關(guān)問題,因?yàn)樗鼈兺鶢可娴蕉询B,定位和浮動(dòng)等諸多令人頭疼的問題。給那些 z-index 定位的元素 layout 是一種可能的修正方法,不過也不限于此,這里只是提醒一下。

混亂的 contenteditable

  如果給一個(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)制向后兼容性)。

  • More on contenteditable

和 CSS 規(guī)范類似的地方

  你的 MSIE 頁面在別的瀏覽器中一團(tuán)糟?我們可沒必要讓這種事情發(fā)生。如果使用恰當(dāng),任何好的瀏覽器都能擺平 MSIE 的頁面——只要你使用一些正確的 CSS。

  利用 hasLayout 和“新的塊級(jí)格式內(nèi)容”之間的細(xì)微相似之處,我們可以有幾種方法在標(biāo)準(zhǔn)兼容瀏覽器中重新實(shí)現(xiàn) hasLayout 的“包含浮動(dòng)元素”效果,和一些“浮動(dòng)元素旁邊的元素”所特有的效果。

  • Reverse engineering series
  • Simulations

Quirks 模式

  某些 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">

Layout — 結(jié)論

  整個(gè) layout 概念和一些基本 CSS 概念是不兼容的,即包含,排列,浮動(dòng),定位和層疊等。

  由于頁面中元素或有或沒有 layout,會(huì)導(dǎo)致 IE/Win 的行為和 CSS 規(guī)范相違背。

擁有 layout — 另外一個(gè)引擎?

  IE 的對(duì)象模型看起來是文檔模型和他們傳統(tǒng)的應(yīng)用程序模型的糅合。我之所以提到這點(diǎn)是因?yàn)樗鼘?duì)于理解IE如何渲染頁面很重要。而從文檔模型切換到應(yīng)用程序模型的開關(guān)就是給一個(gè)元素“l(fā)ayout”。

(Dean Edwards)

  有時(shí)候要解釋清楚某種行為是不可能的:就比如 hasLayout,會(huì)根據(jù)它的狀態(tài)選擇兩種不同渲染引擎的一種使用,而且每一種都有其自己的 bug 和怪異之處。

不可消除的 bug

  軟件 bug 是由于在制作過程中對(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,這也更說明找到一個(gè)無 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)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《轉(zhuǎn)載:On having layout》相關(guān)的同類信息!
  • 本頁收集關(guān)于轉(zhuǎn)載:On having layout的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章