标准参考

根据 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 个:

  1. 若一个元素向左浮动(float:left),且其设置的左边距('margin-left')大于其至容器的左侧内边界的距离:
    该元素实际的左边距 = 设置的左边距 * 2 - 左边界至容器的距离;
  2. 同样地,若一个元素向右浮动(float:right),且其设置的右边距 ('margin-right')大于其至容器的右侧内边界的距离:
    该元素实际的右边距 = 设置的右边距 * 2 - 右边界至容器的距离;
  3. 若一个元素向左浮动(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。

From;http://w3help.org/zh-cn/causes/RX1001

IE双边距bug的更多相关文章

  1. ie6双边距bug及其解决办法

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. IE的双边距Bug以及解决办法

    display:inline和display:block区别 一.什么是双边距Bug? 先来看图: 我们要让绿色盒模型在蓝色盒模型之内向左浮动,并且距蓝色盒模型左侧100像素.这个例子很常见,比如在网 ...

  3. IE6中浮动双边距bug

    想要创建出漂亮的网页设计, 除了要认真学习每一个html和CSS代码之外,不可能不去了解一下臭名昭著的IE6和更早的那些IE浏览器的坏脾气,因为你本来写出的规规矩矩的代码, 漂亮的设计就此就要完成了, ...

  4. ie6双边距解决

    这个bug是ie6有名的双边距bug:同时为一个元素设置向一个方向偏移和对这个方向进行外边距设置,比如float:left,margin-left:45px;在其他浏览器下是显示正常的,在ie6下这个 ...

  5. IE6下margin出现双边距

    在IE6下,块元素有浮动和横向margin的时候,横向的margin值会被放大成两倍 解决方法:添加display:inline; eg:下面的例子在IE6下会有两倍边距 <style> ...

  6. ie6下双边距的问题

    1.ie6双边距情况 <div class="red"></div> <div class="blue"></div& ...

  7. 双倍边距bug

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  8. IE6 双倍距BUG

    IE6双倍距BUG的形成: 1.快元素 2.元素浮动 3.margin左右 解决方案:_display:inline;

  9. IE6下不能定义1px高度的容器和IE6 双边距

        (1)触发的条件---定义一个div,将容器的高度设置成1px (2)  编码得到的结果---在IE6浏览器中,容器的高度不是1px   而是18px (3)出现问题的原因---是因为IE6浏 ...

随机推荐

  1. js写出斐波那契数列

    斐波那契数列:1.1.2.3.5.8.13.21.34.…… 函数: 使用公式f[n]=f[n-1]+f[n-2],依次递归计算,递归结束条件是f[1]=1,f[2]=1. for循环: 从底层向上运 ...

  2. 微信支付:微信支付遇到的坑:jssdk,phpdemo,微信支付提示{"errMsg":"chooseWXPay:fail"}

    微信支付:微信支付遇到的坑:jssdk,phpdemo 使用微信支付,真是变态,如果不是微信用户多,我才不适配微信支付,我就在想:为什么没人用我支付宝的[点点虫]呢.一个小小的“/”的误差,都调不起微 ...

  3. asp.net 锚点

    可以使用锚点,但这里可使用灵活处理 首先获取需要滚动到的位置的id,如,可以设置一个元素(,注:要在form里),另外在form的任意位置设置 代码如下: 注:a标签里不要有内容,在回传的地方调用 代 ...

  4. Redis 存储机制

    Redis存储机制分成两种Snapshot和AOF.无论是那种机制,Redis都是将数据存储在内存中. Snapshot工作原理: 是将数据先存储在内存,然后当数据累计达到某些设定的伐值的时候,就会触 ...

  5. 终端命令对字符串进行sha1、md5、base64、urlencode/urldecode

    sha1.md5.base64 mac $ echo -n foo|shasum 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 - $ 2c26b46b68ffc6 ...

  6. 强大的表格控件handsometable,结合vue

    handsontable handsontable是目前在前端界最接近excel的插件,可以执行编辑,复制粘贴,插入删除行列,排序等复杂操作.jQuery.react.ng和vue版本,功能强大,是复 ...

  7. Linux(CentOS)下.NET,mono环境的安装步骤整理

    本文Linux使用的是CentOS 7 1.软件下载 CentOS:https://www.centos.org/download/ mono-4.2.1.36.tar.bz2 http://down ...

  8. Redis源码解析(1)——源码目录介绍

    概念 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合)和zset(有序集合).这些 ...

  9. git公私钥的拷贝

    1.场景 由于我换了一台电脑,为了能访问远程仓库,我就把原来电脑上的私钥和config文件拷贝过来 2.出现问题及解决方案 git clone server:xxx_service_express 报 ...

  10. VSCode使用正则表达式进行内容替换

    首先描述一下我要达到的目的: 1.源数据: 2.目标数据: 3.使用的正则表达式如下: (id: (\d+),) id: $2, \n order: $2,