[CSS] IE hasLayout
YehYeh\'s Notepad yehyeh@gmail.com 

Has Layout概述

本文翻譯自Microsoft MSDN "HasLayout" Overview
採重點式翻譯,並非依順序逐字翻譯,若有錯誤或不清楚的地方請參考原文。

什麼是HasLayout? HasLayout為什麼重要?

  • Internet Explorer(IE)上有多個因a layout(IE內部的一種資料結構)而引起的bug
    • 像是尺寸問題或是Holly hack
  • 大部份的使用者不需要知道a layout的含意
  • 本文將說明當一個元素has a layout時會發生什麼,且有什麼含意
  • 元素(Element)可以分成兩類
    • 元素依據父元素來決定尺寸和位置
    • 元素自行決定尺寸和位置
  • 元素在IE的動態HTML引擎一般不會自行決定其位置
  • div或p元素的位置會依出現在原始檔中的順序決定
    • div或p的內容會依據其最接近的一個擁有a layout的祖先元素(通常是body)來決定位置
    • div或p的子孫元素會依據祖先元素的layout來決定大小和定位
    • 負責決定元素的大小和位置的可能是元素的祖先元素,不一定是元素的父元素
    • 不必每個元素都有layout的好處是效能和簡單
Δ 回到最上方

具有Layout有什麼含意?

  • 具有layout代表一個元素負責決定其自身的大小和位置
    • 也可能負責其子孫元素的大小和位置
    • 如果子元素有layout,則子元素及其子孫元素的大小和位置由子元素負責
  • 一些元素有固定的大小,或是有特殊的大小限制
    • 這種元素一定會有layout
    • 像buttons, images, inputs, selects, marquee,即使沒有指定width, height,也一定會有基本的大小
  • 一些元素(如div, span)一般不需要layout
    • 有時為了某種需求,需要賦予其layout屬性
    • 例如為了讓元素有Scrollbar,所以要讓元素有layout屬性
  • layout的元素,會有一個hasLayout旗標被設為true
Δ 回到最上方

為什麼具有Layout很重要?

  • layout會限制元素的形狀為矩形
    • 所以元素的內容無法浮貼在其它的矩形元素 無法文繞圖
    • 換句話說,在IE的引擎中,浮動元素不能超過layout的邊界
  • 具有layout的元素會建立一個新的區塊內容(9.4.1 in the CSS 2.1 spec)
  • layout是一個額外的快取物件,用來輔助元素大小和位置計算的演算法
    • layout會增加記憶體及效能下降
  • 自動調整大小(auto-sizing)的副作用:
    • layout的元素無法縮小以符合其子元素
    • 例如一個設定為絕對定位(position:absolute)的元素裡有一個且具有layout的元素,有layout的元素不會自動縮小以符合其子元素的大小
  • Layout產生的矩形會自動變大以符合其內文(IE6中的height bug)
    • 補充:假設指定一個hasLayout的div width為50px,而其內文的寬度為100px
      div width會變成100px
  • 很多人都用過layout來解決IE 6的bug,特別是相對定位的元素
    • 但相對定位(Relative Positioned)元素不需要layout
    • 這種情況下,還可能會受layout的副作用影響,產生另外的問題
Δ 回到最上方

那些元素一定會具有Layout?

  • 廣義而言,任何具有基本寬度的元素且需要維護特定資訊和功能,以定位和渲染其內容到基本寬度中的元素都應具有layout
    1. Images
    2. Tables
    3. TableRows
    4. TableCells
    5. HR
    6. Input elements: text, button, file, select
    7. Marquee
    8. Framesets, Frames
    9. Objects, applets, plugins
    10. Absolute positioned elements
    11. Floated elements
    12. Inline-block elements
    13. Filters (rotation, dropshadow, etc.)
    14. Body (和嚴格模式(Strict Mode)中的HTML元素)
Δ 回到最上方

那些元素可以取得Layout?

  • 嚴格模式(Strict Mode)下,區塊級(Block Level)元素有指定widthheight
  • 相容模式(Compat Mode)下,任意有指定widthheight的元素
  • 有設定zoom屬性的元素
  • 編輯模式(Edit Mode)中的元素
  • Elements that host to a viewlinked behavior
  • 浮動方向和父元素不同的元素
Δ 回到最上方

