标签归档:CSS

有关.clearfix的一些事

一,什么是.clearfix

很多网站都讲到一个盒子清除内部浮动时可以用到.clearfix。

.clearfix:after {
	content: " ";
	display: block;
	clear: both;
	height: 0;
}
.clearfix {
	zoom: 1;
}
<div class="clearfix">
	<div class="floated"></div>
</div>

上面的代码就是.clearfix的定义和应用,简单的说下.clearfix的原理:

  • 在IE6, 7下zoom: 1会触发hasLayout,从而使元素闭合内部的浮动。
  • 在标准浏览器下,.clearfix:after这个伪类会在应用到.clearfix的元素内部插入一个clear: both的块级元素,从而达到清除浮动的作用。这时的代码相当于:
    <div>
    	<div class="floated"></div>
    	<div style="clear: both"></div>
    </div>

二,总结

在IE6, 7下面只要是触发了hasLayout的元素就可以清除内部浮动了。而在标准浏览器下面清除元素内部浮动的方法有很多,大多数的情况下.clearfix:after都可以满足需求。除了.clearfix:after这种方式,其余的方法无非就是产生新的Block Formatting Context以达到目的……

白话Block Formatting Context

转载须写明出处,附带本文链接。关于文中的示例,用标准浏览器查看。

一,啥是Block Formatting Context

当涉及到可视化布局的时候,Block Formatting Context提供了一个环境,HTML元素在这个环境中按照一定规则进行布局。一个环境中的元素不会影响到其它环境中的布局。

为了让我们有个感性的认识,举个不太合适的例子。你可以把一个页面想象成大的集装箱,这个集装箱里装的货物就是HTML元素。在现实生活中为了避免不同人的货物相互混淆,都是把货物打好包装再装入集装箱,这样的话无论你包装里面的货物怎么摆放,都不会影响到其他人的货物。那么这个包装就可以被想象成Block Formatting Context。

二,怎样才能形成Block Formatting Context

当一个HTML元素满足下面条件的任何一点,都可以产生Block Formatting Context

  • float的值不为none。
  • overflow的值不为visible。
  • display的值为table-cell, table-caption, inline-block中的任何一个。
  • position的值不为relative和static。

三,Block Formatting Context在生产中有什么作用

  1. Block Formatting Context可以阻止边距折叠(margin collapsing)。我们知道在一般情况下,两个上下相邻的盒子会折叠它们垂直方向接触到的边距,这种情况只会发生在同一个Block Formatting Context中。换句话说,在同一个布局环境中(Block Formatting Context)是边距折叠的必要条件。这也就是为什么浮动的元素和绝对定位元素不会发生边距折叠的原因(当然还有很多种情况也不会折叠)。

  2. Block Formatting Context可以包含内部元素的浮动。考虑一下下面的例子(请用标准浏览器查看):
    <!DOCTYPE html>
    <html>
    <head>
    	<title>Demo</title>
    	<style type="text/css">
    		html, body {
    			margin: 0;
    			padding: 0;
    		}
    		#red, #orange, #yellow, #green {
    			width: 100px;
    			height: 100px;
    			float: left;
    		}
    		#red {
    			background: red;
    		}
    		#orange {
    			background: orange;
    		}
    		#yellow {
    			background: yellow;
    		}
    		#green {
    			background: green;
    		}
    	</style>
    </head>
    <body>
    	<div id="c1">
    		<div id="red"></div>
    		<div id="orange"></div>
    	</div>
    	<div id="c2">
    		<div id="yellow"></div>
    		<div id="green"></div>
    	</div>
    </body>
    </html>

    在上面的代码本意是做一个两行两列的布局,但是由于#red, #orange, #yellow, #green这四个div同在一个布局环境中,即便通过#c1, #c2这两个div划分,浮动之后它们还会一个接着一个排列,并不会换行。我们要做的就是把这四个div两两划分到不同的布局环境之中,从而闭合浮动。通过上面的分析,让#c1形成新的Block Formatting Context就可以解决问题。

  3. Block Formatting Context可以阻止元素被浮动覆盖。请看示例:
    <!DOCTYPE html>
    <html>
    <head>
    	<title>Demo</title>
    	<style type="text/css">
    		html, body {
    			margin: 0;
    			padding: 0;
    		}
    		#left {
    			width: 100px;
    			height: 100px;
    			background: red;
    			float: left;
    		}
    		#right {
    			height: 200px;
    			background: yellow;
    		}
    	</style>
    </head>
    <body>
    	<div id="left"></div>
    	<div id="right"></div>
    </body>
    </html>

    在标准浏览器下可以看到,普通的#right元素被浮动的#left元素所覆盖了。要想避免这种情况,有一种方法就是让#right形成新的Block Formatting Context。但是这里一定要注意的是,浮动不会覆盖的只是Block Formatting Context的border-box。换句话说,形成Block Formatting Context元素的margin还是会被浮动所覆盖掉的。

