分类目录归档:CSS

让IE6支持min-width

最新更新,在IE7中_width: expression中的表达示还会被计算,所以要考虑好脚本的兼容性。

最近和同事在搞一个自适应布局的页面改版,样式里用到了一些min-width,这个CSS属性在IE6里不被支持。要解决这个问题,网上大多数都是用IE的expression去解决的(不了解expression的同学看下http://msdn.microsoft.com/en-us/library/ms537634%28v=vs.85%29.aspx)。expression有个特点就是,当元素reflow/repaint的时候,它都会重复运算一次。虽说可以解决min-width的兼容问题,但是性能损耗太大了,而且页面上用的min-width越多,这个性能损耗会随之变大。下面是用expression实现min-width的代码

<style type="text/css">
#target {
	min-width: 800px;
	_width: expression(this.parentNode.clientWidth > 800 ? 'auto' : '800px');
	height: 100px;
	background: red;
}
</style>

为了解决用expression的性能损耗问题,我又考虑到用JavaScript去实现。思路很简单,就是把在expression里面的逻辑搬到window.onresize这个事件处理函数中,以达到重新布局的目的。但是问题又来了,想重新布局页面元素,就要拿到这个元素的句柄,如果是带有id的元素事情到不是很复杂,如果是在类选择器里用到了min-width,事情就不是那么容易了。虽然有jQuery之类的类库帮我们选择元素,但这也是一笔不小的性能开销,而且代码变得难于维护,要是日后对min-width有所更改的话,还要同时去改JS。

总结一下,碰到的问题有以下两点:

  1. 在CSS中用expression实现min-width会造成大量不必要的计算
  2. 在JS中用window.onresize重新设定元素宽度会涉及到:1),如何取元素句柄的问题;2),JS代码不够简洁难于维护,修改样式的同时还要改JS;

结合上面的分析,最好的情况就是在CSS定义里面为window绑定onresize事件处理函数,然后在函数里面对当前DOM元素实现重新布局。听起来不可思议的事情,在IE6中变得很容易,因为expression的本质就是一段js代码,在里面可以调用页面中声明的其它JS函数,可以写成_width: expression(someFunc(min-width-value));的形式。此处的someFunc是通过JS声明的函数,在里面实现对window.onresize的绑定,每当窗口改变的时候,将元素的宽度重新设置成min-width-value。在CSS定义中可以这么写 #target {min-width: 800px; _width: expression(someFunc(‘800px’)); } 样式的定义都放在一处,维护起来也容易,这样就解决了上述第二点的问题。

到目前为止,当元素需要reflow/repaint的时候,expression还是不断的去调用someFunc,这也是第一点问题。其实解决的办法很容易,就是在someFunc的最后一行调用 this.style.width=’auto’;这样在以后的重绘中width的值恒为auto,就不会重新计算expression了。至此所以问题都已解决。下面就是真实的代码了。

<!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" xml:lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=GBK" />
	<title>测试IE6的min-width</title>
	<style type="text/css">
	#target {
		min-width: 800px;
		_width: expression(minWidth(this, 800)); 
		height: 100px;
		background: red;
	}
	</style>
</head>
<body>
	<div id="target"></div>
	<script type="text/javascript">
	(function() {
		var isIE6=!-[1,]&&!window.XMLHttpRequest,
			elements = [];
		
		function reflow(elem, value) {
			elem.style.width = elem.parentNode.clientWidth > value ? 'auto': value + 'px';
		}
		
		window.minWidth = function(elem, value) {
			if(isIE6) {
				reflow(elem, value);
				elements.push({
					'elem': elem,
					'value': value
				});
			} else {
				elem.style.width = 'auto';
			}
		};
		
		if(isIE6) {
			var timer;
			window.attachEvent('onresize', function() {
				var handler = arguments.callee;
				
				clearTimeout(timer);
				timer = setTimeout(function() {
					// 注销掉事件,防止reflow里触发onresize而导致的死循环
					window.detachEvent('onresize', handler);
					for(var i = 0, len = elements.length; i < len; i++) {
						var element = elements[i];
						reflow(element.elem, element.value);
					}
					window.attachEvent('onresize', handler);
				}, 50);
			});
		}
	}());
	</script>
