CSS Hack Table
This | 当前浏览器 | Y | 渲染 | N | 不渲染 | H | 部分版本或部分属性渲染 | B | 样式失效 |
---|
THIS | windows | Mobile | Linux | Mac | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
IE | Firefox | Chrome | Safari | Opera | Android | iOS | Firefox | Chrome | Opera | Safari | Firefox | Chrome | Opera | |||||||||||||
6 | 7 | 8 | 9 | 2 | 3 | 7 | 9 | 5 | 15 | 4 | 5 | 8 | 9 | 10 | 11 | 2.3 | 5.0 | 9 | 17 | 11 | 5 | 9 | 17 | 11 | ||
s1 | * html #selector | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
s2 | *+html #selector | N | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
s3 | *:first-child+html #selector | N | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
s4 | html>body #selector | N | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
s5 | html>/**/body #selector | N | N | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
s6 | #selector:not(x) | N | N | N | Y | Y | Y | Y | Y | Y | Y | Y | Y | N | N | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
s7 | body:last-child #selector | N | N | N | Y | Y | Y | Y | Y | Y | Y | Y | Y | N | N | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
s8 | body:nth-of-type(1) #selector | N | N | N | Y | N | H | Y | Y | Y | Y | Y | Y | N | N | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
s9 | body:first-of-type #selector | N | N | N | Y | N | H | Y | Y | Y | Y | Y | Y | N | N | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
s10 | html[lang] #selector | N | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
s11 | :root *> #selector | N | N | N | Y | Y | Y | Y | Y | Y | Y | Y | Y | N | N | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
s12-1 | #selector, x:-moz-any-link | N | Y | N | N | Y | Y | Y | Y | N | N | N | N | N | N | N | N | N | N | Y | N | N | N | Y | N | N |
s12-2 | #selector, x:-webkit-any-link | N | Y | N | N | N | N | N | N | Y | Y | Y | Y | N | N | N | N | Y | Y | N | Y | N | Y | N | Y | N |
s13-1 | #selector, x:-moz-any-link, x:default | N | Y | N | N | N | Y | Y | Y | N | N | N | N | N | N | N | N | N | N | Y | N | N | N | Y | N | N |
s13-2 | #selector, x:-webkit-any-link, x:default | N | Y | N | N | N | N | N | N | Y | Y | Y | Y | N | N | N | N | Y | Y | N | Y | N | Y | N | Y | N |
s14 | body:not(:-moz-handler-blocked) #selector | N | N | N | N | N | H | Y | Y | N | N | N | N | N | N | N | N | N | N | Y | N | N | N | Y | N | N |
s15 | html:first-child #selector | N | N | N | N | N | N | N | N | N | N | N | N | Y | H | N | N | N | N | N | N | N | N | N | N | N |
s16 | #selector,x:ie | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
p1 | property:value\9; | Y | Y | Y | Y | N | N | N | N | N | N | N | N | B | B | N | N | N | N | N | N | N | N | N | N | N |
p2 | property:value!ie; | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
p3 | *property:value; | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
p4 | _property:value; | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
p5 | property /**/:value; | N | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
p6 | property /*\**/:value\9; | N | Y | Y | Y | N | N | N | N | N | N | N | N | B | B | N | N | N | N | N | N | N | N | N | N | N |
p7 | property: /*\**/value\9; | N | N | Y | Y | N | N | N | N | N | N | N | N | B | B | N | N | N | N | N | N | N | N | N | N | N |
p8 | property:value\0/; | N | N | Y | H | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
p9 | property:value\0; | N | N | Y | Y | Y | N | N | N | N | N | N | N | B | B | Y | Y | N | N | N | N | Y | N | N | N | Y |
m1 | @media screen and (-webkit-min-device-pixel-ratio:0){...} |
N | N | N | N | N | N | N | N | Y | Y | Y | Y | N | Y | N | N | Y | Y | N | Y | N | Y | N | Y | N |
m2 | @-moz-document url-prefix(){...} | N | N | N | N | Y | Y | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
m3 | @media screen\9{...} | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
m4 | @media \0screen\,screen\9{...} | Y | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
m5 | @media \0screen{...} | N | N | Y | N | Y | H | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |
m6 | @media screen\0{...} | N | N | Y | Y | Y | H | N | N | N | N | N | N | N | Y | Y | Y | N | N | N | N | Y | N | N | N | Y |
THIS | 6 | 7 | 8 | 9 | 2 | 3 | 7 | 9 | 5 | 15 | 4 | 5 | 8 | 9 | 10 | 11 | 2.3 | 5.0 | 9 | 17 | 11 | 5 | 9 | 17 | 11 | |
IE | Firefox | Chrome | Safari | Opera | Android | iOS | Firefox | Chrome | Opera | Safari | Chrome | Firefox | Opera | |||||||||||||
windows | Mobile | Linux | Mac |
如何使用
必须明确一点,我个人抵制任何Hack。之所以做出这张表,是出于对一个时期的缅怀,这同时也是我给IE6/7树立的一座墓碑。
把hack的种类分成三种的话,分别是选择器hack、属性hack和Query Hack。将它们分类标号,开头分别是s、p、m。点击This一列里的标号,就可以查看我对于这个hack的简单说明。
这里列举都是原子hack,即实际使用中,可以是一种或者任意数种的任意组合,以交集获得特定浏览器正确渲染——当然这也是极其糟糕的做法——就如同每一种武器都可以是凶器,组合几种就成了大杀器...决不放弃使用武力,因为往往总有些时候,不可避免。
尽管我花了大量的时间测试,但是一个人的精力毕竟有限,错误在所难免。如果你发现任何问题,请联系我 iifksp[at]swordair.com,非常感谢。
选择器Hack
选择器Hack主体式基于浏览器对选择器的支持度,当然也有很多bug被利用。
s1: * html #selector
Star HTML hack,仅IE6及以下支持渲染,所有其他浏览器均不支持,可能是最为常用也是最为滥用的hack写法。W3C标准规定 html
作为其DOM的根元素,但是从IE4开始直到IE6,IE的 html
之上还有一个以 *
选取的根元素。所以标准浏览器忽略此条规则,仅IE4-6匹配。这条hack能通过CSS验证,但因为使用了 *
通配符而为人诟病,虽然应用广泛但会造成一些不良影响。
s2: *+html #selector
IE7的出现虽然修复了IE6根节点选择的错误,但是同时也带来了新的问题。这条hack仅在IE7标准模式及IE8的兼容模式(IE7标准)中正常渲染,其他浏览器、IE8标准模式、IE7怪异模式均忽略。与s1相同,可以通过CSS验证。
s3: *:first-child+html #selector
作用和说明同s2。值得一提的是,经过我的测试,这条规则并非完全等值于s2,当使用IE9并调整到IE7标准模式的情况下,这条hack是无效——非滤镜的css在IE9的开发模式下失效并不常见。
s4: html>body #selector
从IE7开始才支持的子元素选择器(child selector)区分了IE7及之前版本,除了IE6-以外,所有浏览器正常渲染。子元素选择器将选择结果限定在了父节点的直接子元素,是因为IE6的存在而大范围使用受限的选择器之一。
s5: html>/**/body #selector
尽管如s4所述,IE7实现了子元素选择器,但是简单地在IE7子元素选择器的代码里添加空注释就能让IE7无法识别这条CSS规则,从而也将IE7排除在外。当前除了IE6与7,所有的浏览器都能正确渲染。
s6: #selector:not(x)
:not
是CSS3里的一个伪类,称为“否定伪类”,用于否定的描述性运算。hack里的 x
只是占位,其可以是任意支持的其它简单选择器。由于是使用CSS3的特性,所以IE8-、Opera9-均不支持。同理,其它CSS3伪类也可以用来写同类hack,诸如 :empty
等。
s7: body:last-child #selector
:last-child
以及 :first-child
都是因为浏览器的支持不够而使用受限的超级方便的伪类(我都不知道我不得已写了多少 class="last-item"
了),也正因为如此它也被用来hack。表现同s6相同——IE8及以下、Opera9及以下直接忽略规则。
s8: body:nth-of-type(1) #selector
:nth-of-type
伪类用于公式化的选择,IE9、Safari 3+、chrome、opera 9+ 以及Firefox 3.5+支持。
s9: body:first-of-type #selector
识别度与s8相同,等价于s8。
s10: html[lang] #selector
[]
是属性选择器,本应被广泛使用,因为其在编写应对某些有特定属性的元素的样式时非常有用,仅IE6不支持。
s11: :root *> #selector
:root
伪类选中所有块的根元素。虽然现代浏览器普遍支持此伪类,但IE直到9才开始支持,所以 IE8-忽略此条规则。
s12-1: #selector, x:-moz-any-link
由于带有 -moz
前缀,所以只匹配Firefox(1+)。这种规则可以在Firefox默认的UA样式里(us.css)找到:
*|*:-moz-any-link { cursor: pointer; }
虽然每个版本不尽相同,但大都如上所示。webkit也有类似的 -webkit-any-link
。
IE7由于忽略x之后的值,所以也会诡异的匹配这条规则,可以通过添加s5的 html>/**/body
来过滤IE7。
s12-2: #selector, x:-webkit-any-link
s12-1的webkit版本,说明同s12-1。
s13-1: #selector, x:-moz-any-link, x:default
与s12-1类同,区别是Firefox从3.0才开始支持。
s13-2: #selector, x:-webkit-any-link, x:default
s13-1的webkit版本。
s14: body:not(:-moz-handler-blocked) #selector
-moz-handler-blocked
同样属于Mozilla的CSS 扩展,类似的属性可以在 Mozilla CSS Extensions 这个列表里找到,并都标明了所需Gecko版本。由于是专属,只有Firefix、Seamonkey、Thunderbird识别并正确渲染,其他浏览器则都会忽略。比如 -moz-handler-blocked
就需要 Firefox 3.5+。
s15: html:first-child #selector
:first-child
只匹配当前元素是其父元素第一个子元素的情况。但Opera 9.27以及其之前的版本会选中根元素 html
,即使它不是另一元素的子元素。
/* Opera 9.27 and below, safari 2 */
属性Hack
属性Hack里,出现的最多的就是反斜杠和注释。反斜杠是一个很特别的字符,其在属性里出现会被浏览器直接忽略(IE6+)。比如:
p\r\o\e\t\y:value; property:value;
这两条规则无异,浏览器都能正确识别并渲染。
而 \0
更为特别,作为C语言的字符值null、字符串的结尾,被用在Hack上也就不足为奇了。这也是为什么属性Hack以及下面的查询Hack多次出现这些字符的原因。
p1: property:value\9;
最为常见的IE hack之一,IE直到IE9都仍然识别这种属性值。
p2: property:value!ie;
属性之后的叹号后面可以出现任何字符串,在IE7-作用与 !important
相同,IE8以上则会忽略。
p3: *property:value;
著名的“Star Hack”,IE7-识别在之前加星号的属性,所以这条经常被用来Hack轻微的IE7-的渲染不一致。其实 *
只是我们最为常见的符号hack,在这个hack里,*
可以被下面的任何一种字符代替,效果完全一致。
! $ & * ( ) = % + @ , . / ` [ ] # ~ ? : < > |
甚至是上述字符的任意组合,IE7-都会忽略属性之前的这些字符就好像它们不存在一样,而无论属性之前有多少个这些字符。因此,看起来像是注释的这种下面这些写法其实也是这种hack的变种:
//background:skyblue; ##background:skyblue;
p4: _property:value;
针对于IE6-的被广泛使用的下划线hack,常常和p3的星号hack同时出现,用来重写IE6-的样式。和p3一样,规则中的字符 _
可以被替换成其它字符,并且任意替换和组合下面这些字符都是有效的:
_ - £ ¬ ¦
p5: property /**/:value;
除了IE6以外,所有浏览器都能正确识别注释。需要注意的是,这里的 property
与 /**/
之间的空格是必须的。如果没有空格,IE6也能正确识别。
p6: property /*\**/:value\9;
与p5不同的是,加入了 \9
hack之后,IE之外的浏览器全部忽略了这条规则。属性后的空格也是必须的。需要注意的是,此hack后的分号的有无对浏览器有影响:
- 如果有分号:IE7识别规则
- 如果无分号:IE7忽略规则
另外,如果使用了无分号的Hack,则不能再在同一个定义里添加规则,需要分别重新定义。
p7: property: /*\**/value\9;
写法与p6只有细微差别,空格同样必须。区别是IE7不再能识别。
p8: property:value\0/;
只有IE8能够识别的hack规则IE8识别此规则,IE9部分识别 订正[1],当被放在同一个定义里时,其必须被放置在所有规则之后。
p9: property:value\0;
标准的 \0
hack,IE高版本(8+)、Firefox低版本(2-)以及Opera(部分,具体见表),都能识别并渲染。
Query Hack
这里主要指的是Media Query,关于Media Query 可以参考我写的 CSS3 Media Queries 详解。这里的hack也同样多是特殊字符的增插。
m1: @media screen and (-webkit-min-device-pixel-ratio:0){...}
所有的webkit均匹配这条规则(safari 3+, chrome 1+),包括移动版。但经过我的测试,Opera 9.0会非常诡异的匹配这条Media Query。所以虽然这条规则在网上被广泛使用,却并非完美。
m2: @-moz-document url-prefix(){...}
仅Firefox(1.5+) 所支持的一种的限定URL的@样式规则,关于其说明可以参考Mozilla Developer Network的 @-moz-document
。是为数不多的针对Firefox的Media Query Hack。
m3: @media screen\9{...}
与这条规则神似的属性hack是p1,但IE的表现差别却很大。只有IE7及以下渲染这样的规则。
m4: @media \0screen\,screen\9{...}
与m3相比只是多了IE8的识别。
m5: @media \0screen{...}
只有IE8以及低版本Firefox识别并渲染。更为严格的3.6已经不再识别。
m6: @media screen\0{...}
更为标准的 \0
hack,相比m5多了IE9以及Opera的识别。可见 \0
仍然是神奇的。Opera的表现也与其在属性hack里的同类hack中保持一致,即如果 \0
出现在字符串值结束处,Opera就会识别这条规则。
参考资料:
- Browser CSS hacks by Paul Irish
- The two CSS Selector bugs in IE6 by Paul Irish
- In defense of CSS hacks — introducing “safe CSS hacks” by Mathias Bynens
- CSS hacks playground - the hunt for an IE8-only CSS hack by Mathias Bynens
- Personal CSS Hacks for IE6, IE7, IE8, IE9 by Dimox
- CSS filter: Will the browser apply the rule(s)? by KEVIN C SMITH
- CSS hacks by David Hammond
- CSS Hacks Targeting Firefox by Chris Coyier
- CSS filter by Wikipedia
- Improving the CSS 2.1 strict parser for IE 7 by IEBlog
- Selectors Level 3 by W3C
- @-moz-documentby Mozilla Developer Network
- CSS3 Media Queries 详解 by 葵中剑
感谢:
- 感谢 ATA 的 Neil,给了我第一份工作,以及学习的时间。
- 感谢我曾经的团队:阿里巴巴 AliExpress UED 的每一位,特别是团长、老赵、导师小运。
- 感谢 Ctrip English Website Department 在我最迷失的时候收留我,特别感谢面试我的 Allen 和 Brice。
订正信息:
- 感谢@Max_Lee提出IE9支持
property:value\0/;
的大部分属性
再见了,IE6/7,后会无期!——by 葵中剑 2012-02-02