转自:http://www.smallni.com/haslayout-block-formatting-contexts/
因为本人脑子不好使,自己打印出了一张haslayout和block formatting contexts(以下简称bfc)的触发表贴在办公桌上(也可以称作创建了bfc),每天看看就记住了,不知道大家有没有对这2个东西做过深入了解,如果真的做过了解,一些各浏览器部分奇怪的bug也会迎刃而解。今天,我们一起来剖析下,揭开它们神秘的面纱。
1.haslayout ‘layout’ 是 ie 的专有概念,它决定了元素如何对其内容进行定位和尺寸计算,与其他元素的关系和相互作用,以及对应用还有使用者的影响。
概念说明: ‘layout’ 可以被某些 css property(特性)不可逆的触发,而某些 html 元素本身就具有 layout 。 ‘layout’ 在 ie 中可以通过 haslayout 属性来判断一个元素是否拥有 layout ,如 object.currentstyle.haslayout 。 ‘layout’ 是 ie 浏览器渲染引擎的一个内部组成部分。在 ie 浏览器中,一个元素要么自己对自身的内容进行组织和计算大小, 要么依赖于包含块来计算尺寸和组织内容。为了协调这两种方式的矛盾,渲染引擎采用了 ‘haslayout’ 属性,属性值可以为 true 或 false。 当一个元素的 ‘haslayout’ 属性值为 true 时,我们说这个元素拥有了一个布局(layout),即成功触发haslayout 触发方式: 默认拥有布局的元素: , , , , , , , , , , , ,
可触发 haslayout 的 css 特性: display: inline-block /*all*/height: (除 auto 外任何值) /*仅适用ie6 7*/width: (除 auto 外任何值) /*仅适用ie6 7*/float: (left 或 right) /*all*/position: absolute /*all*/writing-mode: tb-rl /*all*/zoom: (除 normal 外任意值) /*仅适用ie6 7*/
ie7 还有一些额外的属性(不完全列表)可以触发 haslayout : min-height: (任意值)/*以下适用ie7+*/min-width: (任意值)max-height: (除 none 外任意值)max-width: (除 none 外任意值)overflow: (除 visible 外任意值,仅用于块级元素)overflow-x: (除 visible 外任意值,仅用于块级元素)overflow-y: (除 visible 外任意值,仅用于块级元素)position: fixed
ie6 以前的版本(也包括 ie6 及以后所有版本的混杂模式,其实这种混杂模式在渲染方面就相当于 ie 5.5), 通过设置任何元素的 ‘width’ 或 ‘height’(非auto)都可以触发 haslayout ; 但在 ie6 和 ie7 的标准模式中的行内元素上却不行,设置 ‘display:inline-block’ 才可以。 2.block formatting contexts(bfc) ie有它自己的haslayout属性,那么非ie浏览器呢?非ie浏览器采用的就是bfc(块格式化上下文)
概念说明: bfc是 w3c css 2.1 规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。 在创建了 bfc的元素中,其子元素会一个接一个地放置。垂直方向上他们的起点是一个包含块的顶部,两个相邻的元素之间的垂直距离取决于 ‘margin’ 特性。在bfc中相邻的块级元素的垂直边距会折叠(collapse)。 在bfc 中,每一个元素左外边与包含块的左边相接触(对于从右到左的格式化,右外边接触右边), 即使存在浮动也是如此(尽管一个元素的内容区域会由于浮动而压缩),除非这个元素也创建了一个新的bfc。 在css3中,对这个概念做了改动:http://www.w3.org/tr/css3-box/#block-level0css3中,将bfc 叫做 flow root。 触发方式 float:(任何值除了none)overflow:(任何值除了visible)display:(table-cell/table-caption/inline-block)position:(任何值除了static/relative)
tips:我们有时会用overflow:hidden的方法去清除浮动,就是因为触发了元素的块格式化上下文(ie6 7要申明zoom为1),这个方法的确简单,但很暴力 ? -#
3. haslayout 和 bfc 的特点 3.1 在触发 haslayout 的元素和创建了 bfc的元素中,浮动元素参与高度的计算 情况1:没有创建 bfc的块级非替换元素,触发了 ie 的 haslayout。
分析以下代码:
simple text in flow
float:left
container 没有创建 block formatting context。 container 的 ‘zoom:1’设置,是为了触发 ie 中的 haslayout; container 的高度值为 auto,并且 ‘overflow’ 的值为默认的 ‘visible’; span1 是一个行内元素, div1 是一个处于普通流中的块元素; div2 是一个浮动的块级元素。 根据 css2.1 规范第 10.6.3 部分的高度计算规则,在进行普通流中的块级非替换元素的高度计算时,浮动子元素不参与计算。
所以,在进行 container 高度计算时,只受 span1 和 div1 的影响,应该是它们两个的高度之和,所以最终银色部分不应该包含金色的部分。
这段代码在不同的浏览器环境中表现如下:
ie6 ie7 ie8(q) ie8(s) firefox chrome safari opera
去掉 container 的 ‘zoom:1′ 后,各浏览器表现一致:
可见,ie 浏览器中,触发 haslayout 的元素在进行高度计算的时候,其浮动的子元素也会参与运算。
情况2:创建了 bfc的块级非替换元素,未触发 ie 的 haslayout。
分析以下代码:
simple text in flow
float:left
container 的 ‘overflow:hidden;’ 创建了bfc; container 的 ‘overflow:hidden;’,在 ie6 中未触发 haslayout,但在 ie7(s) 中触发了 haslayout; container 的高度值为 ‘auto’; span1 是一个行内元素,div1 是一个处于普通流中的块元素; div2 是一个浮动的块级元素。 根据 css2.1 规范第10.6.7部分的高度计算规则,在计算生成了 bfc的元素的高度时,其浮动子元素应该参与计算。
所以,在进行 container 高度计算时,div2 也应该参与计算,所以最终银色部分应该包含金色的部分。
这段代码在不同的浏览器环境中表现如下:( 注意 ie7(s) 此时触发了 haslayout )
ie6 ie7(q) ie8(q) ie7(s) ie8(s) firefox chrome safari opera
可见,只要 container 创建了 bfc,其浮动子元素就会参与其高度计算(ie7(s) 是由于 haslayout 导致与其他浏览器的效果相同)。
3.2 与浮动元素相邻的、触发了 haslayout 的元素或创建了 bfc 的元素,都不能与浮动元素相互覆盖 如果浮动元素的两侧有足够的空间放置该元素,则元素会紧邻浮动元素放置,必要时,该元素的宽度将会被压缩。否则它们可 能会定位到浮动元素的下方。
情况1:没有创建 bfc 的块级非替换元素,触发了 ie 的 haslayout。
分析以下代码:
float block
if i had a single flower for every time i think about you, i could walk forever in my garden.
div1 是一个浮动元素,背景是 50% 的透明 div2 的 ‘zoom:1′ 触发了 ie 中的 haslayout。 其中,grid2a.png 背景是 100px * 100px 的图片:
根据 css 2.1 9.5 floats 中的描述,浮动元素会覆盖普通流中的块容器。所以,div2 应该有一部分呢被 div1 覆盖。
这段代码在不同的浏览器环境中表现如下:(忽略 ie 中 3px bug 的影响)
ie6 ie7 ie8(q) ie8(s) firefox chrome safari opera
情况2:创建了 bfc的块级非替换元素,未触发 ie 的 haslayout。
分析以下代码:
float block
if i had a single flower for every time i think about you, i could walk forever in my garden.
div1 是一个浮动元素,背景是50%的透明 div2 的 ‘overflow:hidden;’ 在 ie6 中未触发 haslayout,但在 ie7(s) 中触发了 haslayout。 根据 css 2.1 9.5 floats 中的描述,创建了bfc的元素不能与浮动元素重叠, 所以,div2 应该有一部分被 div1 覆盖。
这段代码在不同的浏览器环境中表现如下:( 注意 ie7(s) 此时触发了 haslayout )
ie6 ie7(q) ie8(q) ie7(s) ie8(s) firefox chrome safari opera
3.3 触发 haslayout 的元素和创建了 bfc的元素不会与它们的子元素发生外边距折叠 情况1:没有生成bfc的块级非替换元素,触发了 ie 的 haslayout。
分析以下代码:
content
container 是宽度为300px,含有 border 的块元素,根据标准,它不会与子元素的 margin 发生空白边折叠。 div1 的宽度没有设置,所以宽度等于 container 的宽度。 div1 的高度也没有设置,所以其高度取决于其内容的高度。 div1 设置了 ‘zoom:1’,在 ie 中触发了 haslayout。 根据 css 2.1 8.3.1 collapsing margins 第一条,两个相邻的普通流中的块框在垂直位置的空白边会发生折叠现象。
div1 和 div2 应该发生空白边折叠,深灰色的 div1 应该刚好包含 ‘content’ 文本。
这段代码在不同的浏览器环境中表现如下:
ie6 ie7 ie8(q) ie8(s) firefox chrome safari opera
可见,在 ie 中,触发 haslayout 的元素,阻止了它自身与子元素间的空白边折叠。
情况2:生成 bfc的块级非替换元素,未触发 ie 的 haslayout。
分析以下代码:
content
container 是宽度为300px,含有 border 的块元素,根据标准,它不会与子元素的 margin 发生空白边折叠。 div1 的宽度没有设置,所以宽度等于 container 的宽度。 div1 的高度也没有设置,所以其高度取决于其内容的高度。 div1 设置了 ‘overflow:hidden’,在 ie6 中未触发 haslayout,但在 ie7(s) 中触发了 haslayout。 根据 css 2.1 8.3.1 collapsing margins 第三条,生成bfc 的元素不会和在流中的子元素发生空白边折叠。
div1 和 div2 不应该发生空白边折叠,深灰色的 div1 应该撑满 container 。
这段代码在不同的浏览器环境中表现如下:( 注意ie7(s) 此时触发了 haslayout )
ie6 ie7(q) ie8(q) ie7(s) ie8(s) firefox chrome safari opera
可见,在 ie 中,创建了 bfc,未触发 haslayout 的元素,它自身与子元素间的空白边折叠还是会发生。
haslayout 和 bfc 的异同及可能产生的问题 区别 在 ie8(s) 之前的版本中,没有规范中提及的 block formatting context 和 inline formatting context 概念,而是用 haslayout 来达到相似的目的。 在 ie 中可通过设置 ‘width’、’height’、’min-width’、’min-height’、’max-width’、’max-height’、 ‘zoom’、’writing-mode’ 来触发 haslayout,而这些特性值的设置不能够使元素创建 bfc。 在 ie 中很多元素默认就是拥有布局的,如 ipunt, button, select, textarea 等,但是这些元素在标准中会形成 inline formatting context (本博客后面会介绍)。 共同点 两者都是决定了对内容如何定位及大小计算的规则。 两者都决定了与其他元素的相互作用的规则。 ‘table-cell’ 和 ‘table-caption’ 既是 haslayout 的元素,又是可以创建 bfc 的元素。 浮动元素,绝对定位元素,inline-block 元素以及除 ‘visible’ 外任意值的 overflow(ie7) 在 ie 中可以触发 haslayout,同时在标准中,又可以创建bfc。 可能产生的兼容性问题: 由于 haslayout 和 bfc是对一类事物的不同理解,并且他们的启用条件不尽相同,因此如果一个元素设计时,在 ie 早期版本中触发了 haslayout ,但在其他浏览器中又没有创建bfc,或者相反,一个元素在 ie 早期版本中没有触发 haslayout ,在其他浏览器中却创建了 bfc(如设置了 ‘overflow:hidden’ ),将导致页面布局的重大差异。 解决方案 仅当一个元素即在 ie 早期版本中触发了 haslayout,又在其他浏览器中创建了bfc时,才能避免上述问题的发生。即同时启用上述两者以保证各浏览器的兼容,或者相反,两者皆不启用。
使元素即生成了bfc,又触发了 haslayout 对于触发 haslayout 的元素,通过 css 设置,使它产生bfc; 生成 bfc但是没有触发 haslayout 的元素,通过设置 ‘zoom:1’,使其触发 haslayout。 使元素即没有触发 haslayout,又没有创建 bfc。 本文部分内容完全来源于w3help(武利剑) ,本文参考的一些其他资料来源:
http://www.w3.org/tr/css21/visuren.html#block-formatting
http://reference.sitepoint.com/css/haslayout
http://blog.csdn.net/pengju_guo/article/details/6945436
http://www.qianduan.net/comprehensive-haslayout.html