</body>
</html>

有一点值得注意,就是如何在expression中拿到元素的句柄。

弹出窗口的兼容方案

<!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>
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
	<title>主页面</title>
	<style type="text/css">
	html, body {
		margin: 0;
		padding: 0;
	}
	body {
	}
	#div1 {
		height: 2000px;
	}
	#floatedLayer {
		position: fixed;
		_position: absolute;
	}
	</style>
</head>
<body>
	<div id="floatedLayer">
		<iframe src="demo.html" width="580" height="542" frameborder="no"></iframe>
	</div>
	<div id="div1"></div>
	<script type="text/javascript">
		var floatedLayer = document.getElementById("floatedLayer");
		function adjustPopupWin() {
			var height = document.documentElement.clientHeight,
				width = document.documentElement.clientWidth;				
			floatedLayer.style.left = Math.max((width - floatedLayer.offsetWidth) / 2, 0) + "px";
			floatedLayer.style.top = Math.max((height - floatedLayer.offsetHeight) / 2, 0) + "px";
		}
	</script>
	<!--[if IE 6]>
	<script type="text/javascript">
		function adjustPopupWin() {
			var height = document.documentElement.clientHeight,
				width = document.documentElement.clientWidth;
			floatedLayer.style.left = Math.max((width - floatedLayer.offsetWidth) / 2, 0) + document.documentElement.scrollLeft + "px";
			floatedLayer.style.top = Math.max((height - floatedLayer.offsetHeight) / 2, 0) + document.documentElement.scrollTop + "px";
		}
		window.onscroll = adjustPopupWin;
	</script>
	<![endif]-->
	<script type="text/javascript">
		window.onresize = adjustPopupWin;
		adjustPopupWin();
	</script>
</body>
</html>

底部浮动条的一种兼容方案

Demo

原理:在标准浏览器下用position: fixed的方式就可以了。IE6下面用overlay.className = overlay.className迫使浏览器重新布局,以达到position: fixed的效果。

<!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" xml:lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
	<title>出师表</title>
	<style type='text/css'>
	html, body {
		margin: 0;
		padding: 0;
	}
	body {
		/* 这里不能加position: relative */
	}
	#content {
		font-family: 微软雅黑;
		font-size: 36px;
		line-height: 60px;
		width: 960px;
		margin: 0 auto;
	}
	#content p {
		text-indent: 2em;
	}
	#overlay {
		opacity: .5;
		filter: alpha(opacity=50);
		background: #ccc;
		width: 100%;
		height: 100px;
		position: fixed;
		_position: absolute;
		bottom: 0;
	}
	</style>
</head>
<body>
	<div id='content'><p>先帝创业未半,而中道崩殂;今天下三分,益州疲敝,此诚危急存亡之秋也。然侍卫之臣,不懈于内;忠志之士,忘身于外者:盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气;不宜妄自菲薄,引喻失义,以塞忠谏之路也。宫中府中,俱为一体;陟罚臧否,不宜异同:若有作奸犯科,及为忠善者,宜付有司,论其刑赏,以昭陛下平明之治;不宜偏私,使内外异法也。侍中、侍郎郭攸之、费依、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下:愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰"能",是以众议举宠为督:愚以为营中之事,事无大小,悉以咨之,必能使行阵和穆,优劣得所也。亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也!侍中、尚书、长史、参军,此悉贞亮死节之臣也,愿陛下亲之、信之,则汉室之隆,可计日而待也。</p><p>臣本布衣,躬耕南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,谘臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间:尔来二十有一年矣。先帝知臣谨慎,故临崩寄臣以大事也。授命以来,夙夜忧虑,恐付托不效,以伤先帝之明;故五月渡泸,深入不毛。今南方已定,甲兵已足,当奖帅三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都:此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、依、允等之任也。愿陛下托臣以讨贼兴复之效,不效则治臣之罪,以告先帝之灵;若无兴复之言,则责攸之、依、允等之咎,以彰其慢。陛下亦宜自谋,以谘诹善道,察纳雅言,深追先帝遗诏。臣不胜受恩感激!今当远离,临表涕泣,不知所云。</p>
	</div>
	<div id='overlay'></div>