如果想全面了解Block Formatting Context,请看CSS 101: Block Formatting Context这篇文章。

:after伪类的小应用

<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<style type="text/css">
h1[id]:hover::after {
content: " #"attr(id);
}
</style>
</head>
<body>
<h1 id="test">测试标题</h1>
</body>
</html>

注:h1[id]只选择有id属性的h1标签。

用CSS禁用输入法

用简单的一行CSS就可以在表单元素里禁用输入法。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>TEST</title>
	<style type="text/css">
		.ime-disabled {
			ime-mode: disabled;
		}
	</style>
	<script type="text/javascript">
	</script>
</head>
<body>
	<input type="text" /><br />
	<input class="ime-disabled" type="text" />
</body>
</html>

不一定兼容所有浏览器,目前测试过并且支持ime-mode的有IE6和FF。

IE6中选择器的BUG

请仔细观察下面的代码,在FF中是正常显示的,但在IE6中字体变成了红色。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>TEST</title>
	<style type="text/css">
		.span.text a {
			color: red;
		}
	</style>
</head>
<body>
	<span class="text"><a href="#">IE6下是红的</a></span>
</body>
</html>

象.a.b与.a.b.c这种写法,ie6只能识别最后一个选择器,也就是.b和.c。

触发hasLayout引起的BUG

在IE6下面,很多显示的BUG都可以用触发hasLayout的方式去解决。但有种情况正好相反,触发hasLayout之后会产生显示的BUG。请看下面的代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>Demo</title>
	<style type="text/css">
		#div1 {
			background: red;
			margin: 10px;
			padding: 10px;
		}
		#div2 {		
			background: gray;
			margin: 30px;
			padding: 10px;
		}
	</style>
</head>
<body>
	<div id="div1">
		<div id="div2">TEST</div>
	<div>
</body>
</html>

上面的代码在所有浏览器里是正常显示的,包括IE6。但是给#div1设定宽度之后(触发hasLayout),经过大量测试,在IE6下#div1上面的padding会消失。有兴趣的同学可以看这篇文章:IE7-/Win: Margin collapsing and hasLayout

目前解决的办法就是去掉#div1的宽度,然后在#div1外面套一层div,在这个新div上设定宽度。解决问题的代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>Demo</title>
	<style type="text/css">
		#con {
			width: 400px;
		}
		#div1 {
			background: red;
			margin: 10px;
			padding: 10px;
		}
		#div2 {		
			background: gray;
			margin: 30px;
			padding: 10px;
		}
	</style>
</head>
<body>
	<div id="con">
		<div id="div1">
			<div id="div2">TEST</div>
		<div>
	</div>
</body>
</html>

IE6是支持!important的

由于本人最近沉迷于iPhone不能自拔,所以很久没有更新博客了。转入正题:

网上很多讲CSS HACK的教程都有这样的内容,如果想写一个让FF、IE7、IE8可以识别,并且IE6不能识别的CSS HACK,就用!important。造成的结果就是很多人以为!important在IE6下根本不支持,本人当时就是受害者之一。!important在CSS1中就有描述,链接如下:http://www.w3.org/TR/CSS1/#important。为什么会造成IE6不支持的假象呢,原因是IE6有BUG。在IE6中,下面的这段代码显示是不正确的。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Demo</title>
    <style type="text/css">
		div {
			width: 100px;
			height: 100px;
			background: red !important;
			background: yellow;
		}
	</style>
</head>
<body>
	<div></div>
</body>
</html>

在标准浏览器下,这个DIV应该是红色的,但在IE6下是黄色的。这个只能说是IE6的BUG,而不能说IE6完全不支持!important。如果把上面的代码改为:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Demo</title>
    <style type="text/css">
		div {
			width: 100px;
			height: 100px;
			background: red !important;
		}
		div {			
			background: yellow;
		}
	</style>
