初始问题描述
最近在学习CSS的display属性时,遇到一个在IE6/7下html块级元素设置inline-block属性的兼容性问题,于是就查资料,网上很多关于这个问题的解答,大致的描述如下:[1]
IE6、IE7支持对html行内元素设置inline-block。实际上只是看起来支持而已,IE6、IE7并不识别inline-block这个属性值,只是触发了layout,让行内元素有了inline-block的表征,比如说:行内显示且可设置宽高等等。
而对html块级元素设置inline-block,也只是触发了layout,对块级元素设置行内块级属性的目的没有达到。
那么在IE6、IE7下,怎么实现块级元素的inline-block属性值设置呢?
常见有2种方法:
-
先使用display:inline-block属性触发块元素,然后再定义display:inline,让块元素呈递为行内对象(两个display 要先后放在两个CSS声明中才有效果,这是IE的一个经典bug,如果先定义了display:inline-block,然后再将display设回 inline或block,layout不会消失),代码如下:
div {display:inline-block;}
div {display:inline;} -
直接让块元素设置为行内对象呈递(设置属性display:inline),然后触发块元素的layout(如:zoom:1 或float属性等),代码如下:
div { display:inline-block; _zoom:1;_display:inline;}/*推荐IE6*/
div { display:inline-block; *zoom:1;*display:inline;}/*推荐IE6或IE7*/
可是,总觉得有些地方不明白。
动手试试
我们用IETester来测试一下,IE6/IE7/IE9三个版本浏览器对行内和块级元素实际的显示情况。
首先,给出HTML部分代码,这里的one和four对应的元素只是作为参照物,中间两个才是实际操作的元素:
one
two
three
four
css部分代码如下:
#one { background-color: orangered; }
#two {
background-color: lime;
height: 2em;
}
#three {
background-color: black;
color: white;
height: 3em;
}
#four { background-color: skyblue; }
IE6/IE7/IE9对应的显示情况:
很明显,这里三者没啥区别。
然后,就是修改了。
第一步,对行内元素two设置display:inline-block;声明
#two {
background-color: lime;
height: 2em;
display: inline-block;
}
IE6/IE7/IE9对应的显示情况:
小结:我们发现虽然IE6/IE7的行内元素设置inline-block后显示的结果表明有块级元素显示宽高的“能力”,但是跟IE9上显示的有区别呢,我又在在chrome上试了一下,跟IE9的一样。IE9和chrome对inline-block是完全支持的,这说明什么?说明可能IE6/IE7并不是像IE9和chrome那样实现inline-block设置的。
第二步,对块级元素three设置display:inline-block;声明
#three {
background-color: black;
color: white;
height: 3em;
display: inline-block;
}
IE6/IE7/IE9对应的显示情况:
小结:我们很明显可以看出IE6/IE7不支持块级元素设置inline-block。
第三步,对上述的块级元素再添加*display:inline;声明
#three {
background-color: black;
color: white;
height: 3em;
display: inline-block;
*display: inline;
}
IE6/IE7/IE9对应的显示情况:
小结:这次是块级元素three获得了inline的属性值,可是IE6/IE7下block属性“丢了”。也就是设置inline-block失败,*display:inline;没起作用。
第四步,将上述后添加的*display:inline;放于一个独立的CSS规则中
#three {
background-color: black;
color: white;
height: 3em;
display: inline-block;
}
#three { *display: inline; }
IE6/IE7/IE9对应的显示情况:
小结:总算把块级元素设置成inline-block了,但是为何IE6/IE7跟IE9的显示结果还是不一样呢?是不是跟第一步中行内元素设置inline-block的情况很像呢?
第五步,换个方法,给第三步的块级元素再添加_zoom:1;声明
#three {
background-color: black;
color: white;
height: 3em;
display: inline-block;
_zoom:1;
*display: inline;
}
IE6/IE7/IE9对应的显示情况:
小结:这次IE7直接不显示出块级的效果了。为何IE6就可以,哪里出问题了?
第六步,给第三步的块级元素再添加*zoom:1;声明
#three {
background-color: black;
color: white;
height: 3em;
display: inline-block;
*zoom:1;
*display: inline;
}
IE6/IE7/IE9对应的显示情况:
小结:可以看到,这次显示的效果跟第四步的一样的了。结合第五步的结果,可以说明display前面的星号(*)和下划线(_)的作用对于IE6和IE7有区别。
那么问题真的解决掉了么?
衍生问题
IE6、IE7是否真的支持inline-block属性值?为何说支持行内元素的设置inline-block,又说只是“表征”呢?
“触发layout”中这个layout又是指的什么,触发的原理是什么?
_zoom和_display具体是什么情况下使用的。
*display和_display前面的星号(*)和下划线(_)有什么作用?
探讨延伸
首先来看下MSDN上关于inline-block属性值的解释:
将对象呈现为行内元素,但将对象的内容呈现为块元素。相邻的行内元素将呈现在同一行上,允许有空格。[2]
然而并不能用于解答“表征”inline-block的问题,好吧,那就当巩固知识点好了。
再来瞧瞧quirks mode上关于inline-block的解释:
IE 6/7 accepts the value only on elements with a natural display: inline.[3]
也就是说IE6/7是只对原生行内元素起作用,但是为何上面的实例中第一步显示的结果跟IE9和chrome的结果不一样呢?哦,对了,IE9和chrome是按照w3c标准支持inline-block属性值的。而前面说的对行内元素起作用或者说只有行内元素能够接受这个inline-bloc属性值,但并未说明是严格按照w3c标准支持的呀。有猫腻!
于是乎,根据“触发layout”就到了一个关于hasLayout这个(既)微(又)软专有属性的相关文章。
hasLayout是个什么鬼呢?这一切得从微软专有概念“layout”讲起。
“Layout” is an IE/Win proprietary concept that determines how elements
draw and bound their content, interact with and relate to other
elements, and react on and transmit application/user events.[4]
也就是说在IE下面layout是跟元素“随行”,每个元素都有个layout,只不过有些元素是天然显现出layout的或者说是天然触发了layout的(自带光环啊!摔),有些没有天然触发layout。而触发layout时,会有微软专有属性hasLayout赋值为true的行为,hasLayout=true,而且还是不可逆的,置于怎么把不可逆的“逆”回去,引文的“重度参考”里有,就不再探讨了。
当触发layout后,这个元素就可以像块级元素设置宽高边界等等属性了,但是一定要记住这跟w3c标准的块级属性的区别。因为触发layout后并不完全支持w3c标准的inline-block,在IE6/7下对块级元素设置inline-block,会覆“忽视”块级元素原生的display属性。也就是说对于一个块级元素直接设置inline-block并不能达到预期的目的。所以才需要用到*display:inline; *zoom:1; 这等IE hack。
但是为何行内元素直接设置,inline-block就不会被“忽视”原生的display属性呢?这还得从IE6标准版以前的版本说起。在那个“年代”,设置行内元素是可以设置宽高的,没错,你没看错,是可以设!置!宽!高!的!也就是微软家的行内元素其实一出生就是个行内块级元素,所以才会有IE6标准版以前的版本的“尺寸bug”。
不过,人家也确实不是完全按照W3C标准套路走的,微软自己搞出来的一套东西自己玩,你能说啥。IE6标准版以前的版本下行内元素是原生带有W3C标准中display:inline-block;的属性值的,我试过,确实是酱紫的,不信请看:
#two {
background-color: lime;
height: 2em;
}
#three {
background-color: black;
color: white;
height: 3em;
display: inline-block;
*zoom:1; /*这里可以省略,至于为什么,我说测试出来就是这样子,会被打死么*/
*display: inline;
}
但是,从IE6标准版开始,行内元素设置宽高是会被忽略的,所以看起来还像是有W3C标准中display:inline;属性的特性。
综上,我们可以解决第一个和第二个衍生问题了。对于IE6、IE7是否真的支持inline-block属性值,首先要明确我们常说的inline-block是W3C标准的属性值,是明确的区分行内元素、块级元素和行内块级元素的。但是微软不玩那一套,搞出个layout,通过一些特定的CSS属性来触发,表现为hasLayout=true,来使得一个元素有了W3C标准中inline-block的一些特性。
接下来,再说_zoom和_display以及*zoom和*display。这里前后的区别在于星号()和下划线(_)。其实下划线(_)是只有IE6才能识别,而星号()是只有IE6和IE7可识别,作用就是用于区分不同浏览器的。[5] 没错就是区分屌丝和高帅富的!
然后,为何要用_zoom和_display或者*zoom和*display呢?首先zoom又是微软的专有属性,平常多用zoom:1;来进行调试,其次zoom始终可以触发layout。[6] 而_display:inline;或者*display:inline;是为了让元素重新获得display:inline;的属性。也就是这两者已经可以完成与W3C标准中inline-block相似的特性了,那开头第二个解决方案为何前面还要加个display:inline-block;这不画色添足么?no,no,no。前面说了,这两个属性声明只是分别适用与IE6和IE6+IE7,对于其他浏览器是可以识别且按照W3C标准准确实现inline-block的,因此,才有了开头的代码:
display:inline-block; _zoom:1;_display:inline;
至此,第三和第四个衍生问题也解决了,有没有觉得对IE6、7的display属性的了解又有点增长呢?也不枉我花了好多事时间去查资料,码文章啦。
作者语
以上为根据一些网络资料加上部分个人实际测试得出的个人观点,或有错漏之处,还请指出以便交流学习。本人初发技术贴,也许水了点,还请轻拍。
其他
本文章对参考目录中的第一篇文章参考度很高,并且也觉得第一篇文章很不错,找时间用我“靠谱”的英语来翻译一下,顺便加深一下对IE“layout”的理解。
另外,找到一个测试IE块级元素inline-block的网页:IE block level element inline-block hack
测试工具
IE浏览器兼容性测试软件:IETester;
编辑器sublime text 3;
参考
重度参考:On having layout — the concept of hasLayout in IE/Win
IE6/IE7下:inline-block解决方案;
IE css hack 汇总;
CSS hack大全;
MSDN关于display的解释;
quirks mode上关于inline-block的兼容性解释:The display declaration