您所在的位置:小祥子 » 编程 » CSS » 正文

hasLayout与Block formatting contexts的学习(下)

时间:2015-08-04 编辑:妙瞳 来源:CnBlogs

BFC布局规则

  • 内部的Box会在垂直方向,一个接一个地放置。
  • Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
  • 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
  • BFC的区域不会与float box重叠。
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  • 计算BFC的高度时,浮动元素也参与计算。
  • CSS3中,对这个概念做了改动:http://www.w3.org/TR/css3-box/#block-level0CSS3中,将BFC 叫做 flow root。

简单示例:
1.自适应两栏布局
代码如下:

	<!DOCTYPE html>
	<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>BFC</title>
		<style>
			body{
				width:350px;
				position:relative;
			}
			div.sidebar{
				float:left;
				width:100px;
				height:200px;
				background-color:#9deaf1;
			}
			div.main{
				height:300px;
				background-color:#5dc2f6;
			}
		</style>
	</head>
	<body>
		<div class="sidebar"></div>
		<div class="main"></div>
	</body>
	</html>

页面效果图:

上述示例,正好反映了BFC布局规则:每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
所以,sidebar虽然存在浮动,但main的左边依然与包含块的左边相接触。

2.BFC的区域不会与float box重叠。示例如下:

代码:

	<!DOCTYPE html>
	<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>BFC</title>
		<style>
			body{
				width:350px;
				position:relative;
			}
			div.sidebar{
				float:left;
				width:100px;
				height:200px;
				background-color:#9deaf1;
				
			}
			div.main{
				height:300px;
				background-color:#5dc2f6;
				overflow:hidden;
			}
		</style>
	</head>
	<body>
		<div class="sidebar"></div>
		<div class="main"></div>
	</body>
	</html>

页面效果图:

通过overflow:hidden;触发main的BFC,main区域没有与float的sidebar重叠。说明了BFC的区域不会与float box重叠。

3.计算BFC的高度时,浮动元素也参与计算。

	<!DOCTYPE html>
	<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>BFC</title>
		<style>
			div.wrapper{
				width:300px;
				border:2px solid #5dc2f6;
			}
			div.box{
				width:100px;
				height:200px;
				background-color:#9deaf1;
				border:2px solid #5dc2f6;
				float:left;
			}
		</style>
	</head>
	<body>
		<div class="wrapper">
			<div class="box"></div>
			<div class="box"></div>
		</div>
	</body>
	</html>

页面效果图:

我们通过

div.wrapper{
		width:300px;
		border:2px solid #5dc2f6;
		overflow:hidden;
}

overflow:hidden; 触发wrapper的BFC,
清除box的浮动带来的影响,得到的页面效果图如下:


因此说明:计算BFC的高度时,浮动元素也参与计算。

4.清除垂直边距重叠

代码:

	<!DOCTYPE html>
	<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>BFC</title>
		<style>
			div.box{
				width:100px;
				height:100px;
				background-color:#9deaf1;
				border:2px solid #5dc2f6;
			}
			div.m50{
				margin-bottom:50px;
			}
			div.m100{
				margin-top:100px;
			}
		</style>
	</head>
	<body>
		<div class="box m50"></div>
		<div class="box m100"></div>
	</body>
	</html>

页面效果图如下:

如图所示,Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。所以,两个div的垂直距离变成了100px,而不是150px了。

如果我们给第二个div套上一层wrapper,并且触发外层的BFC,那么两个div就不是同一个BFC的两个相邻的Box了,而是变成两个独立的BFC。

代码:

	<!DOCTYPE html>
	<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>BFC</title>
		<style>
			div.box{
				width:100px;
				height:100px;
				background-color:#9deaf1;
				border:2px solid #5dc2f6;
			}
			div.wrapper{
				overflow:hidden;
			}
			div.m50{
				margin-bottom:50px;
			}
			div.m100{
				margin-top:100px;
			}
		</style>
	</head>
	<body>
		<div class="box m50"></div>
		<div class="wrapper">
			<div class="box m100"></div>
		</div>
	</body>
	</html>

页面效果图如下:

垂直边距不再重叠,不是100px,而是150px了。

  • 总结

    以上事例都证明了:BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
    
    因为BFC内部的元素和外部的元素绝对不会互相影响,因此, 当BFC外部存在浮动时,它不应该影响BFC内部Box的布局,所以BFC通过改变自己的宽度,实现不与浮动box有重叠。同样的,当BFC内部有浮动时,为了不影响外部元素的布局,BFC计算高度时会包括浮动的高度。避免margin重叠也是这样的一个道理。

hasLayout与Block formatting contexts的实例分析

