我理解的浏览器兼容性

浏览器兼容性是一个很长久的话题,之所以前端需要面对浏览器兼容性,是因为用户的环境有不同的平台,不同的浏览器。不同的厂商之间为了相互竞争,对标准的实现不一样。不同的浏览器有不同的内核。即使同一个浏览器也有不同的版本,不同的版本对同一特性的支持情况也不尽相同。也可能某个浏览器的某个版本针对某个特性存在bug,而我们的产品又暂时不能放弃这个版本的用户,所以必须兼容。
PC的情况是这样,移动端的情况更复杂,除了要适配不同的平台和浏览器,还需要适配不同的屏幕,不同的硬件。

而要写出兼容性良好的代码,一是要了解规范,了解每个特性的实现原理,二是要了解各个浏览器内核的差异,三是要多尝试多踩坑,多积累。
下面介绍一下浏览器兼容性问题的大致分类,更多的细节可以到w3help查询。

html

目前主要是一些浏览器对html5的新特性不能完全支持,在使用html5新特性之前,可以在caniuse上查询特性的支持情况,也可以在html5test这个网站查询各个浏览器对html的支持情况。

如果想在不支持html5的浏览器里继续使用html的标签,可以用html5shiv

css

css的兼容性比较多,而且复杂,都是细节的问题,这里做一些整理。关于css选择器和各个属性的兼容性情况可以在http://www.quirksmode.org/css/查询。一些比较常见的css兼容性如下:

盒模型的解释

http://ggbond.qiniudn.com/box.png
border-box:width=content + l/r padding + l/r border(IE盒模型)
content-box:width = content-width(标准盒模型)

新特性的支持

市场上的浏览器对css3的特性支持不够完整,或者不同的厂商对同一个属性的实现不一样,所以出现了浏览器前缀。常见的浏览器前缀

  • Firefox:-moz-
  • Safari:-webkit-
  • Opera:-o-box-
  • IE:-ms-box-

需要添加浏览器前缀的属性有:

  • @keyframes
  • 移动和变换属性:transition-property,transition-duration,transition-timing-function,transition-delay;
  • 动画属性:animation-name,animation-duration,animation-timing-function,animation-delay;
  • border-radius;
  • boxshadow;
  • backface-visivility;
  • column属性;
  • flex属性;
  • respective属性

  • IE6和IE8不支持CSS3属性,为了确保网站设计能在不支持CSS3 的浏览器中也能正常执行,可以将CSS3Pie文件放到根目录下。

一些例子收集

  • 背景半透明
1
2
3
4
5
.transparent{
filter:alpha(opacity=60); /*支持 IE 浏览器*/
-moz-opacity:0.6; /*支持 FireFox 浏览器*/
opacity:0.6; /*支持 Chrome, Opera, Safari 等浏览器*/
}
  • IE6以前的版本会把text-align:center转换为<center></center>元素

    原生js

浏览器对原生js的支持情况可以通过http://kangax.github.io/compat-table/es5/查询

  • IE8不支持数组的indexOf方法,可以如下方法实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(elt /*, from*/)
{
var len = this.length >>> 0;
var from = Number(arguments[1]) || 0;
from = (from < 0)
? Math.ceil(from)
: Math.floor(from);
if (from < 0)
from += len;
for (; from < len; from++)
{
if (from in this &&
this[from] === elt)
return from;
}
return -1;
};
}
  • new Date().getYear(),在FF里返回的年份是减去1900
  • 对象字面量最后一个属性之后不支持,如下代码,在IE6/7下会报错
1
2
3
4
var obj = {
name:'ggbond',
}
  • 数组末尾多余逗号在IE8下的解析会有问题
1
2
3
4
5
6
var ary = [1,2,3,]
// IE 8
var ary = [1,2,3,null]

来源

  • ie8上传文件后提示下载文件

DOM

事件类

事件绑定

1
2
3
4
5
6
7
8
9
addHandler:function(element,type,handler){
if(element.addEventListener){//检测是否为DOM2级方法
element.addEventListener(type, handler, false);
}else if (element.attachEvent){//检测是否为IE级方法
element.attachEvent("on" + type, handler);
} else {//检测是否为DOM0级方法
element["on" + type] = handler;
}
}

取消绑定

1
2
3
4
5
6
7
8
9
removeHandler:function(element, type, handler){
if (element.removeEventListener){
element.removeEventListener(type, handler, false);
} else if (element.detachEvent){
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}

事件对象

1
2
3
4
5
6
7
getEvent: function(event){
return event ? event : window.event;
},
//获取事件对象目标的兼容性写法
getTarget: function(event){
return event.target || event.srcElement;
}

取消默认事件

1
2
3
4
5
6
7
preventDefault: function(event){
if (event.preventDefault){
event.preventDefault();
} else {
event.returnValue = false;
}
}

取消冒泡

1
2
3
4
5
6
7
stopPropagation: function(event){
if (event.stopPropagation){
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}

鼠标对象

1
2
3
4
5
6
7
8
9
10
11
getRelatedTarget: function(event){
if (event.relatedTarget){
return event.relatedTarget;
} else if (event.toElement){
return event.toElement;
} else if (event.fromElement){
return event.fromElement;
} else {
return null;
}
}

触发自定义事件

  • 标准
1
2
3
4
document.createEvent()
event.initEvent()
element.dispatchEvent()
  • IE 用propertychange模拟

DOM

  • children与childNodes

IE提供的children、childNodes和firefox下的childNodes的行为是有区别的,firefox下childNodes会把换行和空白字符都算作父节点的子节点,而IE的childNodes和children不会

  • getComputedStyle
1
2
3
4
5
6
7
8
9
function getStyle(obj,name){
if(obj.currentStyle){
return obj.currentStyle[name];
}
else{
return getComputedStyle(obj,false)[name];
}
}

XMLHttpRequest

1
2
3
4
5
6
7
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE的获取方式
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}

classList

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
if (!("classList" in document.documentElement)) {
Object.defineProperty(HTMLElement.prototype, 'classList', {
get: function() {
var self = this;
function update(fn) {
return function(value) {
var classes = self.className.split(/\s+/g),
index = classes.indexOf(value);
fn(classes, index, value);
self.className = classes.join(" ");
}
}
return {
add: update(function(classes, index, value) {
if (!~index) classes.push(value);
}),
remove: update(function(classes, index) {
if (~index) classes.splice(index, 1);
}),
toggle: update(function(classes, index, value) {
if (~index)
classes.splice(index, 1);
else
classes.push(value);
}),
contains: function(value) {
return !!~self.className.split(/\s+/g).indexOf(value);
},
item: function(i) {
return self.className.split(/\s+/g)[i] || null;
}
};
}
});
}

其他

cookie大小

  • IE50个,每个最长4095
  • FF 50个,每个最长4097

针对同一个域名同时发起的http请求数

http://ggbond.qiniudn.com/request.png

图片来源自:stevesouders

后续遇到兼容性会问题,会持续更新这篇文章

转载注明出处或者联系作者
Fork me on GitHub