兼容性
浏览器兼容性问题又被称为网页兼容性或网站兼容性问题,指网页在各种浏览器上的显示效果可能不一致而产生浏览器和网页间的兼容问题。在网站的设计和制作中,做好浏览器兼容,才能够让网站在不同的浏览器下都正常显示。而对于浏览器软件的开发和设计,浏览器对标准的更好兼容能够给用户更好的使用体验。
一、浏览器内核
浏览器最核心的部分是渲染引擎(Rendering Engine),一般习惯称之为“浏览器内核”,其负责解析网页语法(如标准通用标记语言的子集HTML、JavaScript)并渲染、展示网页。因此,所谓的浏览器内核通常也就是指浏览器所采用的渲染引擎,渲染引擎决定了浏览器如何显示网页的内容以及页面的格式信息。不同的浏览器内核对网页编写语法的解析也有所不同,所支持的HTML等网页语言标准不同,以及用户客户端的环境不同(如分辨率不同)造成的显示效果不能达到理想效果,因此同一网页在不同的内核浏览器里的渲染、展示效果也可能不同。最常见的问题就是网页元素位置混乱,错位。下面介绍一下几款主流的排版引擎和浏览器。
1) Trident(windows)
Trident 就是IE浏览器所使用的内核,也是很多浏览器所使用的内核,通常被称为IE内核。基于Trident内核的浏览器非常多,这是因为Trident内核提供了丰富的调用接口。老的Trident内核(比如常说的IE6内核)一直是不遵循W3C标准的,但是由于当时IE6的市场份额最大,所以后果就是大量的网页专门为IE6等老Trident内核编写,在IE6下显示很正常,但其实这些网页的代码并不符合W3C标准,于是,完全依据W3C标准写的网页在老的Trident内核下面又出现偏差,这就是为什么很多人觉得后来的IE9的网页排版有时会乱了,而IE6则正常,其实不是浏览器兼容性差了,而是访问的网页不符合新的标准。目前可供调用的最新版的Trident内核是IE9所用的内核,相较之前的版本对W3C标准的支持增强了很多。
2) Gecko(跨平台)
Netscape6 启用的内核,现在主要由Mozilla基金会进行维护,是开源的浏览器内核,目前最主流的Gecko内核浏览器是Mozilla Firefox,所以也常常称之为火狐内核。因为Firefox的出现,IE的霸主地位逐步被削弱,Chrome的出现则是加速了这个进程。非Trident内核的兴起正在改变着整个互联网,最直接的就是推动了编码的标准化,也使得微软在竞争压力下不得不改进IE。
3) WebKit(跨平台)
由KHTML发展而来,也是苹果给开源世界的一大贡献。因为是脱胎于KHTML,所以也是具有高速的特点,同样遵循W3C标准。从目前看来,WebKit内核是最有潜力而且是已经有相当成绩的新兴内核,性能非常好,而且对W3C标准的支持很完善。
二、css常见兼容问题及解决方案
1) 不同浏览器的标签默认的外补丁和内补丁不同
描述:标签在不加样式控制的情况下,各自的margin 和padding差异较大
解决方案:CSS里 *{margin:0;padding:0;}
备注:这个是最常见的也是最易解决的一个浏览器兼容性问题,几乎所有的CSS文件开头都会用通配符*来设置各个标签的内外补丁是0。
2) 块属性标签float后,又有横行的margin情况下,在IE6显示margin比设置的大
描述:常见症状是IE6中后面的一块被顶到下一行
解决方案:在float的标签样式控制中加入 display:inline;将其转化为行内属性
备注:最常用的就是div+CSS布局了,而div就是一个典型的块属性标签,横向布局的时候通常都是用div float实现的,横向的间距设置如果用margin实现,这就是一个必然会碰到的兼容性问题。
3) 设置较小高度标签(一般小于10px),在IE6,IE7,遨游中高度超出自己设置高度
描述:IE6、IE7和遨游里这个标签的高度不受控制,超出自己设置的高度
解决方案:给超出高度的标签设置overflow:hidden;或者设置行高line-height 小于你设置的高度。
备注:这种情况一般出现在设置小圆角背景的标签里。出现这个问题的原因是IE8之前的浏览器都会给标签一个最小默认的行高的高度。即使你的标签是空的,这个标签的高度还是会达到默认的行高。
4) 行内属性标签,设置display:block后采用float布局,又有横行的margin的情况,IE6间距bug
描述:IE6里的间距超过设置的间距
解决方案:在display:block;后面加入display:inline;display:table;
备注:行内属性标签,为了设置宽高,需要设置display:block;(除了input标签比较特殊)。在用float布局并有横向的margin后,在IE6下,他就具有了块属性float后的横向margin的bug。不过因为它本身就是行内属性标签,所以再加上display:inline的话,它的高宽就不可设了。这时候我们还需要在display:inline后面加入display:talbe。
5) 图片默认有间距
描述:几个img标签放在一起的时候,有些浏览器会有默认的间距,加了问题一中提到的通配符也不起作用。
解决方案:使用float属性为img布局
备注:因为img标签是行内属性标签,所以只要不超出容器宽度,img标签都会排在一行里,但是部分浏览器的img标签之间会有个间距。去掉这个间距需要使用float。
6) 标签最低高度设置min-height不兼容
描述:因为min-height本身就是一个不兼容的CSS属性,所以设置min-height时不能很好的被各个浏览器兼容
解决方案:如果设置一个标签的最小高度200px,需要进行的设置为:{min-height:200px;height:auto !important; height:200px; overflow:visible;}
备注:当内容小于一个值(如300px)时。容器的高度为300px;当内容高度大于这个值时,容器高度被撑高,而不是出现滚动条。这时候会遇到这个兼容性问题。
7) 兼容CSS代码
描述:很多兼容性问题都是因为浏览器对标签的默认属性解析不同造成的,只要稍加设置都能解决这些兼容问题。
解决方案:使用csshack
CSShack的目的就是CSS代码兼容不同的浏览器,使用hack把浏览器分为3类:IE6 、IE7和遨游、其他(IE8 chrome ff safari opera等)
常用的css hack方式:
a) 方式一 条件注释法
Ø 只在IE下生效
<!--[if IE]>
这段文字只在IE浏览器显示
<![endif]-->
Ø 只在IE6下生效
<!--[if IE 6]>
这段文字只在IE6浏览器显示
<![endif]-->
Ø 只在IE6以上版本生效
<!--[if gte IE 6]>
这段文字只在IE6以上(包括)版本IE浏览器显示
<![endif]-->
Ø 只在IE8上不生效
<!--[if ! IE 8]>
这段文字在非IE8浏览器显示
<![endif]-->
Ø 非IE浏览器生效
<!--[if !IE]>
这段文字只在非IE浏览器显示
<![endif]-->
b) 方式二 类内属性前缀法
属性前缀法是在CSS样式属性名前加上一些只有特定浏览器才能识别的hack前缀,以达到预期的页面展现效果。
IE浏览器各版本 CSS hack 对照表
hack | 写法 | 实例 | IE6(S) | IE6(Q) | IE7(S) | IE7(Q) | IE8(S) | IE8(Q) | IE9(S) | IE9(Q) | IE10(S) | IE10(Q) |
* | *color | 青色 | Y | Y | Y | Y | N | Y | N | Y | N | Y |
+ | +color | 绿色 | Y | Y | Y | Y | N | Y | N | Y | N | Y |
- | -color | 黄色 | Y | Y | N | N | N | N | N | N | N | N |
_ | _color | 蓝色 | Y | Y | N | Y | N | Y | N | Y | N | N |
# | #color | 紫色 | Y | Y | Y | Y | N | Y | N | Y | N | Y |
\0 | color:red\0 | 红色 | N | N | N | N | Y | N | Y | N | Y | N |
\9\0 | color:red\9\0 | 粉色 | N | N | N | N | N | N | Y | N | Y | N |
!important | color:blue !important;color:green; | 棕色 | N | N | Y | N | Y | N | Y | N | Y | Y |
说明:在标准模式中
″-″减号是IE6专有的hack
″\9″ IE6/IE7/IE8/IE9/IE10都生效
″\0″ IE8/IE9/IE10都生效,是IE8/9/10的hack
″\9\0″ 只对IE9/IE10生效,是IE9/10的hack
c) 方式三:选择器前缀法
选择器前缀法是针对一些页面表现不一致或者需要特殊对待的浏览器,在CSS选择器前加上一些只有某些特定浏览器才能识别的前缀进行hack。
目前最常见的是:
*html *前缀只对IE6生效
*+html *+前缀只对IE7生效
@media screen\9{...}只对IE6/7生效
@media \0screen {body { background: red; }}只对IE8有效
@media \0screen\,screen\9{body { background: blue; }}只对IE6/7/8有效
@media screen\0 {body { background: green; }} 只对IE8/9/10有效
@media screen and (min-width:0\0) {body { background: gray; }} 只对IE9/10有效
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none){body { background: orange; }} 只对IE10有效
8) 兼容CSS3属性
描述:浏览器的标准不统一,有些浏览器不支持CSS3属性
解决方案:使用浏览器的厂商前缀
前缀 | 组织 | 示例 | 说明 |
-ms- | Microsoft | -ms- border-radius | IE浏览器专属的CSS属性需添加-ms-前缀 |
-moz- | Mozilla | -moz- border-radius | 所有基于Gecko引擎的浏览器(如Firefox)专属的CSS属性需添加-moz-前缀 |
-o- | Opera | -o- border-radius | Opera浏览器专属的CSS属性需添加-o-前缀 |
-webkit- | Webkit | -webkit-border-radius | 所有基于Webkit引擎的浏览器(如Chrome、Safari)专属的CSS需添加-webkit-前缀 |
9) cursor:hand VS cursor:pointer
描述:firefox不支持hand,但ie支持pointer
解决方法: 统一使用pointer
10) ul和ol列表缩进问题
描述:消除ul、ol等列表的缩进
解决方案:重写样式
例如:
ul,ol{ list-style:none;
margin:0px;
padding:0px;}
11) 元素水平居中问题
描述:让元素水平居中
解决方案:
FF: margin:0auto;
IE: 父级{text-align:center; }
12) Div的垂直居中问题
描述:div内容的垂直居中
解决方案:
vertical-align:middle;将行距增加到和整个DIV一样高:line-height:200px; 然后插入文字,就垂直居中了。缺点是要控制内容不要换行。
13) margin加倍的问题
描述:
设置为float的div在ie下设置的margin会加倍。这是一个ie6都存在的bug。
解决方案:
在这个div里面加上display:inline;
例如:
<divid=”imfloat”>
#imfloat{
float:left;
margin:5px;/*IE下理解为10px*/
display:inline;/*IE下再理解为5px*/}
14) LI中内容超过长度后以省略号显示
描述:LI中内容超过长度后以省略号显示
解决方案:适用与IE、Opera、safari、chrom浏览器,FF暂不支持。
例如:
li{
width:200px;
white-space:nowrap;
text-overflow:ellipsis;
-o-text-overflow:ellipsis;
overflow:hidden;
}
15) IE无法设置滚动条颜色
描述:web标准中IE无法设置滚动条颜色
解决方案:将body换成html
例如:
html{
scrollbar-face-color:#f6f6f6;
scrollbar-highlight-color:#fff;
scrollbar-shadow-color:#eeeeee;
scrollbar-3dlight-color:#eeeeee;
scrollbar-arrow-color:#000;
scrollbar-track-color:#fff;
scrollbar-darkshadow-color:#fff;
}
16) 超链接访问过后hover样式就不出现的问题
描述:被点击访问过的超链接样式不在具有hover和active了,
解决方案:改变CSS属性的排列顺序: L-V-H-A
例如:
a:link {}
a:visited {}
a:hover {}
a:active {}
1.1.1.1.3 Javascript常见兼容问题及解决方案
1) HTML对象获取问题
描述:
FireFox:document.getElementById("idName");
ie:document.idname或者document.getElementById("idName").
解决办法:统一使用document.getElementById("idName");
2) const问题
描述:
Firefox下,可以使用const关键字或var关键字来定义常量;
IE下,只能使用var关键字来定义常量.
解决方案:统一使用var关键字来定义常量.
3) window.event问题
描述:
window.event只能在IE下运行,而不能在Firefox下运行,这是因为Firefox的event只能在事件发生的现场使用。
解决方法:在事件发生的函数上加上event参数,在函数体内(假设形参为evt)使用 var myEvent = evt?evt:(window.event?window.event:null)
例如:
<inputtype="button" οnclick="doSomething(event)"/>
<scriptlanguage="javascript">
functiondoSomething(evt) {
varmyEvent = evt?evt:(window.event?window.event:null)
...
}
4) event.x与event.y问题
描述:
Firefox下,event对象有pageX,pageY属性,但是没有x,y属性.
IE下,event对象有x,y属性,但是没有pageX,pageY属性;
解决方案:
使用mX(mX=event.x?event.x:event.pageX;)来代替IE下的event.x或者Firefox下的event.pageX.
如果考虑window.event问题,就改用myEvent代替event。
5) event.srcElement问题
描述:
IE下,even对象有srcElement属性,但是没有target属性;
Firefox下,even对象有target属性,但是没有srcElement属性。
解决方案:使用srcObj= event.srcElement ?event.srcElement : event.target;
如果考虑window.event问题,就改用myEvent代替event。
6) window.location.href问题
说明:IE或者Firefox2.0.x下,可以使用window.location或window.location.href;
Firefox1.5.x下,只能使用window.location.
解决方案:使用window.location来代替window.location.href.
7) frame问题
以下面的frame为例:
<frame src="xxx.html" id="frameId" name="frameName" />
Ø 访问frame对象:
IE:使用window.frameId或者window.frameName来访问这个frame对象.
frameId和frameName可以同名。
Firefox:只能使用window.frameName来访问这个frame对象.
另外,在IE和Firefox中都可以使用window.document.getElementById("frameId")来访问这个frame对象.
Ø 切换frame内容:
在 IE和Firefox中都可以使用
window.document.getElementById("testFrame").src="xxx.html"
或window.frameName.location="xxx.html"来切换frame的内容
如果需要将frame中的参数传回父窗口(注意不是opener,而是parentframe),可以在frame中使用parent来访问父窗口。
例如:parent.document.form1.filename.value="Aqing"
8) 模态和非模态窗口问题
描述:
IE下,可以通过showModalDialog和showModelessDialog打开模态和非模态窗口;
Firefox下则不能。
解决方案:直接使用window.open(pageURL,name,parameters)方式打开新窗口。
如果需要将子窗口中的参数传递回父窗口,可以在子窗口中使用window.opener来访问父窗口。
例如:
var parWin=window.opener;parWin.document.getElementById("Aqing").value="Aqing";
9) firefox与IE的父元素(parentElement)的区别
描述:
IE下,使用obj.parentElement 或 obj.parentNode 访问obj的父结点;
firefox下,使用obj.parentNode 访问obj的父结点。
解决方案:因为firefox与IE都支持DOM,因此统一使用obj.parentNode来访问obj的父结点。
10) document.formName.item("itemName")问题
描述:
IE下,可以使用 document.formName.item("itemName")或 document.formName.elements ["elementName"];
Firefox下,只能使用document.formName.elements["elementName"]。
解决方案:统一使用document.formName.elements["elementName"]。
11) 集合类对象问题
描述:
IE下,可以使用 () 或 [] 获取集合类对象;
Firefox下,只能使用 [ ]获取集合类对象。
解决方案:统一使用 []获取集合类对象。
12) 自定义属性问题
描述:
IE下,可以使用获取常规属性的方法来获取自定义属性,也可以使用 getAttribute() 获取自定义属性;
Firefox下,只能使用getAttribute() 获取自定义属性。
解决方案:统一通过getAttribute()获取自定义属性。
13) input.type属性问题
描述:
IE下input.type属性为只读;
Firefox下input.type属性为读写。
解决办法:不修改input.type属性。如果必须要修改,可以先隐藏原来的input,然后在同样的位置再插入一个新的input元素。
14) body载入问题
描述:Firefox的body对象在body标签没有被浏览器完全读入之前就存在;
IE的body对象则必须在body标签被浏览器完全读入之后才存在。
备注:经验证,IE6、Opera9以及FireFox2中不存在上述问题,单纯的JS脚本可以访问在脚本之前已经载入的所有对象和元素,即使这个元素还没有载入完成。
15) 事件委托方法
描述:
IE下,使用document.body.οnlοad= inject; 其中function inject()在这之前已被实现;Firefox下,使用document.body.onload = inject()。
解决方案:统一使用document.body.οnlοad=newFunction(’inject()’);
或者document.body.οnlοad= function(){}
备注:Function和function的区别。
16) Table操作问题
描述:ie、firefox以及其它浏览器对于 table 标签的操作都各不相同,在ie中不允许对table和tr的innerHTML赋值,使用js增加一个tr时,使用appendChild方法也不管用。
解决方案:把行插入到TBODY中,不要直接插入到表
//向table追加一个空行:
varrow = otable.insertRow(-1);
varcell = document.createElement("td");
cell.innerHTML= "";
cell.className= "XXXX";
row.appendChild(cell);
备注:建议使用JS框架集来操作table,如JQuery。
17) 对象宽高赋值问题
描述:FireFox中类似obj.style.height = imgObj.height的语句无效。
解决方案:统一使用obj.style.height = imgObj.height + ‘px';
18) eval("idName ")问题
描述:
IE下,可以使用 eval("idName") 或 getElementById("idName ") 来取得 id 为 idName 的HTML对象;
Firefox下,只能使用getElementById("idName ") 来取得 id 为 idName 的HTML对象。
解决方案:统一用getElementById("idName ") 来取得 id 为 idName 的HTML对象。
19) 变量名与某HTML对象ID相同的问题
描述:IE下,HTML对象的ID可以作为document 的下对象变量名直接使用,Firefox下则不能;Firefox下,可以使用与HTML对象ID相同的变量名,IE下则不能。
解决方案:使用 document.getElementById(”idName”)代替 document.idName。
最好不要取HTML对象ID相同的变量名,以减少错误;在声明变量时,一律加上var关键字,以避免歧义。
20) innerText的问题.
描述:innerText在IE中能正常工作,但是innerText在FireFox中却不行。
解决方案:在非IE浏览器中使用textContent代替innerText。
例如:
if(navigator.appName.indexOf("Explorer")>-1){
document.getElementById("element").innerText = "my text";
}else{
document.getElementById("element").textContent = "my text";
}
备注:innerHTML同时被ie、firefox等浏览器支持,其他的,如outerHTML等只被ie支持。
21) 用setAttribute设置事件
描述:
varobj = document.getElementById('objId');
obj.setAttribute('onclick','funcitonname();');
FIREFOX支持,IE不支持
解决办法:
IE中必须用点记法来引用所需的事件处理程序,并且要用赋予匿名函数
例如:
varobj = document.getElementById('objId');
obj.οnclick=function(){fucntionname();};
22) 建立单选钮
描述:
IE以外的浏览器
varrdo = document.createElement('input');
rdo.setAttribute('type','radio');
rdo.setAttribute('name','radiobtn');
rdo.setAttribute('value','checked');
IE:
varrdo =document.createElement(”<input name=”radiobtn” type=”radio”value=”checked” />”);
解决方案:
使用IF-ELSE判断