一. 在触发 hasLayout 的元素和创建了 Block Formatting Contexts 的元素中,浮动元素参与高度的计算

情况1:没有创建 Block formatting contexts 的块级非替换元素,触发了 IE 的 hasLayout。

分析以下代码:

	<!DOCTYPE html>
	<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>hasLayout 和 BFC</title>
		<style>
			div.wrapper{
				width:300px;
			}
			div#container{
				background-color:#9deaf1;
				zoom:1;
			}
			span#span1{
				background-color:#5dc2f6;
			}
			div#div1{
				width:150px;
				height:50px;
				background-color:#0576b0;
			}
			div#div2{
				float:left;
				background-color:#4dd5b3;
			}
		</style>
	</head>
	<body>
		<div class="wrapper">
	    		<div id="container">
        			<span id="span1">simple text</span>
					<div id="div1">in flow</div>
					<div id="div2">float:left</div>
			</div>
		</div>
	</body>
	</html>
  • container 没有创建 Block formatting contexts。
  • container 的 'zoom:1'设置,是为了触发 IE 中的 hasLayout;
  • container 的高度值为 auto,并且 'overflow' 的值为默认的 'visible';
  • span1是一个行内元素, div1 是一个处于普通流中的块元素;
  • div2 是一个浮动的块级元素。

根据 CSS2.1 规范第 10.6.3部分的高度计算规则,在进行普通流中的块级非替换元素的高度计算时,浮动子元素不参与计算。

所以,在进行 container 高度计算时,只受 span1 和 div1的影响,应该是它们两个的高度之和,所以最终container 的高度不包括div2的高度。

页面效果图在各浏览器的效果如下:
IE6 IE7:

IE8 Firefox Chrome Safari Opera:

当去掉container的zoom:1;各浏览器表现一致:

情况2:创建了 BFC的块级非替换元素,未触发 IE 的 hasLayout。

代码如下:

	<!DOCTYPE html>
	<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>hasLayout 和 BFC</title>
		<style>
			div.wrapper{
				width:300px;
			}
			div#container{
				background-color:#9deaf1;
				overflow:hidden;
			}
			span#span1{
				background-color:#5dc2f6;
			}
			div#div1{
				width:150px;
				height:50px;
				background-color:#0576b0;
			}
			div#div2{
				float:left;
				background-color:#4dd5b3;
			}
		</style>
	</head>
	<body>
		<div class="wrapper">
	    		<div id="container">
	        			<span id="span1">simple text</span>
				<div id="div1">in flow</div>
				<div id="div2">float:left</div>
			</div>
		</div>
	</body>
	</html>
  • container 的 ‘overflow:hidden;’ 创建了BFC;
  • container 的 ‘overflow:hidden;’,在 IE6 中未触发 hasLayout,但在 IE7中触发了 hasLayout;
  • container 的高度值为 ‘auto’;
  • span1是一个行内元素,div1是一个处于普通流中的块元素;
  • div2是一个浮动的块级元素。

页面效果图如下:

IE6:

IE7/IE8/Firefox/Chrome/Safari/Opera

可见,只要 container 创建了 BFC,其浮动子元素就会参与其高度计算(IE7是由于触发了hasLayout 导致与其它浏览器的效果相同)。

二.与浮动元素相邻的、触发了 hasLayout 的元素或创建了 BFC 的元素,都不能与浮动元素相互覆盖。

与浮动元素相邻的、触发了 hasLayout 的元素或创建了 Block formatting contexts的元素,都不能与浮动元素相互覆盖。如果浮动元素的两侧有足够的空间放置该元素,则元素会紧邻浮动元素放置,必要时,该元素的宽度将会被压缩。否则它们可能会定位到浮动元素的下方。

情况1:没有创建BFC的块级非替换元素,触发了 IE 的 hasLayout。

代码:

	<!DOCTYPE html>
	<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>hasLayout 和 BFC</title>
		<style>
			div#container{
				border:2px solid #ddd;
				width:300px;
				height:150px;
				background:url("http://images0.cnblogs.com/
				blog2015/790006/201508/041827351894332.png") repeat;
			}
			div#div1{
				width:100px;
				height:100px;
				background-color:#9deaf1;
				float:left;
				filter:alpha("opacity=50");
				opacity: 0.5;
			}
			div#div2{
				background-color:green;
				zoom:1;
			}
		</style>
	</head>
	<body>
		<div id="container">
			<div id="div1">
				Float Block
			</div>
			<div id="div2"> 
				怀才就象怀孕,时间久了会让人看出来。
			</div>
		</div>
	</body>
	</html>

IE6:

IE7/IE8

Firefox/Chrome/Safari/Opera

