/ 昌里大金猪的空间 / IE6 下的多类选择符

IE6 下的多类选择符

2011-03-31 posted in [frontend]


某天发现一个小bug:在IE6下,鼠标移过顶部导航,由于标签宽度被意外撑大,直接导致下边的次导航错位:
2011年03月30日 - nomospace(昌里大金猪) - Nomospace

其他页面都正常,唯独每日专题这个页面有问题,经验告诉我应该是样式被覆盖了。

于是定位到对应样式,顶部导航模块的实现:
2011年03月30日 - nomospace(昌里大金猪) - Nomospace
 
专题页面的实现:
2011年03月30日 - nomospace(昌里大金猪) - Nomospace
 
.此处的.js-hover是专为IE6而写的,通过js使a支持非a标签的hover,具体代码实现不是本文的重点故不赘述。

为简化模拟bug触发环境,在此我写了一个多类选择符测试页面:
  1. <!DOCTYPE HTML>  
  2. <html>  
  3.     <head>  
  4.         <title>多类选择符测试</title>  
  5.         <style type="text/css">  
  6.             body .link{display:block;width:100px;height:100px;background-color:black;}  
  7.             body .content.link:hover{background-color:blue;}  
  8.             body .link:hover{background-color:red;}  
  9.         </style>  
  10.     </head>  
  11.     <body>  
  12.         <div><a href="#" class="content link"></a></div>  
  13.     </body>  
  14. </html> 

在IE6下,鼠标移过a元素后背景色为red,而在其他浏览器中则为blue。这是为什么呢?

先看一下官方是怎么说的:

A selector's specificity is calculated as follows:

  • count 1 if the declaration is from is a 'style' attribute rather than a rule with a selector, 0 otherwise (= a) (In HTML, values of an element's "style" attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
  • count the number of ID attributes in the selector (= b)
  • count the number of other attributes and pseudo-classes in the selector (= c)
  • count the number of element names and pseudo-elements in the selector (= d)

The specificity is based only on the form of the selector. In particular, a selector of the form "[id=p33]" is counted as an attribute selector (a=0, b=0, c=1, d=0), even if the id attribute is defined as an "ID" in the source document's DTD.

Concatenating the four numbers a-b-c-d (in a number system with a large base) gives the specificity.

Some examples:

 *             {}  /* a=0 b=0 c=0 d=0 -> specificity = 0,0,0,0 */
li {} /* a=0 b=0 c=0 d=1 -> specificity = 0,0,0,1 */
li:first-line {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
ul li {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
ul ol+li {} /* a=0 b=0 c=0 d=3 -> specificity = 0,0,0,3 */
h1 + *[rel=up]{} /* a=0 b=0 c=1 d=1 -> specificity = 0,0,1,1 */
ul ol li.red {} /* a=0 b=0 c=1 d=3 -> specificity = 0,0,1,3 */
li.red.level {} /* a=0 b=0 c=2 d=1 -> specificity = 0,0,2,1 */
#x34y {} /* a=0 b=1 c=0 d=0 -> specificity = 0,1,0,0 */
style="" /* a=1 b=0 c=0 d=0 -> specificity = 1,0,0,0 */
<HEAD>
<STYLE type="text/css">
#x97z { color: red }
</STYLE>
</HEAD>
<BODY>
<P ID=x97z style="color: green">
</BODY>

In the above example, the color of the P element would be green. The declaration in the "style" attribute will override the one in the STYLE element because of cascading rule 3, since it has a higher specificity.

来源出自http://www.w3.org/TR/CSS21/cascade.html#specificity

上文大致是说,css选择符有个权重,比如0,0,0,0。style标签的内联样式a=1,ID选择符b=1,class选择符c=1,标签选择符d=1等等,具体可以参考此文CSS Specificity: Things You Should Know(如何理解Css Specificity)

再来看看之前的测试页面,a元素的specificity

  1. body .link{display:block;width:100px;height:100px;background-color:black;}  -->0,0,1,0
  2. body .content.link:hover{background-color:blue;}                            -->0,0,2,2
  3. body .link:hover{background-color:red;}                                     -->0,0,1,2

照理说,第二条的权重最大,为什么IE6仍旧显示第三条的样式呢。其实IE6不支持.a.b的css写法(未找到出处),后一个类名会覆盖前一个类名,也就是说,.a.b在IE6上实际会被解析成.b,于是,第二条样式在IE6下实际为body .link:hover,与第三条一致了。后者覆盖前者,于是bug就出现了。


参考资料:

CSS Specificity: Things You Should Know

如何理解Css Specificity

CSS多类选择符测试

http://www.w3.org/TR/CSS21/cascade.html#specificity