RD8004: IE6 IE7 IE8(Q) 中浮動元素寬度的 shrink-to-fit 算法與標準規定的算法不同

標準參考

如果一個浮動元素的 'width' 是 'auto',並且它是一個非替換元素,那麼它的寬度將會是shrink-to-fit。

shrink-to-fit的計算公式:min(max(preferred minimum width, available width), preferred width)

CSS2.1 並未給出 preferred minimum width、available width 和 preferred width 確切算法,通常,將內容中非明確的換行外的其他部分強制不換行來計算 preferred width;反之,嘗試將內容儘可能的換行,以得到 preferred minimum width;available width 即該元素的包含塊的寬度減去 'margin-left','border-left-width','padding-left','padding-right','border-right-width','margin-right' 的值以及任何存在的縱向滾動條的寬度。

關於浮動非替換元素寬度計算的詳細資料,請參考 CSS2.1 規範 10.3.5 Floating, non-replaced elements 中的內容。

問題描述

在 IE6 IE7 IE8(Q) 中,如果一個浮動元素的寬度是 shrink-to-fit,該元素的最終寬度可能比預期的小,並被儘可能的向上佈局。

造成的影響

這個問題將導致一些元素在各瀏覽器中的實際尺寸不一致,在有些瀏覽器中可能發生佈局混亂的現象。

受影響的瀏覽器

IE6 IE7 IE8(Q)  

問題分析

分析以下代碼:

<div id="Container" style="width:300px; background:lightgrey; font:14px Consolas; overflow:auto;">
    <div id="Placeholder_150" style="float:left; width:150px; height:30px; background:dimgray;"></div>
    <div id="Placeholder_100" style="clear:both; float:left; width:100px; height:30px; background:black;"></div>
    <div id="STF" style="float:left; background:url(x.gif);">
        <span id="A" style="background:darkgray;">background_darkgray</span>
        <span id="B" style="background:gray;">background_gray</span>
        <span id="C" style="background:dimgray;">background_dimgray</span>
    </div>
</div>
  • Container 是容器,設置寬度爲 300px 的目的是限制 STF 的最大寬度。設置 'overflow:auto' 是爲了使其創建 block formatting context 並自動容擴展高度容納其內容,以便於查看其尺寸。設置了一個等寬字體(14px 的 Consolas 字體的每個英文字符的尺寸爲 8px * 17px)的目的是爲了便於計算 ABC 的寬度。
  • Placeholder_150 是一個 150px * 30px 的左浮動元素,事實上可以使用 'float:right' 來替代本例中的 'float:left'。放置這個元素的目的是用來佔位,以更直觀的測試 IE6 IE7 IE8(Q) 中 STF 寬度算法的問題。
  • Placeholder_100 是一個 100px * 30px 的左浮動元素,它也可以是一個右浮動元素。其作用與 Placeholder_150 相同。
  • STF 是一個沒有設置width(默認值是auto)的左浮動元素,事實上可以使用 'float:right' 來替代本例中的 'float:left',關鍵點在於:它是一個寬度爲 shrink-to-fit 的浮動元素。他被設置了一個網格狀的圖片背景,以便於查看其尺寸。
  • A 包含了 19 個不可換行的字符,尺寸爲 152px * 17px。
  • B 包含了 15 個不可換行的字符,尺寸爲 120px * 17px。
  • C 包含了 18 個不可換行的字符,尺寸爲 144px * 17px。

注意:如果 STF 內包含右浮動元素,將觸發由 IE6 IE7 IE8(Q) 中佈局右浮動元素時的 Bug,導致 STF 的寬度儘可能的寬。

根據 CSS2.1 規範中 shrink-to-fit 的計算公式,獲取 STF 的幾個關鍵值:
preferred minimum width:將 STF 中所有元素儘可能的換行,最寬的元素是 B,爲 152px。
available width:即 Container 的寬度,爲 300px。
preferred width:將 STF 中所有元素儘可能的不換行,即 ABC 的寬度之和,再加上 AB 之間、BC 之間的兩個壓縮後的空格,爲 432px。

將結果代入計算公式:
min(max(152, 300), 432) = 300

也就是說,最終 STF 的寬度應該是 300px。

這段代碼在不同的瀏覽器環境中表現如下:

Snapshot

刪除 Placeholder_100Placeholder_150 後:

Snapshot

可見,在 IE6 IE7 IE8(Q) 中,STF 的寬度計算並非是按照 CSS2.1 規範中描述的 shrink-to-fit 算法來進行的。

推測其算法如下:

  1. 儘可能的將浮動元素靠上佈局在其包含塊中,如果當前所在行的剩餘橫向空間小於其 preferred minimum width,則嘗試下一行,以此類推,直到可以將其放置在這行爲止。
  2. 然後,將其內容逐行順次擺放,無法擺放時則折行繼續擺放,直到其所有內容擺放完畢。
  3. 最後,取其內容中最寬的行的寬度爲其最終寬度。

第一張圖是因爲第一行的 Placeholder_150 佔據了 150px,導致該行剩餘空間僅有 150px,無法放置 STF 中最寬的內容 A,因此換到第二行繼續嘗試。第二行的 Placeholder_100 佔據了 100px,剩餘 200px,大於 A 的寬度,因此在本行佈局。順次擺放其內容 ABC 後,取最長的一行 A 的寬度作爲 STF 的最終寬度,即 152px。

第二張圖的當前行寬度有 300px,因此 STF 在本行佈局。放置了 AB 後,剩餘空間不足以放置 C,因此折行繼續。全部內容放置完畢後,將其內容中最寬的、放置了 AB 的行的寬度作爲其最終寬度,即 152 + 120 + 8 = 280 (px)。(注:8px 是 AB 中間被壓縮的空白字符的寬度。)

在其他瀏覽器中,第一張圖中的 STF 以及第二張圖中的 STF 的最終寬度均爲 300px,是正確的值。

這個差異是由 IE6 IE7 IE8(Q) 中浮動元素的 shrink-to-fit 的不規範算法造成的。

該問題將導致受影響的元素的寬度比預期的小,並且儘可能的靠上佈局。

該問題在 IE8(S) 中被修復。在 IE8(S) 中,浮動元素的 shrink-to-fit 的算法與 CSS2.1 規範中描述的算法一致。

如果一個頁面在 IE6(S) IE7(S) 或 IE6(Q) IE7(Q) IE8(Q) 中被設計,並且有該問題存在,那麼這個頁面在其他瀏覽器中的佈局將與預期的不符。

關於 block formatting context 的詳細資料,請參考 CSS2.1 規範 9.4.1 Block formatting contexts 中的內容。

解決方案

這個問題的影響較大,避免該問題的最直接的方式是給浮動非替換元素指定一個寬度,而不使用其默認值 'auto',從而避免其寬度爲 shrink-to-fit,以使頁面佈局在各瀏覽器中的表現一致。

 

 

 

 

http://www.w3help.org/zh-cn/causes/RD8004

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