最近看了一篇总结ie常见bug的文章,里面提到ie多数的bug源于她的特有属性:haslayout。这个属性以前也了解过一点,但没有深入去理解,于是查阅了一些相关的资料,现在在此来对这个属性作一下总结。
一、haslayout的定义。
这里我就不一一敲了,直接复制百度的咯。
在ie中,一个元素要么自己对自身的内容进行计算大小和组织,要么依赖于父元素来计算尺寸和组织内容。为了调节这两个不同的概念,渲染引擎采用了 haslayout 的属性,属性值可以为true或false。当一个元素的 haslayout属性值为true时,我们说这个元素有一个布局(layout)。
如果它设置成了true,它就不得不去渲染它自己,因此元素不得不扩展去包含它的流出的内容。例如浮动或者很长很长的没有截断的单词,如果haslayout没有被设置成true,那么元素得依靠某个祖先元素来渲染它。这就是很多的ie bugs诞生的地方。
当一个元素有一个布局时,它负责对自己和可能的子孙元素进行尺寸计算和定位。简单来说,这意味着这个元素需要花更多的代价来维护自身和里面的内容,而不是依赖于祖先元素来完成这些工作。因此,一些元素默认会有一个布局。当我们说一个元素“拥有layout”或“得到 layout”,或者说一个元素“has layout” 的时候,我们的意思是指它的微软专有属性 haslayout 被设为了 true。通过 ie developer toolbar 可以查看 ie 下 html元素是否拥有haslayout,在 ie developer toolbar 下,拥有 haslayout的元素,通常显示为“haslayout = -1”。
值得注意的是,css下是没有haslayout这一个属性的,只能通过把某些属性设置特定值来使ie下的haslayout属性触发。这个属性在ie8及以后版本中被抛弃。
首先来看一下 默认拥有“haslayout”的元素:
, , , , , , , , , , , , 激活“haslayout”的方式调整下列css属性:
width:非auto任意值优先考虑 height:非auto任意值对 ie6 及更早版本来说很常用,该方法被称为霍莉破解(holly hack),即设定这个元素的高度为 1% (height:1%;)。但是要注意,当这个元素的 overflow 属性被设置为 visible 时,这个方法就失效了。 zoom:非normal任意值该属性也为ie特有属性。一般测试的时候用zoom:1。可以避免改变其他属性破坏布局。 position:absolute可能引发新问题。 float:left/rightie 常见bug很多都因为元素设置了浮动而触发haslayout产生的。 display:inline-block当一个内联元素想获得layout就要使用这个属性。 min-height、max-height(除none)、min-width、max-width(除none)设置任意值针对ie7。 overflow、overflow-x、overflow-y除visible外任意值针对ie7。 position:fixed针对ie7。 重置“haslayout”:需要没有其他属性激活haslayout的前提下。
width, height (设为 auto) max-width, max-height (设为 none)(在 ie 7 中) position (设为 static) float (设为 none) overflow (设为 visible) (在 ie 7 中) zoom (设为 normal) writing-mode (从 tb-rl 设为 lr-t) display 属性的不同:当用inline-block激活了haslayout 属性时,就算在一条独立的规则中覆盖这个属性为block或inline,haslayout 这个标志位也不会被重置为 false。把 mid-width, mid-height 设为它们的默认值0仍然会赋予 haslayout,但是 ie 7 却可以接受一个不合法的属性auto来重置 haslayout。
二、haslayout具体作用
上一部分总结了haslayout的定义和激活条件,现在来到了我们最关心的问题:haslayout到底有什么用。要说haslayout的作用,我们先来看看bfc。
什么是bfc?bfc,全称即:block formatting context,直译为:块级格式化范围。w3c css 2.1 规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。当涉及到可视化布局的时候,block formatting context提供了一个环境,html元素在这个环境中按照一定规则进行布局。一个环境中的元素不会影响到其它环境中的布局。
要更好地理解bfc,要先来谈谈box和formatting context的概念。我们知道网页布局是由很多盒子组成的,这些块就是box。元素的类型和 display 属性,决定了这个 box 的类型。 不同类型的 box, 会参与不同的 formatting context(一个决定如何渲染文档的容器),因此box内的元素会以不同的方式渲染。
这些盒子有:
block-level box:display 属性为 block, list-item, table 的元素,会生成 block-level box。并且参与 block fomatting context; inline-level box:display 属性为 inline, inline-block, inline-table 的元素,会生成 inline-level box。并且参与 inline formatting context; 而formatting context是一块渲染区域,它决定了其子元素如何定位,以及与其他元素的位置关系。
根据上述的一些基本概念,我把bfc简单理解成一个容器,在bfc这个容器中,元素按照bfc的规则实现布局。比如浮动元素会形成bfc,这就是为什么我们看到浮动元素布局跟普通文档流下的布局有所差别的原因。
bfc中的规则简单整理为以下几条:
内部的box会在垂直方向,一个接一个地放置。 box垂直方向的距离由margin决定。属于同一个bfc的两个相邻box的margin会发生重叠 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。 bfc的区域不会与float box重叠。 bfc就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。 计算bfc的高度时,浮动元素也参与计算 哪些元素会形成bfc:
根元素 float属性不为none position为absolute或fixed display为inline-block, table-cell, table-caption, flex, inline-flex overflow不为visible bfc在布局中的作用:
谈到作用,需要理解bfc中的布局规范。 第一条没什么好说的,就是按照正常文档流的渲染顺序对元素进行排布。
第二条是我们常说的margin重叠问题。要想两个相邻的元素不发生垂直方向上的margin重叠,需要将他们两定义在不同的bfc中。解决方法即在其中一个元素外包裹一层元素,再对那层包裹的元素进行bfc触发。(这里可以加入上述的css属性。)
第三条意思是,在bfc包含块中,每一个元素都会与父盒子进行左对齐。如果元素具有左边的margin,那么则是元素的margin边界与父盒子的border边界对齐。这就是为什么我们设置绝对定位时,所有具有绝对定位熟悉的元素初始化时都会以左上角重叠。
第四条跟我们的浮动布局有关。一般情况下,浮动元素会脱离文档流,即不占位置。它的兄弟元素会与它在左上角重叠。但是如果两个相邻元素都设置了浮动,那么意味着它们都是以bfc的规则渲染,根据第四条,bfc区域不会相互重叠,所以便能理解为什么设置浮动后元素能独占空间了。
第五条不是特别理解,占且放一下。
第六条也是特别常见。在普通容器中,如果里面有浮动元素,在不设置高度的情况下,容器是不能被撑起来的,这时候通过设置overflow:hidden把其变为bfc,那么就可以包含浮动元素了。
bfc的说明到此就告一段落了,现在回到最初讨论的haslayout的问题。ie7及以下ie版本不支持bfc的,但有私有属性haslayout,于是我们可以通过触发元素的haslayout来达成bfc的相似效果。
三、ie下因为haslayout导致的bug
……待续。