<!--[if IE 6]>
<script type="text/javascript">
(function(){
	var overlay = document.getElementById('overlay'), t;
	window.onscroll = function() {
		t && clearTimeout(t);
		t = setTimeout(function() {
			// reflow
			overlay.className = overlay.className;
		}, 13);
	};
})();
</script>
<![endif]-->
</body>
</html>

自定义样式的input[type=range]

今天下午有人在群里提出个问题,能不能把自定义样式应用到HTML 5中的range元素上。晚上研究了一下,是可以实现上述的需求的。请用Chrome查看Demo。代码如下:

<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
	<title>自定義樣式的input[type=range]</title>
	<style type="text/css"> 
	#range {
		width: 600px;
		height: 10px;
		background: rgba(60, 114, 230, .8);
		border: 1px solid #333;
		-webkit-border-radius: 5px;
		-webkit-appearance: none !important;
	}

	#range::-webkit-slider-thumb{
		width: 28px;
		height: 28px;	
		
		background: -webkit-gradient(
			linear,
			left top,
			left bottom,
			from(#fff),
			to(#ccc)
		);
		
		border: 1px solid #000;
		-webkit-box-shadow: 0 0 6px #000;
		-webkit-border-radius: 14px;
		-webkit-appearance: none !important;  
	}
	
	#result {
		border: 2px solid #ccc;
		width: 32px;
	}
	</style>
</head>
<body>
	<input type='range' min='0' max='1000' value='0' id='range' />
	<input type='text' id='result'/>
	<script type='text/javascript'>
	var result = document.getElementById('result');
	document.getElementById('range').onchange = function() {
		result.value = this.value;
	}
	</script>
</body>
</html>

代码中的”-webkit-appearance: none !important”很重要,要先把-webkit-appearance设置为none才能自定义样式。

让IE支持RGBa的背景色

文章部分内容来自:RGBa Browser Support

老版本的IE不支持RGBa的背景色,不过我们可以用滤镜实现同样的效果。上代码:

<!DOCTYPE html>
<html>
	<head>
		<title>Demo</title>
		<style type="text/css">
			#div1 {
				padding: 10px;
				width: 380px;
				height: 205px;
				background: url(shuizhu.jpg);
			}
			#div2 {
				color: #FFF;
				font-size: 40px;
				font-weight: bold;
				text-align: center;
				
				height: 205px;
				line-height: 205px;
				background: rgba(125, 0, 0, .3);
				filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#4B7D0000
						,endColorstr=#4B7D0000);
			}
		</style>
	</head>
	<body>
		<div id="div1">
			<div id="div2">	
				Hello world!
			</div>
		</div>
	</body>
</html>

DXImageTransform.Microsoft.gradient滤镜里的startColorstr参数值是#AARRGGBB形式的,其中的AA是代表不透明度的十六进制,00表示完全透明,FF就是全不透明,化成十进制的范围就是0~255,剩下的RRGGBB就是颜色的十六进制代码。例子中background: rgba(125, 0, 0, .3);表示的是30%不透明度的红色背景。如何把30%的不透明度转换成十六制呢?很简单,先计算#AA的的十进制x,x/255 = 3/10,解得x=3*255/10,然后再把x换算成十六进制,约等于4B。

下面附上示例中用到的图片:

有关.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。