10.2.1 CSS Hack
开发人员基本都知道,CSS的开发本身并不难,但是,当在不同的浏览器下测试代码时,困难就出现了。浏览器的 bug 和不一致的显示方式,是大多数CSS开发人员面临的主要难题,你的设计在一种浏览器上看起来很好,而在另一种浏览器上可能会支离破碎。
实践证明,CSS的兼容性主要有两种情况:一种是对老版本IE的兼容性,一种是使用CSS3新特性后产生的兼容性。
对老版本IE的兼容性,主要通过CSS Hack和客户端脚本来解决;对使用CSS3新特性后产生的兼容性,主要通过浏览器私有前缀来解决。
CSS Hack
由于不同厂商的浏览器(如IE、Chrome、Firefox、Safari),或同一浏览器的不同版本(如IE6~IE11),对CSS的解析不完全一样,导致同一页面在不同浏览器中的效果可能不一致。
为了得到统一的效果,就需要针对不同浏览器,或同一浏览器的不同版本,编写不同的CSS,把这个过程就被称作CSS Hack。
实践证明,CSS Hack主要用来解决IE的兼容性问题。虽然它是强有力的工具,但应该谨慎使用,它一般作为修复问题的最后一道屏障,在不得已的时候才会使用。因为更重要的是跟踪、隔离和识别问题,而不是修复问题。只有真正了解问题背后的原理,才能找到最好的解决方案。
CSS Hack 有 3 种表现形式:
1)属性前缀或后缀法
即在定义样式规则时,为样式属性添加只有特定浏览器,或某浏览器特定版本才能识别的前缀或后缀。
前缀/后缀 | 适用版本 | 应用示例 |
---|---|---|
_ | IE6 | p { _color: blue; } |
- | IE6 | p { -color: blue; } |
+ | IE7 | p { +color: blue; } |
* | IE6/IE7 | p { *color: blue; } |
# | IE6/IE7/IE8 | p { #color: blue; } |
!important | IE7/IE8/IE9/IE10/IE11 | p { color: blue !important; } |
\9 | IE6/IE7/IE8/IE9/IE10/IE11 | p { color: blue\9; } |
\0 | IE8/IE9/IE10/IE11 | p { color: blue\0; } |
\9\0 | IE9/IE10/IE11 | p { color: blue\9\0; } |
在使用属性前缀或后缀法时,一般是将适用范围广、被识别能力强的写法写在前面,把特殊写法写在后面。如:
div {
background: blue;
background: green\9;
*background: black;
_background: orange;
}
由于所有浏览器都识别标准写法,而IE6/IE7/IE8/IE9/IE10/IE11可识别\9,IE6/IE7可识别*,IE6仅能识别_。根据CSS的叠加原理,后定义的属性会覆盖先定义的同名属性,就实现了为IE各版本和现代浏览器应用不同样式的目的。
2)选择器前缀法
即在CSS选择器前,添加只有特定浏览器或某浏览器特定版本才能识别的前缀,选择器和前缀之间用空格分隔。
常用的前缀有 *html 和 *+html,*html 是IE6特有的前缀,而 *+html 是IE7特有的前缀。如:
*html p { color: blue; } /* IE6 */
*+html p { color: blue; } /* IE7 */
3)条件注释法
条件注释是IE浏览器专有的,也是微软官方推荐的Hack方式。它是使用IE条件注释,针对不同IE版本,编写不同的CSS,来为不同版本的IE应用不同的样式。
一种方法是直接在条件注释中定义样式。如:
<style>
<!--[if IE 6]>
div {
display: inline;
}
<![endif]-->
</style>
虽然这种方法可以解决一些现实的问题,但这些注释需要放在HTML文件,而不是CSS文件中,样式定义散落在多个地方,不便于维护,也容易出错。也违背了内容与表现相分离的原则,故不推荐使用。
另一种方法是,编写不同的CSS文件,再使用IE条件注释,通过 <link> 标签,有针对性的加载外部样式表。如:
<!--[if IE 6]>
<link rel="stylesheet" href="css/ie6.css" />
<![endif]-->
这种方法却会增加IE用户的HTTP请求次数,影响访问速度。所以,在使用这种方法前,要仔细斟酌,判断是否真的有必要在自己的网站上使用它。
一个好消息是,从IE10版本开始,不再支持条件注释。这标志着IE从此走向成熟、走向标准,Web设计师再也不必为IE的兼容性问题所困扰了。
愿望是美好的,现实却是残酷的。很多WEB设计师仍然发现,相同的CSS,在IE9/10/11上的渲染效果,和其它现代浏览器还是不一样。
也就是说,我们仍然需要条件注释。那么,在不支持条件注释的IE10/11上,能够实现条件注释的效果呢?
答案是肯定的。并且,有多种方法可以实现条件注释的替代效果。并且,它们有各自的应用场景,可以根据需要选择使用。
方法一:使用IE = EmulateIE9属性,指示浏览器采用IE9渲染模式:
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9">
因为IE9是支持条件注释的,在页面的头部加入以上的元数据后,IE10/11就使用IE9的渲染模式,自然就能识别条件注释了。
很显然,这样做的弊端是,浏览器使用的是IE9的渲染模式,而不是最新的IE10/11的渲染模式。
方法二:使用媒体查询语句的 +-ms-high-contrast 属性,为不同浏览器应用不同的样式。
CSS 的媒体查询语句是一种高级的CSS条件语句,它能根据一些属性和属性值的计算结果,来判断CSS是否可以生效。
由于只有IE10/11实现了 -ms-high-contrast 属性,取值为active或none。因此,就可以使用以下媒体查询语句:
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
/* IE10+ CSS styles go here */
}
Firefox浏览器、Chrome浏览器不能识别这个属性,这个语句中的CSS就不会生效,便间接实现了条件注释的效果。
方法三:使用Javascript判断浏览器的类型,来为不同浏览器定义不同的样式。
先用Javascript 判断浏览器的类型,如果是IE浏览器,就在页面的 <html> 标签上添加一个 ie 的类名:
<script>
var ms_ie = false;
var ua = window.navigator.userAgent;
var old_ie = ua.indexOf("MSIE");
var new_ie = ua.indexOf("Trident/");
if ((old_ie > -1) || (new_ie > -1)) {
ms_ie = true;
}
if ( ms_ie ) {
document.documentElement.className += "ie ";
}
</script>
有了这个标志性 class 后,就可以在CSS中,区分不同的浏览器,并专门针对IE编写不同的CSS代码。如:
.testClass{
/* 这里写通用的css */
}
.ie .testClass{
/* 这里写专门针对IE的css */
}
事实上,这个方法还能区分老IE和新IE。因此,也可以区分老IE和新IE,并有针对性的编写不同的CSS代码。
方法四:使用IE10/11私有的条件编译特性,来区分IE6-9 和IE10/11。
<!--[if !IE]>
<script>
if (/*@cc_on!@*/false) {
document.documentElement.className += "ie10 ";
}
</script>
<!--<![endif]-->
上述脚本中,先使用条件注释 !IE来排除IE,以确保IE6-9不承认它。然后,再执行@ cc_on功能检测。