</head>
<body>
	<div></div>
</body>
</html>

怎么样,可以正常显示了吧。同理,下面的代码在IE6下也可以正确显示的。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Demo</title>
    <style type="text/css">
		div {
			width: 100px;
			height: 100px;
			background: red !important;
		}
		#div1 {			
			background: yellow;
		}
	</style>
</head>
<body>
	<div id="div1"></div>
</body>
</html>

结论:作为CSS优先级别的老大,!important是全浏览器兼容的。

消失的列表背景

IE6中设定了position: relative; float: left的容器下,如果存在着多个带有背景的列表,那么这些列表中有一部分会显示不正常,具体的表现为背景消失。例如下面的代码(请在IE6中查看):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>TEST</title>
</head>
<style type="text/css">
	#container {
		position: relative;
		float: left;
	}
	#container li {
		background: red;
	}
</style>
<body>
	<div id="container">
		<ul>
			<li>Hello Kitty</li>
			<li>Hello Kitty</li>
			<li>Hello Kitty</li>
			<li>Hello Kitty</li>
			<li>Hello Kitty</li>
		</ul>
		<ul>
			<li>Hello Kitty</li>
			<li>Hello Kitty</li>
			<li>Hello Kitty</li>
			<li>Hello Kitty</li>
			<li>Hello Kitty</li>
		</ul>
		<ul>
			<li>Hello Kitty</li>
			<li>Hello Kitty</li>
			<li>Hello Kitty</li>
			<li>Hello Kitty</li>
			<li>Hello Kitty</li>
		</ul>
	</div>
</body>
</html>

解决的方法是给li也加上position: relative。这个BUG的具体描述,请参考:http://www.positioniseverything.net/explorer/ie-listbug.html

IE6,IE7中负缩进的问题

在IE6,IE7下面给display: inline-block的元素设置text-indent: -9999px会把这个元素以及后面的元素拉走。请在IE6和IE7下,查看演示

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>TEST</title>
	<style type="text/css">
		.bar {
			border: 1px solid;
			display: inline-block;
			height: 18px;
		}
		.bar .icon {
			display: inline-block;
			width: 16px;
			height: 16px;
			background: red;
			text-indent: -9999px;
		}
	</style>
	<!--[if lte IE 7]>
	<style type="text/css">
		.bar {
			display: inline;
		}
	</style>
	<![endif]-->
</head>
<body>
	<input type="text" />
	<div class="bar">
		<span class="icon"></span>
		<span>HELLO KITTY HELLO KITTY HELLO KITTY</span>
	</div>
</body>
</html>

在IE6,IE7下可以看到.bar里面的内容都没有了。最开始的想法是让.icon浮动来解决这个问题,可是用css hack给.icon加上float: left居然不起作用,.icon后面的文字仍然被拉走。这时候只好在blueidea求助,结果那里的版主(yoom)想法和我的一样,让.icon浮动,但是他比我多加了个display: block,最终这个BUG被修正了。正常情况下,span元素加上float之后就已经是block级别了,但就是这个display: block起了决定性的作用,按yoom的话说,真是无心插柳啊。

最终的CSS HACK为:

<!--[if lte IE 7]>
<style type="text/css">
	.bar {
		display: inline;
	}
	.bar .icon {
		display: block;
		float: left;
	}
</style>
<![endif]-->

断头台(Guillotine)

Guillotine是一个在IE6下的BUG。表现的形式为:当鼠标放在一些链接上,浮动元素的下部会被裁剪掉。请用IE6查看演示

如何触发

如果让Guillotine“正常工作”,要满足下面几点:

  1. 有一个block级的包含元素(#container),不要触发layout
  2. 在#container里有一个浮动的元素(#floated)。
  3. 在#float的后面有一些a标签,并且在a:hover里面要改变background。

其中第三点改变background很重要,经过测试如果不改变background,则在上面的条件下不会触发这个BUG。

如何修复

修复这个BUG有下面几个方法:

  1. 让#container触发layout。
  2. 在a:hover里面不要改变background。
  3. 在#container的后面添加一个清除浮动的元素。如:
    <div id="container">
    	<div id="floated">
    	...
    	</div>
    	<a href="#">断头台</a><br />
    	...
    </div>
    <div style="clear: both"></div>
    
  4. 在#floated的后面加上清除浮动的元素。(不推荐,会带来新BUG。)