根据 CSS 2.1 9.5 Floats 中的描述,浮动元素会覆盖普通流中的块容器。所以,div2 应该有一部分被 div1 覆盖。

情况2:创建了 BFC的块级非替换元素,未触发 IE 的 hasLayout。
代码:

		<!DOCTYPE html>
		<html lang="en">
		<head>
			<meta charset="UTF-8">
	<title>hasLayout 和 BFC</title>
		<style>
			div#container{
				border:2px solid #ddd;
				width:300px;
				height:150px;
				background:url("http://images0.cnblogs.com/
				blog2015/790006/201508/041827351894332.png") repeat;
			}
			div#div1{
				width:100px;
				height:100px;
				background-color:#9deaf1;
				float:left;
				filter:alpha("opacity=50");
				opacity: 0.5;
			}
			div#div2{
				background-color:green;
				overflow:hidden;
			}
		</style>
	</head>
	<body>
		<div id="container">
			<div id="div1">
				Float Block
			</div>
			<div id="div2"> 
				怀才就象怀孕,时间久了会让人看出来。
			</div>
		</div>
	</body>
	</html>

Firefox/Chrome/Safari/Opera:

IE6:

IE7/IE8

  • div1 是一个浮动元素,背景是50%的透明
  • div2 的 ‘overflow:hidden;’ 在 IE6 中未触发 hasLayout,但在 IE7 中触发了 hasLayout。
    根据 CSS 2.1 9.5 Floats 中的描述,创建了BFC的元素不能与浮动元素重叠, 所以,div2 应该有一部分被 div1 覆盖。

三. 触发 hasLayout 的元素和创建了 BFC的元素不会与它们的子元素发生外边距折叠

情况1:没有生成BFC的块级非替换元素,触发了 IE 的 hasLayout。

代码:

		<!DOCTYPE html>
		<html lang="en">
		<head>
			<meta charset="UTF-8">
			<title>hasLayout和BFC</title>
			<style>
				div.box{
					width:100px;
					height:100px;
					background-color:#9deaf1;
					border:2px solid #5dc2f6;
				}
				div.wrapper{
					zoom:1;
				}
				div.m50{
					margin-bottom:50px;
				}
				div.m100{
					margin-top:100px;
				}
			</style>
		</head>
		<body>
			<div class="box m50"></div>
			<div class="wrapper">
				<div class="box m100"></div>
			</div>
		</body>
		</html>

根据 CSS 2.1 8.3.1 Collapsing margins 第一条,两个相邻的普通流中的块框在垂直位置的空白边会发生折叠现象。
通过zoom:1;在IE中触发了hasLayout,所以,垂直边距不重叠,为150px。
而BFC未触发,所以垂直边距重叠,为100px;

IE6/IE7:

IE8/Firefox/Chrome/Safari/Opera:

情况2:生成 BFC的块级非替换元素,未触发 IE 的 hasLayout。
代码:

			<!DOCTYPE html>
			<html lang="en">
			<head>
				<meta charset="UTF-8">
				<title>BFC</title>
				<style>
					div.box{
						width:100px;
						height:100px;
						background-color:#9deaf1;
						border:2px solid #5dc2f6;
					}
					div.wrapper{
						overflow:hidden;
					}
					div.m50{
						margin-bottom:50px;
					}
					div.m100{
						margin-top:100px;
					}
				</style>
			</head>
			<body>
				<div class="box m50"></div>
				<div class="wrapper">
					<div class="box m100"></div>
				</div>
			</body>
			</html>
	

IE6:

IE7/IE8/Firefox/Chrome/Safari/Opera:

IE7此时触发了hasLayout,但IE6没有触发hasLayout。

hasLayout 和 BFC 的异同及可能产生的问题

区别

  • 在 IE8之前的版本中,没有规范中提及的 Block formatting contexts 和 Inline formatting contexts概念,而是用 hasLayout 来达到相似的目的。
  • 在 IE 中可通过设置 ‘width’、’height’、’min-width’、’min-height’、’max-width’、’max-height’、 ‘zoom’、’writing-mode’ 来触发 hasLayout,而这些特性值的设置不能够使元素创建 BFC。
  • 在 IE 中很多元素默认就是拥有布局的,如 IPUNT, BUTTON, SELECT, TEXTAREA 等,但是这些元素在标准中会形成 Inline formatting contexts。

共同点

  • 两者都是决定了对内容如何定位及大小计算的规则。
  • 两者都决定了与其他元素的相互作用的规则。
  • ‘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。

如有错误或者不足的地方,还望指正!----妙瞳

文章参考资料:
http://www.cnblogs.com/lhb25/p/inside-block-formatting-ontext.html
http://w3help.org/zh-cn/causes/RM8002

关键词:or 学习