Layout Hacks的範例

  • 這個鏈結提供一份清單,可以解決產生layout且不引起視覺上的改變
  • 如果你觀看或使用這些解決,請注意它們的含意(感謝Ingo Chao和這份清單的編輯們~)
  • 情境1:文繞圖(Floating)
    • 看一下下面的標記:
      <div style="float:left; border: 2px solid red"> 123</div>
         <span style="border: 2px solid blue">
               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>
      /pre>
      			
    • 預期畫面為:
      Bb250481.HasLayout_1(en-us,VS.85).gif
      • 注意,預期文字是緊密的靠在左邊浮動的div
      • 這裡的框線用來展示span的盒子模式
    • 如果讓span具有layout時,裡面的文字會發生什麼事?
      <style>
           .gainlayout {zoom: 1;}
      </style>
      .
      .
      .
      <span class="gainlayout" style="border: 2px solid blue">
      
      Bb250481.HasLayout_2(en-us,VS.85).gif
      • span具有layout時會變成矩形
      • span裡的文子不再緊靠著div,這很重要,因為它破壞了預期的版面(想像你把讓p標籤具有layout)
  • 情境2:自動大小(Auto-sizing)
    <div style="position: absolute; background:red">
       <div>
          123
       </div>
    </div>
    
    • 預期為:
      Bb250481.HasLayout_3(en-us,VS.85).gif
      • 第一個div為絶對定位到包含它的區塊(這裡是指viewport),div不在自然的版面流中
      • 紅色的背景色自動縮放成"123"的大小,而位置由其絕對定位的父元素決定
    • 如果讓div具有layout時,裡面的"123"會發生什麼事?
      <style>
        .gainlayout {zoom: 1;}
      </style>
      
      <div style="position: absolute; background:red">
         <div class="gainlayout">
            123
         </div>
      </div>
      
      Bb250481.HasLayout_4(en-us,VS.85).gif
      • div擁有自己的layout且完全忽視其父元素的任何要求
      • 由父元素引起的緊縮包裝(Shink Wrap)的動作完全不見了
      • 如果你讓一個元素擁有layout,你應該要知道這個副作用
  • 情境3:相對定位(Position:relative)
    <div style="position: relative; border: 2px solid blue">
       <div style="float:left; border: 2px solid red">
          <img style="position: relative; border: 2px solid green; width:100px; height:100px" 
             src="slider.jpg">
       </div>
    </div>		
    
    • 我們期望IE會產生下面的結果
      • 一條緊縮的4px藍線(因為子孫元素被移到版面流外)
      • 一個紅色浮動的盒子,含住一張有綠色框線的圖片
      Bb250481.HasLayout_5(en-us,VS.85).gif
    • 但在IE6中,你會驚訝的得到: Bb250481.HasLayout_6(en-us,VS.85).gif
    • 這發生了什麼事?
      • 因為圖片是相對定位,所以需要父元素的layout來決定圖片的位置
      • layout的父元素是一個向左浮動的div
      • IE6的相對定位計算程式很脆弱(這個bug在IE7中已修復),且其父元素的layout導致在計算圖片位置的時候錯誤
      • 你可能已經注意到緊縮到的藍線沒有正常的穿過紅框的頂端
        • 這是由於Has Layout造成的位移
        • 因為浮動的元素具有layout形成的矩形,所以不能被div的藍框線所穿過
        • 這是IE6內部的一個bug
    • 一般我們會讓藍框線的div也具有layout來解決這個問題
      <style>
        .gainlayout {zoom: 1;}
      </style>
      
      <div class="gainlayout" style="position: relative; border: 2px solid blue">
      
    • 看起來會變成: Bb250481.HasLayout_7(en-us,VS.85).gif
    • 優點:
      • 圖片顯示的位置正常(最外層的layout使float和image的位置正確計算)
    • 缺點:
      • div的Layout具有我們不希望的副作用
        • 藍色框線不在緊縮,但layout造成一個矩形,圍住float和image
        • 在float外圍的文字會被阻隔開來
        • 在這個例子上處理是很簡單的,但如果一個頁面上有50組這類的案例需要處理就...
    • 在這個情境中,沒什麼其它可作的(除了移除非必要的position:relative敘述)
  • 我們不是想打擊用hasLayout來解決IE6 Bug的解決,只是想闡述會引發的其它問題
  • 理想上,這些問題都應該被修正,即使不在IE7,也應在之後的版本被修正...
Δ 回到最上方