標準參考
根據 W3C CSS2.1 規範中的描述,對於非替換的浮動元素,若 'margin-left' 或 'margin-right' 特性的計算值爲 'auto',則它們的實際使用值爲 '0'。
除此之外,'margin-left' 與 'margin-right' 特性的計算則採用其自身定義的規範。
關於 'margin-left'、'margin-right' 以及 非替換的浮動元素寬度計算 的詳細信息,請參考 CSS2.1 規範 8.3 Margin properties: 'margin-top', 'margin-right', 'margin-bottom', 'margin-left', and 'margin' 以及 10.3.5 Floating, non-replaced elements 中的內容。
問題描述
在 IE5.0 IE5.5 IE6 中,當爲一個塊級元素同時設置了向左浮動(float:left)及左邊距或右邊距('margin-left' | 'margin-right')後,則該元素的左邊距或右邊距在某些情況下會是設定值的兩倍。同樣地,向右浮動(float:right)及右邊距('margin-right')也存在此現象。
這個是 IE 著名的 "雙邊距Bug"(IE Double Margin Bug)。
造成的影響
這種雙倍邊距的怪異現象會對頁面造成很多影響,如意外折行、溢出、文字重疊等諸多兼容性問題。
受影響的瀏覽器
IE5.0 IE5.5 IE6 |
---|
問題分析
首先重現這個 Bug。
分析以下代碼:
<!DOCTYPE html> <html> <head> <script> window.onload = function () { document.getElementById("d1").innerHTML = document.getElementById("d1").parentNode.offsetWidth; document.getElementById("d2").innerHTML = document.getElementById("d2").parentNode.offsetWidth; } </script> </head> <body style="font:12px Arial; margin:0;"> <div style="width:100px;"> <div style="background:gold; float:left;"> <div id="d1" style="float:left; margin:0 50px; background:olive; width:100px; height:50px;"></div> </div> <div style="background:pink; float:left;"> <div id="d2" style="float:right; margin:0 50px; background:deeppink; width:100px; height:50px;"></div> </div> </div> </body> </html>
上面代碼中有兩組 DIV 容器,容器內的 DIV 元素分別設置了向左浮動(float:left)與向右浮動(float:right),且左右邊距均爲 50px(margin:0 50px)。當頁面加載完畢後將 DIV 容器的 offsetWidth 顯示出來。
在各瀏覽器中打開這個頁面效果如下:
IE5.0 IE5.5 IE6 | IE7 IE8 Firefox Chrome Safari Opera |
---|---|
從上面的例子與截圖可見:
- 在 IE5.0 IE5.5 IE6 中,當一個塊級元素向左浮動時,其左邊距會出現雙倍於設定的邊距值的現象。當一個塊級元素向右浮動時,其右邊距會出現雙倍於設定的邊距值的現象。由於深黃色的塊級元素爲其容器內的最後一個左浮動元素,所以其右邊距也會出現雙倍於設定的右邊距值的現象;
- 在 其他瀏覽器 中,沒有上述的現象,瀏覽器遵照 W3C 規範對頁面元素進行解釋及渲染。
觸發此 Bug 的條件有 3 個:
-
若一個元素向左浮動(float:left),且其設置的左邊距('margin-left')大於其至容器的左側內邊界的距離:
該元素實際的左邊距 = 設置的左邊距 * 2 - 左邊界至容器的距離; -
同樣地,若一個元素向右浮動(float:right),且其設置的右邊距 ('margin-right')大於其至容器的右側內邊界的距離:
該元素實際的右邊距 = 設置的右邊距 * 2 - 右邊界至容器的距離; -
若一個元素向左浮動(float:left),這個元素爲其父容器的最後一個左浮動元素,且其設置的右邊距('margin-right')大於其至容器的右側內邊界的距離:
該元素的實際右邊距 = 設置的右邊距 * 2。
下面結合上面的觸發條件看一組更加複雜的例子:
<style> .fl { float:left; height:30px; background:gray; } #A { width:90px; margin:0 10px; } #B { width:85px; margin-left:150px; } #C { width:100px; margin-left:100px; } </style> <div style="width:600px; height:30px; background:#CCC;"> <div id="A" class="fl">10 90 10</div> <div id="B" class="fl">150 85 0</div> <div id="C" class="fl">100 100 0</div> </div>
測試代碼中 DIV 容器中包含了三個 DIV 子元素,這三個子元素均爲左浮動元素,且均擁有 'margin-left' 特性。
不同的瀏覽器運行的結果列表如下:
IE5.0 IE5.5 IE6 |
|
---|---|
IE7 IE8 Firefox Chrome Safari Opera |
在 IE5.0 IE5.5 IE6 中,
- 【A】的左邊距容器的距離爲 0,其設置的左邊距爲 10px,10 > 0。則【A】滿足上面的條件1,觸發此 Bug。【A】實際的左邊距變爲 10 * 2 - 0 = 20px。
- 【B】的左邊距容器的距離爲 120px(20 + 90 + 10),其設置的左邊距爲 150px,150 > 120。則【B】滿足上面的條件1,觸發此 Bug。【B】實際的左邊距變爲150 * 2 - 120 = 180px。
- 【C】的左邊距容器的距離爲 385px(20 + 90 + 10 + 180 + 85),其設置的左邊距爲 100px,100 < 285。則【C】不滿足觸發此 Bug 的條件。【C】實際的左邊距仍然爲 100px。
上面討論的都是元素浮動之前爲塊級元素,下面觀察一下 'display' 特性分別爲 'inline' 及 'block' 的 SPAN 元素浮動後的情況:
<div style="width:100px; height:20px; background:#ccc;">100 x 20</div> <span style="float:left; margin-left:100px; width:100px; height:20px; background:gray;">inline FLOAT</span> <br /><br /> <div style="width:100px; height:20px; background:#ccc;">100 x 20</div> <span style="float:left; margin-left:100px; width:100px; height:20px; background:gray; display:block">block FLOAT</span>
這段代碼在不同瀏覽器中運行效果爲:
IE5.0 IE5.5 IE6 |
|
---|---|
IE7 IE8 Firefox Chrome Safari Opera |
從上面一組截圖中很明顯的看出,雙邊距 Bug 會作用於 'display' 特性爲 'block' 的元素,對於 'inline' 的元素不會觸發此 Bug。
解決方案
- 儘量避免同時使用 'margin-left' 與 float:left,及 'margin-right' 與 float:right;
- 由於這個 Bug 對於 'display' 特性爲 'inline' 的元素不會觸發,所以可以通過設置 display:inline 消除此 Bug,由於此 Bug 僅在元素浮動時發生,而浮動將使該元素 'display' 特性計算爲 'block' 或者 'table'(見 CSS2.1 規範第 9.7 Relationships between 'display', 'position', and 'float' 節),因此可以通過設置 display:inline 消除雙邊距 Bug。