三人行必有我师焉,择其善者而从之,其不善者而改之
三人行必有我师焉,择其善者而从之,其不善者而改之
三人行必有我师焉,择其善者而从之,其不善者而改之
三人行必有我师焉,择其善者而从之,其不善者而改之
三人行必有我师焉,择其善者而从之,其不善者而改之

斯芬克斯之迷——ie私有属性haslayout的困扰
作者:Neoxone    发表时间: 2009年03月21号,星期六     阅读:10,003 次

就象神话中的斯芬克斯一样,ie的私有属性haslayout是个神秘且让人困惑的难缠东西,她只游荡于ie(这片沙漠)之下。
她无法使用css声明直接创建。即便是对于ie,她也不能说是一个实实在在存在的属性。
ie下的元素有些本身拥有haslayout(基本上是一些拥有内在尺寸的可置换元素),有些可以通过一些css属性可以触发产生。

我们可以在ie developer toolbar上查看到到haslayout这个属性项,他的值是-1。这说明这个元素触发了layout。
详细haslayout资料:On having layout抄录
更详细资料:译文On having layout这篇文章本人还没怎么看,相信很多问题在这里都有解释

遇到斯芬克斯是件很麻烦的事情,她会给你提出很多怪怪的让人困惑的问题,更何况只要我们在ie沙漠中游荡的话,遇到的概率是非常高的。
遇到她,我们会有三种结果:
猜不出迷题的答案——我们会在迷失在困惑中;
猜错了迷题的答案——我们会误会很多东西;
猜对了迷题的答案——恭喜你,你就不用怕斯芬克斯这个丑婆娘了。

那让我们来猜一下她的几个比较困惑的问题吧。

斯芬克斯之迷1:是firefox错了?

left是浮动元素,她脱离了文档流(注意,这是下一个斯芬克斯之迷),所以right的margin-top相对的是其上级wrap作用的。但我们只是对right设置margin-top。结果在FF下,怎么连left也“产生了margin-top”呢。对比ie和FF下的效果,是不是觉得IE下的解析会比较合理呢?
但是
别忘了影响margin-top/bottom的一个重要规则——margin塌陷(margin collapsing)。

margin collapsing(css2.1规范)
margin collapsing(css2规范)

在ff下就是产生了这么一个margin塌陷。导致wrap的”剥夺”了本属于子元素#right的margin-top值。
为了更加直观看出是否塌陷,可以給wrap添加一个背景:background:#000;

在ff下wrap块的高度并没有被子元素right的margin-top撑开。反而自身拥有了50px的margin-top。
而浮动的left尽管脱离了文档流,但还是受其父级限制的(这跟absolute定位的元素层受限于其定义为relative的父级一样)。所以left还是包含在wrap之中,这样在ff下看起来left也拥有margin-top,而事实上是因为wrap高度不撑开的结果。

这么说,FF并没有错咯,那么IE下又是怎么避开margin塌陷的呢?
问题就出在浮动上面,在ie下,元素浮动将触发其haslayout。就是这个原因,使得在ie下意外(意外?)的就避开了margin塌陷。
haslayout差点让我们怀疑了我们的亲密伙伴firefox。

———-谜题之外———–
但是,margin塌陷往往不是我们想要的效果。那么我们需要怎么避开他呢?
可以看下这篇独立文章:如何解决麻烦的margin塌陷(margin collapsing)

斯芬克斯之迷2:在ie下,float元素不脱离文档流?

在前面的问题里,我们提到浮动元素时一直认为浮动元素脱离文档流。但是看一下下面这个现象:

很多人都一直怀疑浮动元素脱离文档流的这种说法,就是因为ie下haslayout的经常出现。ie下,浮动的元素(left)牢牢的占着自己的位置。后面的block元素(right),只能跟随其后(请对比FF下的效果)。
没错,这又是haslayout在迷惑我们,这回除了left因为浮动触发了haslayout外,right也由于使用了width:500px也触发了haslayout,使得他考虑到了前面浮动的left元素。
如果把right的宽度去掉,或则把值改成auto。就能使ie下达到ff下一样的效果:后面的block元素会忽略前面浮动元素的存在,直接跑到浮动元素的z轴方向的下面(为什么是下面?因为浮动元素的Z值较正常的要高),而inline元素则环绕此浮动元素。
我们再看一个更加明了的demo:

由于父级使用width:100%.触发了haslayout。使得原本脱离文档流的浮动元素,又在其父级之内拥有了一席之地。

——-谜题之外——–
浮动有三个作用效果:
一是使得自身脱离文档流,使得父层不适应其高度,而后面的block元素也将忽略其“存在”,跑到浮动元素之下(可在block元素上加背景色查看);
二是使得后面的inline元素“顺流环绕”浮动元素。
三是浮动元素的尺寸,如果未定义的话,将按内部元素的尺寸来决定(而不是block元素默认的充满整行)。而且即便浮动元素本身是非可置换inline元素,她都可以定义width/height(还有margin也将算入尺寸计算)。
其实第一个效果往往不是我们所想要的。所以ie下的haslayout可以说正中我们下怀。那么FF下怎么让left元素不脱离文档流(看起来没有脱离)呢?
在上面的例子中,我们可以对right也使用浮动,或则在right加上overflow:hidden。
知道了这个原理,我们对于这个【右列宽度自适应】的布局(其实这是个左右布局均自适应的布局。一般来说我们会固定左列的宽度)就能很好理解了:
zoom:1针对IE系列触发haslayout.overflow:hidden针对FF。使得right不会忽视已经脱离文档流的浮动元素left。

IE下的haslayout会引发很多问题:

IE 很多常见的浮动 bug 。
元素本身对一些基本属性的异常处理问题。
容器和其子孙之间的边距重叠(margin collapsing)问题。
使用列表时遇到的诸多问题。
背景图像的定位偏差问题。
使用脚本时遇到的浏览器之间处理不一致的问题。

她经常让我们困惑不堪。
但是只要逐步认识她,重视她。经常怀疑,怀疑自己的怀疑。我们就能慢慢摸清她的谜题,了解问题的本质。

标签: , , ,

6 条评论 发表在“斯芬克斯之迷——ie私有属性haslayout的困扰”上

  1. [...] having layout斯芬克斯之迷——ie私有属性haslayout的困扰如何避开麻烦的margin叠加(margin [...]

  2. 晓辉 说:

    作者对这个属性理解的很深

    回复

  3. 无恙 说:

    貌似上面的例子在IE8中很大部分被修改了哦

    回复

    oneboys 回复:

    @无恙, 嗯,是的。ie8已经抛弃了haslayout属性。

    回复

  4. [...] 斯芬克斯之迷——ie私有属性haslayout的困扰 如何避开麻烦的margin叠加(margin collapsing) [...]

  5. [...] 大家都知道,浮动元素应该是脱离文档流的,但是zoom:1会触发haslayout。所以在ie下,原本是应该脱离文档流的浮动元素仍然占据着文档空间,除非去除zoom:1;(注意对比FF和IE看看背景色的位置)。 然而我们会发现,ie8的效果一直同FF保持一致,并没有受haslayout影响。 可以再参考下这里ie私有属性haslayout的困扰。 [...]

留下回复

):9:( ):8:( ):7:( ):6:( ):5:( ):4:( ):3:( ):2:( ):20:( ):1:( ):19:( ):18:( ):17:( ):16:( ):15:( ):14:( ):13:( ):12:( ):11:( ):10:(