在理想环境中,编写正确的CSS会在支持CSS的浏览器中正常的工作。不幸的事,我们并不是生活在理想环境中,浏览器有不少bug和不一致的地方。为了创建能在各种浏览器上显示相同样式的页面,CSS开发人员需要发挥创造性。通过利用bug和未实现的CSS,开发人员能够选择性的对不同的浏览器应用不同的规则。招数和过滤器是开发人员强大的工具。但是,正是因为强大,使用的时候才更应该谨慎。了解各种常用招数和它们的实现原理确实很重要,但是,了解在什么时候使用它们和什么时候不使用它们也同样重要。
过滤单独的样式表
将招数放在浏览器特定的CSS文件中,然后使用过滤器将它们发送给特定的浏览器,这会大大简化招数的管理。当前有两种主要的实现方法。一种方法是使用解析bug利用@import规则将特定CSS文件发送到适当的浏览器。一种是使用IE有条件注释。
IE有条件注释 是一种专有的(因此是非标准的)、对常规(X)HTML注释的Microsoft扩展。有条件注释可以使你根据条件(通常是浏览器版本)显示代码块。尽管是非标准的,但是有条件注释对于其他所有浏览器作为常规注释出现,因此是无害的。有条件注释在Windows IE 5中首次出现,并且的到了 Windows IE 所有后续版本的支持。
要想将一个特定的样式交给IE 5以及更高版本,那么可以在(X)HTML文档的开头放置以下代码:
<!-- [if IE] <style type="text/css"> @import ("ie.css"); </style> -->
Windows 上的IE5和更高版本会接收样式表 ie.css,而其他所有浏览器只会看到一段注释的文本。可以使用有条件注释指定一种特定浏览器,比如 IE 5.0:
<!-- [if IE 5] <style type="text/css"> @import ("ie50.css"); </style> -->
还可以指定一组浏览器,比如IE5.5和更高版本:
<!-- [if gte IE 5.5000] <style type="text/css"> @import ("ie55up.css"); </style> -->
或者IE 5 和 IE 5.5:
<!-- [if lt IE 6] <style type="text/css"> @import ("ie.css"); </style> -->
这种技术及其有效,而且非常容易记住。主要缺点是这些注释需要放在HTML中,而不是放在CSS中。如果在某一阶段你需要停止支持某种浏览器,就需要从页面中删除注释。如果这是个问题,那么可以考虑下面这个过滤器。
带通过滤器 是由Tantek Celik基于浏览器解析错误创建的一系列过滤器,它允许使用@import规则将样式表提供给选择的浏览器。因为它们是CSS规则,所以这些过滤器可以放在一个CSS文件中,这样就可以在一个地方集中控制过滤的文件。将招数隔离到浏览器特定的CSS文件中,可以大大简化对招数的管理。如果希望停止对某一个浏览器的支持,只需删除相关的样式表,而不需要在大量的页面代码中进行搜索和修改。
要想将CSS文件传递给 Windows上的IE 5和 5.5,可以使用Tantek的中通过滤器:
@media tty { i{content:"\";/*" "*/}} @import ‘ie5x.css‘; /*";} }/* */
这个过滤器看起来像一堆无意义的规则,对于许多浏览器来说却是如此。只能理解CSS1的浏览器不认识@media规则,因此会完全忽略它,能力更强的浏览器会看到@media规则中的一个声明。其目标是需找<i>元素,由于第二个引号前面有一个转义字符,content属性被认为是一个无意义的字符串。基本上,现代浏览器都会看到下面这样的规则:
@media tty { i { content:"Blah, blah, blah"; } }
转义字符是一个保留字符(通常是反斜线),它使解析器忽略后面的保留字符。所以,如果希望使用CSS content属性自动生成一个引号,那么必须对它进行转义,否则它就会结束前引号:blockquote:before{content:"\""}
tty媒体类型指的是终端和电传打印机。幸运的是,当前没有设备支持这种媒体类型,所以符合标准的浏览器实际上会忽略整个规则。
但是,IE5.X/Win不理解转义字符,所以会提前结束内容声明,后面的字符会结束<i>和@media规则,这导致应用@import规则,所有多余的字符都被注释掉,因此在IE5.x/Win看来整个规则像这样:
@media tty { i { content: "blah"; /* blah */ } } @import ‘ie5x.css‘; /* blah */
过滤单独的规则和声明
如果你的CSS文件比较小,而且只需要应用少数几个招数,那么可以将相关过滤器添加到主样式表中,但是,所有这些规则和声明特有的过滤器会给代码添加额外的负担和复杂性。
最安全的过滤器依赖于未实现的CSS,而不是浏览器BUG,因为这些过滤器使用有效地CSS选择器来应用有效的声明,所以严格的说,它们根本不是过滤器。它们仅仅是某些浏览器不能理解的有效的CSS规则。这些过滤器中的第一个称为子选择器招数。Windows上的IE6和更低版本不支持子选择器,所以可以使用它对这些浏览器隐藏规则。为了让这种过滤器起作用,必须确保在子选择器前后没有空格。
像下面这样,使用子选择器对IE5/6Win隐藏透明的背景PNG图像:
html>body { background-image: url(bg.png); }
IE7预期会支持子选择器,还可能会支持PNG透明度。通过以这种方式使用子选择器,就允许IE新版本看到透明背景,而不需要修改代码,因此提供了向前兼容性。
另一种过滤器的有效方法是使用属性选择器,许多现代浏览器支持属性选择器,但是IE6以及更低版本不支持它。因此,可以使用属性选择器在比较高级的浏览器中对类和ID应用样式。在这个示例中,使用属性选择器在符合标准的浏览器中将背景PNG应用于内容DIV:
div[id="content"] { background-image: url(bg.png); }
最著名且最有用的CSS过滤器之一是星号HTML招数。这个过滤器非常容易记住,它可以指定IE6和更低版本。HTML元素被认为是网页上的第一个元素(根元素)。但是,IE6和更低版本有一个匿名的根元素,它包围着HTML元素,可以使用通用选择器指定包围在另一个元素中的HTML元素,因为这种情况只有在IE6和更低版本中才会出现,所以可以将特定的规则应用于这些浏览器:
* html { font-size: small; }
在任何 CSS 选择器开头添加一个通用选择器和一个HTML类型选择器,就会对除IE 之外的所有浏览器隐藏这个规则,使用这个规则最常见的方法是:设置一个希望应用于除IE之外所有浏览器的规则,然后使用星号HTML招数在IE中覆盖这个规则。例如,IE将1像素的点线错误的显示为难看的虚线,为了避免这些难看的虚线,可以将锚上鼠标停留时的边框样式设置为点线,但是在IE6中覆盖这个规则,让它们显示实线:
a:hover { border: 1px dotted black; } * html a:hover { border-style: solid; }
这个bug不可能出现在其他浏览器中,并且在IE 7 中可能会被修复,因此,星号HTML招数提供了一种有效地指定IE6和更低版本的方法。
另一个有用的过滤器是注释反斜线招数。Mac上的IE5错误的允许在注释内部进行转义,这个过滤器的工作方法是在注释结束前面添加一个反斜线,其他所有浏览器都会忽略这个转义,并且应用后面的规则,但是,IE5/Mac会认为注释仍然没有结束,因此会把下一个结束注释之前的所有字符都忽略:
/* Hiding from IE5/Mac \*/ #nav a { width: 5em; } /* End hack */
如果结合使用星号HTML招数和注释反斜线过滤器,就成了Holly招数(这个名称来源于它的发明人 Holly Bergevin)。通过结合使用这两个规则,就可以对Windows上的IE6和更低版本应用规则:
/* Hiding from IE 5/Mac \*/ * html { height: 1px; } /* End Hack */
这对于修复Windows特有的所有IE Bug非常有用,它可能是目前最常用的过滤器之一。
有时候,可能希望在同一个规则中对Windows上的IE6和更低版本应用一个声明,对其他所有浏览器应用另外一个声明,为此,可以使用注释属性招数,也可以使用!important或下划线招数。
!important招数之所以能够起作用是因为Windows上的IE6和更低版本在处理单一规则中的多个属性方面有问题:
#nav { position:fixed !important; position: static; }
IE6和更低版本会忽略第一个声明并且应用第二个,其他所有浏览器会应用第一个声明,因为它使用了!Important关键字,这提高了此规则在层叠中的优先级。
下划线招数和!important招数非常相似,在属性前面放一个下划线,符合标准的浏览器就不再认识这个属性并且忽略这个声明,但是Windows上的IE6和更低版本会忽略下划线,因此应用这个规则。
#nav { position: fixed; _position: static; }
到目前为止,所有的过滤器针对的都是IE的各种版本,这在一定程度上是因为IE的bug比当前大多数浏览器都要多,然后,也是因为IE是目前最流行的浏览器,所以比较多的Bug被找到并记录下来,但是,其他浏览器也有bug,包括Opera 6和更低版本。
Owen招数使CSS作者能够对Opera6和更低版本以及windows 上的IE6和更低版本隐藏样式。这个过滤器之所以能够起作用是因为这些浏览器没有实现第一子选择器。因为只能有一个首部元素,所以它总是第一子元素。主体标签总是出现在首部标签的后面,所以可以使用相邻同胞元素选择器找到它,比较符合标准的浏览器都能够理解最终的选择器,但是Opera6以及Windows上的IE6和更低版本会忽略它。
下面的示例使用Owen招数为比较符合标准的浏览器在主体标签上添加一个背景PNG图像,而对IE6/Win和Opera6和更低版本隐藏它:
head:first-child+body { background-image: url("bg.png"); }
可以结合使用子选择器招数和Owen招数,从而只针对Opera6和更低版本。假设希望向Opera6和更低版本的用户显示一个升级提示,首先,使用子选择器在除了Windows上的IE6和更低版本的所有浏览器上显示升级消息。然后,使用Owen招数对除了Opera6和更低版本的浏览器隐藏这个消息:
html>body #getFirefox { display: static; } head:first-child+body #getFirefox { display: none; }