本文将整理和收集各种常见的浏览器兼容性问题,从大体上来分,浏览器兼容性问题主要有两个方面:JS和CSS
JS常见兼容性问题
JS语言本身的兼容性问题
JS语言本身的兼容性问题不多,平时开发中也不容易遇到,如for in的顺序
var data = { a: ‘a‘, b: ‘b‘ }; delete data[‘a‘]; data[‘a‘] = ‘a‘; for (var i in data) { document.write(data[i]); //在IE中的结果为ab,在FF等浏览器中的结果为ba }
好在IE的开发人员整理出了JScript和ECMAScript 3之间的区别,推荐看看
DOM方面的兼容性问题
JS的兼容性问题主要集中在DOM方面,包括DOM节点的操作、Event等,这里有大量的兼容性问题,主要体现在IE浏 览器方面
典型的如添加事件,在IE中要使用attachEvent
,而其它浏览器中则要使用addEventListener
,下面 是Fe.js中的例子
/** * 给元素el绑定事件(evt)的处理函数handler。 * 用法: * Fe.on("click", function(){ alert(123); }, "button"); * 引入了Fe.event.js之后,接口是不变的,但是提供的功能更强,可以有效的<br /> * 避免内存泄漏的问题. * @param {String} evt 方法的名称 * @param {Function} 事件的处理函数 * @param {DOM/String} el DOM元素 */ Fe.on = function(evt, handler, el){ if(!(el = Fe.G(el))) return false; evt = evt.replace(/^on/, "").toLowerCase(); if(Fe.isIE) el.attachEvent("on" + evt, handler); else if(el.addEventListener) el.addEventListener(evt, handler, false); };
这些兼容性问题已经研究得很充分了,绝大部分问题都可以轻松解决,只要有一个较好到基础库
JS基础库
JS基础库可以屏蔽大部分的浏览器兼容性问题,提高开发效率
它对外提供简单的接口,使用者无需考虑太多底层问题,如想获取文档的高度和可视区有高度,只需调用如下函数 即可
Fe.body.documentWidth(); Fe.body.viewHeight();
Fe的基础库开发和整理主要又JS-Topic小组在做,接口人为玉北,感兴趣的同学可以访问http://fe/js/
相对与prototype、jQuery等框架来说,这个基础库主要给予以往的开发实践,更加小巧实用
阅读其中的源码可以了解许多DOM兼容性的问题
CSS常见兼容性问题
CSS的兼容性问题主要集中在IE浏览器上,IE的问题主要分为以下3种:
- 不支持某些属性,如min-width(IE6)
- 对某些属性的支持有误,如overflow属性的默认值visible(IE6)
- 软件自身的bug,如peekaboo等渲染bug
- hasLayout特性所导致的问题
相对与IE来说,Firefox等其它浏览器几乎很难遇到CSS的bug,在Firefox最常遇到的一个问题是超长英文 字符折行,这个问题在IE中可以用word-break:break-all;
来解决,但在Firefox就很麻烦了,目前 主要有两种解决方式
- 隔几个字符加一个
<wbr>
标签来建议折行 - 采取截断策略,而不是折行,即用
verflow:hidden;
来隐藏超出的文本
加<wbr>
标签的方式可以参考Fe.js中的insertWbr
什么是hasLayout
在讨论IE的各种布局问题前,首先要了解的一个概念是hasLayout,因为很多IE的bug都和它有关
hasLayout不好用语言来解释,但是可以通过各种现象来了解,我们可以认为它是一种状态,当进入了这种 状态后,IE对布局的解析会有所不同
hasLayout并不是一个实际存在的属性,没有hasLayout:true
这样直接的设置,它隐藏在一些常见的CSS 属性中
来看一个很常见的例子
<div style="background:red"> <div style="float:left">test</div> </div>
这个例子在IE和Firefox下的效果是一样的,但是如果给父层的div加上了一个宽度后
<div style="background:red; width:800px"> <div style="float:left">test</div> </div>
我们会发现在IE下背景色红色显示出来了,而在Firefox还是没有显示,为什么呢?是因为受到宽度的影响? 我们再试下面的例子
<div style="background:red; display:inline-block"> <div style="float:left">test</div> </div>
除此之外还有其它属性也能令IE中显示背景色,如
<div style="background:red; zoom:1"> <div style="float:left">test</div> </div>
首先来说明一下zoom:1
,它是IE5.5以后引入的一个IE专有属性,在这里它的作用只有一个,那就是令外层 div有hasLayout
所以这个问题的根本原因不在于设置了宽度或设置了zoom为1,而是因为设置了这些属性导致元素“hasLayout”
与hasLayout有关的问题
Peekaboo IE6
触发条件: 在一个非hasLayout的盒内,如果一边浮动,另一边的内容就会莫名其妙的消失
示例:
<style type="text/css"> #main { background:#FFCC99; } #float { background:#DFF191; float:left; height:200px; width:200px; } #clear { background:#88C2E3; clear:both; } </style> <div id="main"> <div id="float"> <a href="#">浮动的内容</a> </div> 隐藏的文本 <div id="clear">底部</div> </div>
解决办法:
- 给main加hasLayout
如
<!--[if IE lte 6]> <style> #main { zoom:1; } </style> <![endif]-->
- 去掉main的背景色
Guillotine Bug [IE6]
触发条件:
一边是浮动,另一边无浮动,有链接且设置了:hover的background, Padding, Text Style, Border等属性 当鼠标放在第四个以上的链接上时,浮动的内容就会被截断
示例:
<style type="text/css"> .floated {width: 100px;float: left;} a:hover {background: none #FFFFCC scroll repeat 0% 0%;} </style> <div class="floated"> <p>The content in the bottom of the float, such as this paragraph, is vulnerable to the Guillotine.The content in the bottom of the float, such as this paragraph, is vulnerable to the Guillotine.The content in the bottom of the float, such as this paragraph, is vulnerable to the Guillotine.</p> </div> <ul class="nonfloated"> <li><a href="#">Fix the Guillotine</a></li> <li><a href="#">Fix the Guillotine</a></li> <li><a href="#">Chop the float</a></li> <li><a href="#">Chop the float</a></li> </ul>
解决办法:
- 在底部加入一句话
如
- 给非浮动元素hasLayout
如
<!--[if lte IE 6]> <style type="text/css"> .nonfloated { height: 1px; } </style> <![endif]-->
Unscrollable Content Bug [IE6]
触发条件:
在一个相对定位中的绝对定位元素,即使其高度高于浏览器的高度也不会出现滚动条
示例:
<style type="text/css"> #relative { position:relative; } #absolute { position:absolute; height:1000px; } </style> <div id="relative"> <div id="absolute"> s </div> </div>
解决办法:
给相对元素hasLayout
<!--[if IE 6]> <style type="text/css"> /*<![CDATA[*/ #relative { zoom:1; } /*]]>*/ </style> <![endif]-->
Border Missing [IE6]
触发条件:
在一个块中有浮动元素时,会导致这个块的部分边框消失
示例:
<style type="text/css"> #main { margin:500px 100px 10px 100px; padding:50px; border:1px solid #ccc; line-height:300% } </style> <div id="main" style=""> <div style="float:left"> a<br /> b<br /> c<br /> d<br /> </div> <div style="clear:both"></div> </div>
解决办法:
给包含浮动元素的块hasLayout
<!--[if IE 6]> <style type="text/css"> /*<![CDATA[*/ #main { zoom:1; } /*]]>*/ </style> <![endif]-->
Three Pixel Text Jog [IE6]
触发条件:
在两相邻的元素中,如果第一个设置了浮动,第二个没有设置浮动,希望通过设置margin的方式将 其中的内容与浮动元素份开始,在浮动元素周围的文字就会出现3像素的边距,导致上下文字不对
示例:
<style type="text/css"> #floatbox { float:left; width: 100px; height: 50px; background:#87BEF1; } #content { margin-left:100px; background:#BFEE66; } </style> <div id="floatbox">float</div> <div id="content"> <p>content</p> <p>content</p> <p>content</p> <p>content</p> <p>content</p> <p>content</p> <p>content</p> </div>
而如果content具有hasLayout属性,这些文字就可以对齐,但这却又导致两个块间产生3像素的间隙
#content { margin-left:100px; background:#BFEE66; zoom:1; }
因此,要想让IE6表现正常,就得需要hack,将IE6的margin-left减去3像素,这类我们使用下 划线加属性的方式,因为这种写法只有IE6才认
#floatbox { float:left; width: 100px; height: 50px; background: #87BEF1; _margin-right: -3px; } #content { margin-left: 100px; _margin-left: 0; background: #BFEE66; zoom: 1; }
浮动的clear
hasLayout会影响浮动的clear,在最初的例子中可以看出,所以可以利用这个特点来做clearfix,其中第二段 就是利用IE的hasLayout
.clearfix:after { content:"."; display:block; height:0; clear:both; visibility:hidden; } .clearfix { display:inline-block; display:block; }
margin的collapsing
在IE中如果一个元素有hasLayout,将会导致起它与子孙的元素margin不重合,如下面的两个例子
<style type="text/css"> #outer { background: #BFEE66; margin: 10px 0; } #inner { margin: 30px 0; } </style> <div id="outer"> <div id="inner">inner</div> </div>
如果加上zoom属性后
<style type="text/css"> #outer { background: #BFEE66; margin: 10px 0; zoom:1; } #inner { margin: 30px 0; } </style> <div id="outer"> <div id="inner">inner</div> </div>
滤镜
CSS的滤镜只能使用在有hasLayout的元素上,所以如果要对一个div设置滤镜效果,就需要加上zoom等产生 hasLayout的属性
绝对定位元素的起始点
///TODO
小结
可以将hasLayout理解为IE的另一个布局解析引擎,当某个元素具有hasLayout时,它的将采用另一种布局方式
其中有些属性是很容易导致问题的,在使用时需谨慎
- float
- margin
- background
- position
常见的IE问题及解决办法
内容自动撑开 [IE6]
触发条件:造成这一问题的原因是IE6对overflow默认值visible的解析错误,如果一个块中的内容的 宽高超过了这个块,其中的内容会撑开这个块的宽高
示例:
<style type="text/css"> #box { background: #99CC00; width: 50px; } </style> <div id="box"> http://wwwwwwwwwwwwwwwwwwwwwww.com </div>
解决办法:
很遗憾,目前没有完美的解决办法,如果内容为纯文字,可以使用IE特有的word-wrap: break-word
让文字折行,但如果是图片就没办法了,还有另一种办法是使用overflow: hidden
由于IE6的这个特性,可以用它来实现min-width
的效果
Quirky Percentages [IE6]
触发条件:
当使用百分比的单位时,IE6有时会在页面载入时显示不正确,但如果有:hover等reflow事件, 这时IE6就才会知道准确的位置,于是会导致内容的跳动或许多莫名其妙的问题
怀疑是由于IE6对overflow默认值解释的不正确引起的,因为即使设定了宽高,在IE6中还是会 被内容撑大,所以IE6无法判断实际的宽高
示例:
<style type="text/css"> #nav a:hover{ background-color: #ff0; } #main{ float: left; margin-left: 2%; } #container{ width: 400px; } </style> <div id="container"> <div id="nav"> <a href="#link">The link</a> </div> <div id="main"> The text ... </div> </div>
解决办法:
目前还没有完美的解决办法,但可以在一定程度上避免
- 不用百分比,显然这不是一个好办法,但它能避免这个bug
- 不用:hover,但无法修正初始时的错误解析
- 用expression,如margin-left:expression(this.parentNode.offsetWidth / 50 + ‘px‘) 可以当作margin-left:2%
- 进quirks模式,但为了这个问题进入quirks模式不值得
Disappearing List-Background Bug [IE6]
触发条件:
在一个相对定位并浮动的块中的li和dt的背景会消失
示例:
<style type="text/css"> .test1 li { background: #d00; } </style> <div style="position: relative; float: left; "> <ul class="test1"> <li>One</li> <li>Two</li> <li>Three</li> <li>Four</li> <li>Five</li> </ul> </div>
解决办法:
将li、dt设为相对定位
<!--[if IE 6]> <style type="text/css"> /*<![CDATA[*/ .test1 li{ position: relative; } /*]]>*/ </style> <![endif]-->
IE 6 Duplicate Characters Bug
触发条件:
两个浮动元素,它们之间有注释,且它们的宽度和大于包含它们的元素,就会多出字符
还有一种情况是在有多个隐藏的input框时,也会导致莫名其妙地多出字符
示例:
<!-- 取自http://bbs.blueidea.com/thread-2692486-1-1.html --> <div style="width:400px"> <div style="float:left;"></div> <!-- --> <div style="float:right;width:401px">这里会多一个字符</div> </div>
另一种情况,多了一个a
<style type="text/css"> .mod {float:right;width:215px;} .mod .cnt{word-break:break-all;} </style> <div style="width:214px;"> <input type="hidden" /> <input type="hidden" /> <input type="hidden" /> <div class="mod"> <ul class="cnt"> <li>ffffffffffffffffffffffffffffffffffffffffffffffff</li> <li>a</li> </ul> </div> </div>
解决办法:
- 去掉两个浮动元素间的注释
- 减小浮动元素的宽度
- 给隐藏的input外加一个div标签
Doubled Float-Margin Bug [IE6]
触发条件:
浮动元素在其浮动方向上的margin将是所设值的两倍
示例:
<style type="text/css"> .floatbox { float: left; margin-left: 300px; background:#6666FF; } </style> <div> <div class="floatbox">floatbox</div> </div>
解决办法:
设置display: inline;
.floatbox { float: left; margin-left: 300px; background:#6666FF; display:inline; }
或者套一层无意义的div,用这一层来浮动
<div> <div style="float:left"><div class="floatbox">floatbox</div></div> </div>
Doubled top padding [IE]
触发条件:
一个clear的元素紧跟着一个浮动的元素时,这个clear的元素的padding-top会变为所设值的两倍
示例:
<style type="text/css"> .left { background-color:#AAAAFF; float:left; width:40%; } .cleared { clear:both; } .red { background-color:#FFAAAA; padding:30px 5px; } </style> <div class="left">this is a left float with zero content alongside it</div> <div class="red cleared"><p>This div has the same top and bottom padding -- 30 pixels -- but this bug causes the top-padding to be 60 pixels instead</p></div>
日常开发中如何Debug
初步判断
首先是要初步判断受影响的浏览器范围,初步确定bug类型,比如一个问题如果在IE7和Firefox下是正常的,但 在IE6下就有问题,则很有可能是一个已知的IE6 bug
线上修改并定位问题
接下来最重要的就是定位问题的原因,这里有一个很好的办法,那就是利用<base>
标签,通过设置它的src,就 能够直接修改线上的页面,立刻查看效果
具体步骤是
- 复制源码,保存到本地文件
- 增加base标签,将src设为那个页面的url
- 将可能修改到的css改成本地地址,或直接复制出来放到
<style>
标签中 - 不断删减源码,直到找到最简复现条件
推荐学习顺序
- 仔细阅读w3c上的css规范
- 有些现象不是问题,而是特点,如clearfix
- 很多书籍和文章都带有主观想法,有误导
- 了解IE的参见问题
- 参与实际项目,不断解决问题
其它资料
还有许多不常见的问题,都整理到ie_css_bugs.zip中了,建议打开每个例子看看