发现我很久没更新博文了=-=这里把我以前在博客园写过的一篇关于BFC的文章粘贴过来,顺便本身也再次作个总结。css
最近看了一篇总结ie常见bug的文章,里面提到ie多数的bug源于她的特有属性:hasLayout。这个属性之前也了解过一点,但没有深刻去理解,因而查阅了一些相关的资料,如今在此来对这个属性做一下总结。html
洋洋洒洒一大篇。这里的内容若是以为很差懂的话建议能够先看看后文提到的BFC属性。chrome
在ie中,一个元素要么本身对自身的内容进行计算大小和组织,要么依赖于父元素来计算尺寸和组织内容。为了调节这两个不一样的概念,渲染引擎采用了
hasLayout 的属性,属性值能够为true或false。当一个元素的
hasLayout属性值为true时,咱们说这个元素有一个布局(layout)。浏览器若是它设置成了true,它就不得不去渲染它本身,所以元素不得不扩展去包含它的流出的内容。例如浮动或者很长很长的没有截断的单词,若是haslayout没有被设置成true,那么元素得依靠某个祖先元素来渲染它。这就是不少的ie
bugs诞生的地方。sass当一个元素有一个布局时,它负责对本身和可能的子孙元素进行尺寸计算和定位。简单来讲,这意味着这个元素须要花更多的代价来维护自身和里面的内容,而不是依赖于祖先元素来完成这些工做。所以,一些元素默认会有一个布局。当咱们说一个元素“拥有layout”或 “获得layout,ide
或者说一个元素“has layout” 的时候,咱们的意思是指它的微软专有属性 hasLayout 被设为了 true。经过IE Developer Toolbar 能够查看 IE 下 HTML元素是否拥有haslayout,在 IE Developer Toolbar 下,拥有 haslayout的元素,一般显示为“haslayout = -1”。布局
值得注意的是,css下是没有haslayout这一个属性的,只能经过把某些属性设置特定值来使ie下的hasLayout属性触发。这个属性在ie8及之后版本中被抛弃。测试
激活“haslayout”的方式——调整下列css属性:flex
width
:非auto
任意值——优先考虑spa
height
:非auto
任意值——对 IE6 及更早版原本说很经常使用,该方法被称为霍莉破解(Holly hack),即设定这个元素的高度为 1% (height:1%;
)。可是要注意,当这个元素的 overflow
属性被设置为 visible
时,这个方法就失效了。
zoom
:非normal
任意值——该属性也为ie特有属性。通常测试的时候用zoom:1
。能够避免改变其余属性破坏布局。
position:absolute
——可能引起新问题。
float:left/right
——ie 常见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
")
注意:当用inline-block
激活了haslayout 属性时,就算在一条独立的规则中覆盖这个属性为block
或inline
,haslayout 这个标志位也不会被重置为 false。把 min-width
, min-height
设为它们的默认值"0"仍然会赋予 hasLayout,可是 IE 7 却能够接受一个不合法的属性auto
来重置 hasLayout。
BFC是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,这就是为何咱们看到浮动元素布局跟普通文档流下的布局有所差异的缘由。
内部的Box会在垂直方向,一个接一个地放置。
Box垂直方向的距离由margin
决定。属于同一个BFC的两个相邻Box的margin
会发生重叠
每一个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,不然相反)。即便存在浮动也是如此。
BFC的区域不会与float box重叠。
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
计算BFC的高度时,浮动元素也参与计算
根元素
float属性不为none
position为absolute或fixed
display为inline-block, table-cell, table-caption, flex, inline-flex
overflow不为visible
解决两元素margin重叠的问题
要想两个相邻的元素不发生垂直方向上的margin重叠,须要将他们两定义在不一样的BFC中。解决方法即在其中一个元素外包裹一层元素,再对那层包裹的元素进行BFC触发。(这里能够加入上述的css属性。)
解决因为浮动形成的重叠问题
通常状况下,浮动元素会脱离文档流,即不占位置。它的兄弟元素会与它在左上角重叠。可是若是两个相邻元素都设置了浮动,那么意味着它们都是以BFC的规则渲染,根据上述第四条规则,BFC区域不会相互重叠,因此便能理解为何设置浮动后元素能独占空间了。
解决容器因为拥有浮动元素形成高度塌陷的问题
在普通容器中,若是里面有浮动元素,在不设置高度的状况下,容器是不能被撑起来的,这时候经过设置overflow:hidden把其变为BFC,那么就能够包含浮动元素了。
BFC的说明到此就告一段落了,如今回到最初讨论的haslayout的问题。ie7及如下ie版本不支持BFC的,但有私有属性haslayout,因而咱们能够经过触发元素的haslayout来达成bfc的类似效果。
一、浮动元素与普通元素之间产生3px bug
//代码以下 <style> .test {width: 800px;margin: 10px auto;border: 1px solid brown;height: 30px;} .float {float: left;background: saddlebrown;color: #fff;} } </style> <div class="test"> <div class="float">我是浮动元素</div>我是后面的文字,用来测试3px的bug </div>
正常状况:
ie6下:
解决方式:加一个ie6的hack:*margin-right:-3px;
不仅是文字,ie6的浮动元素也会和内联元素产生3px的margin值。
正常状况:
ie6,7下:
解决方式同上。
二、块级元素与浮动元素不会重叠
<style> .test {width: 800px;margin: 10px auto;border: 1px solid brown;height: 30px;} .float {float: left;background: saddlebrown;color: #fff;} } </style> <div class="test"> <div class="float">我是浮动元素</div> <div style="background: #0079F5;height: 30px;">我是浮动元素后面的块级元素</div> </div>
正常状况:
ie6,7:
能够明显地发现ie6,7下块级元素跟浮动元素不能重叠。为何会发生这种状况呢?是由于我在块级元素上设置了高度。激活了ie下的haslayout属性。因而ie6把它以BFC相似的方式进行渲染。
解决方式:在块级元素外再包裹一层DIV。而且把内部DIVbackground的属性写在外层DIV上。
三、浮动闭合元素
这个问题其实不少人会遇到,上文也提到过,只是可能叫法不一样。
<style> .test {width: 800px;margin: 10px auto;border: 1px solid brown;} .float {float: left;background: saddlebrown;color: #fff;} </style> <div class="test"> <div class="float">我浮动啦!</div> </div>
正常状况:
注意那一条横线是.test的border,由于浮动元素脱离了文档流,故.test不能被撑起来。
ie6,7
ie彷佛妥妥的。其实不少状况下,咱们想要的是ie这种效果。在ie中,一个浮动元素老是隶属于包含它的容器。是由于.test设置了宽度,激活了haslayout属性。而在非ie浏览器中,咱们想要得到这种效果通常是在父盒子上加一个:after的伪对象来清除浮动,或者设置overflow:hidden来触发BFC。
插入提一下闭合浮动的广泛作法:
为须要闭合浮动的父元素加入clearfix的类。
.clearfix::after {content:"";display:block;height:0;clear:both;} .clearfix {zoom: 1;} //兼容ie6,7
四、ie下margin不塌陷
<style> .test {width: 800px;margin: 10px auto;} .float {float: left;background: saddlebrown;color: #fff;} </style> <div class="test"> <div class="float">我浮动啦!</div> <div style="margin-top:30px;">测试margin-top在ie下是否塌陷</div> </div>
正常状况:
ie6,7
float是浮动元素,她脱离了文档流,因此第二个DIV的margin-top相对的是其上级.test做用的。但咱们只是对第二个DIV设置margin-top。结果在chrome下,怎么连float也“产生了margin-top”呢。对比ie和chrome下的效果,是否是以为IE下的 解析会比较合理呢?
可是。别忘了影响margin-top/bottom
的一个重要规则——margin塌陷(margin collapsing)。
提到了margin
塌陷,咱们来看看margin
垂直方向上塌陷的一些条件:
水平margin
不会合并。
两个上下渲染相邻(不必定是兄弟节点)的块状元素在正常页面流状况下会发生 margin 合并。
浮动元素不会和任何元素(包括子孙节点)发生 margin
合并。
overflow!=visible
的元素不和任何元素发生margin
合并。
绝对定位的元素不和任何元素发生margin
合并。
inline-block
的元素不和任何元素发生margin
合并。
设置 clear
属性的元素不和任何元素发生margin
合并。
根元素不和任何元素发生margin
合并。
父节点和第一个子节点发生margin-top
合并。
若是最后一个子节点没有border
以及padding
,则和其父节点发生margin-bottom
合并。
注意低版本IE下特别是hasLayout对于margin
合并也有影响,从而也形成了包含的绝对定位元素的位置差别。
在现代浏览器下.test
块的高度并无被子元素第二个DIV的margin-top
撑开。反而自身拥有了30px的margin-top
。
而浮动块尽管脱离了文档流,但仍是受其父级限制的(这跟absolute
定位的元素层受限于其定义为relative
的父级同样)。因此float
仍是包含在test
之中,这样在chrome下看起来浮动块也拥有margin-top
,而事实上是由于test高度不撑开的结果。
这么说,chrome并无错咯,那么IE下又是怎么避开margin
塌陷的呢?问题就出在浮动上面,在ie下,元素浮动将触发其haslayout。就是这个缘由,使得在ie下意外(意外?)的就避开了margin
塌陷。
可是奇怪的是,若是给.test
加上border
,chrome的渲染状况就跟ie同样了,float没有拥有与第二个DIV相同的margin-top
值。而是紧贴.test
的顶部。以下图:
chrome:
ie6,7:
这个问题的缘由还须要研究一下。。。。若是有知道缘由的大神麻烦给留个言,,感激!
五、ie下margin-left/right失效
<style> .test {margin: 10px auto;border:1px solid darkred;} </style> <div class="test"> <div style="height:30px;margin:0 20px;border-bottom: 3px solid sandybrown;">测试失效的margin-left</div> </div>
正常状况:
ie6:
根据上图能够发现,ie下咱们为子DIV设置的margin
失效了。为何会发生这种状况,一样是是由于子DIV设置了高度,激活了haslayout。
解决办法:不为子DIV设置高度,或者把父盒子的haslayout也激活。
参考资料:
http://cssass.com/blog/2009/147.html
http://www.cnblogs.com/lhb25/p/inside-block-formatting-ontext.html
http://www.cnblogs.com/pigtail/archive/2013/01/23/2871627.html