前端浏览器兼容问题总结

14,531 阅读16分钟

浏览器占比现状

在各大浏览器厂商的发展过程中,他们其实对web的标准都有不同的实现,因为实现的标准的不同,所以会有兼容性的产生,早期IE是在浏览器的世界中,占据主导地位。所以它自身实现了很多不同于标准浏览器的东西,有css的,也有js的。

从IE8开始,IE浏览器渐渐遵循标准,到IE9后由于大家都一致认为标准很重要,可以说在兼容性上比较好了,但是在中国来说,由于xp的占有率问题,还是有很多xp系统ie7、8浏览器。
国家互联网应急中心(CNCERT)2018年第四季度国内操作系统及浏览器占比情况分析:





js兼容问题及解决

1、js中 style、currentStyle和getComputedStyle的区别

1.1 style:各大浏览器都兼容,能设置样式和获取样式,但是获取不了外部样式。
写法:ele.style.attr(这样为获取),ele.style.attr="值";
1.2. currentStyle:该属性只兼容IE,不兼容火狐和谷歌
ele.currentStyle.attr;
1.3. getComputedStyle:该属性是兼容火狐谷歌,不兼容IE8及以下
window.getComputedStyle(ele,null).attr
通常使用 getComputedStyle 读取样式,通过 element.style 修改样式。
可选[pseudoElt]属性:指定一个要匹配的伪元素的字符串。不需要伪元素可以为null
配合该属性可以从伪元素拉取样式信息:比如,::after, ::before

 getComputedStyle(oDiv, '::after').content;

//兼容性写法: 

 function getStyle(ele,attr){ 

    if(ele.currentStyle){ 

         return ele.currentStyle[attr] 

    }else{ 

         return getComputedStyle(obj,false)[attr] 

    } 

 }


2. 使用event对象

 以主流浏览器 IE、谷歌、火狐为例:
  (1) IE  在IE中,event 是一个全局的变量,不存在作用域的问题。也就是说,谁触发了事件,那在事件绑定的函数中,你可以直接使用event的属性做任何操作,没有作用域的限制,也没有其他函数格式的要求。
        (2)Chrome 谷歌  谷歌做的也不错,使用也没有什么问题。在 Chrome 中,event并不是全局变量。他是在每个事件绑定的函数中都默认传入了一个形参event,注意函数的第一个形参就是event对象,而且我们不需要去写这个形参。如果你要在事件绑定的函数中使用 event,那直接 event . 点他的属性即可。系统默认将event对象以参数的形式传递到了函数中。这里不需要你做任何操作,只管用,简单粗暴。
IE 和 Chrome 虽然看起来用法一样,其实还是有本质区别的,只是浏览器封装的好而已。
        (3)Firebox 火狐 火狐就麻烦一点了。因为火狐中压根就没有event这个变量。不过解决方法也是很简单的:
1.2.1 用户不传参:
      想要使用 event,我们就需要先使用如下语句  
     var e = arguments.callee.caller.arguments[0] || window.event
     arguments.callee.caller.arguments[0]:
     函数体本身-->函数体的调用函数体--> function onclick()
    argument.callee.caller.arguments[0]即为传参集合的第一个形参event了.
1.2.2. 传参(event)


 3.获取目标元素:

兼容写法:event.srcElement ? event.srcElement : event.target;
srcElement:ie


4. attachEvent和addEventListener

4.1 attachEvent是IE有的方法,它不遵循W3C标准,而其他的主流浏览器如FF等遵循W3C标准的浏览器都使用addEventListener,所以实际开发中需分开处理。
4.2 多次绑定后执行的顺序是不一样的,attachEvent是后绑定先执行,addEventListener是先绑定先执行。
ele.attachEvent('onclick',function(){

console.log('test...')

})//ie11以及以上不支持 chrome不支持 ff不支持

ele.addEventListener("click",function(){

console.log('ceshi...')

},false) //ie8及以下 不支持


5. 获取dom节点:

parentElement 获取对象层次中的父元素。
parentNode 获取文档层次中的父结点。


在Dom文档结构中,HTML页面每一部分都是由节点组成的,节点的类型一共有3种,元素节点,文本节点,属性节点,从图中可以看出属性节点属于元素节点的分支,一般不常考虑。

两者在通常情况下都是一样的,因为包含元素的节点只有可能是元素节点,这里可能会有一个误区,有些人可能会想文本节点是否可以包含元素节点,来作为父节点,这里是不行的,文本节点只是文本本身,自身算一个节点,文本节点的父节点直接是元素节点。
二者唯一区别:
因为parentElement找的是元素,因此当找到根部document时候就是出现值为null的报错,而且parentNode找的是节点,当然就可以显示出来了!
bodyDom.parentNode.parentNode.parentNode.parentNode
---#document

bodyDom.parentElement.parentElement.parentElement.parentElement

---null


6、日期函数处理

IE8以下:new Date().getFullYear() === new Date().getYear()
:得到的是当前年份 2019

IE9、标准浏览器: new Date().getYear() 为 119
:得到的是当前年份(2019)与1900年的差值  119


7、集合类对象问题

问题说明:IE下,可以使用 () 或 [] 获取集合类对象;Firefox下,只能使用 [ ]获取集合类对象。
解决方法:统一使用 [] 获取集合类对象。


8、鼠标按键编码的兼容

W3C标准下:0,1,2分别代表左,中,右三个键;
在ie11及以上 + 主流浏览器下 是符合W3C标准的,但是在ie10以及以下:
左中右分别为:1 4 2
function but(evt){ 

    var e = evt || window.event;

    if(evt){

       return e.button; 

    } else if (window.event){ 

         switch(e.button){ 

            case 1: return 0; 

            case 4: return 1; 

            case 2: return 2; 

         } 

    }

 }


9、8引出的其它问题:

ie中的window.event全局对象和 事件访问对象(传递的参数evt) 的区别:

1.DOM标准描述了一个Event对象,提供了触发事件的元素信息,并允许在脚本中获取该元素。
2. ie中的事件处理:
ie的全局event对象的属性不同于DOM标准的event对象,但提供的数据类似。
区别:
DOM事件模型与IE事件模型之间的主要区别是事件信息的访问方式,以及获取引发事件的元 素的方式。
DOM是需要传送事件引用给处理函数,IE中直接通过全局的event访问;
DOM中获取获取引发事件的元素对象是通过tarfet属性,而IE是通过srcElement属性。

css兼容性问题

首先是<!DOCTYPE>的声明 位于位于HTML文档中的第一行,处于 <html> 标签之前。告知浏览器的解析器用什么文档标准解析这个文档。DOCTYPE不存在或格式不正确会导致文档以兼容模式呈现。
标准模式的排版 和JS运作模式都是以该浏览器支持的最高标准运行。在兼容模式中,页面以宽松的向后兼容的方式显示,模拟老式浏览器的行为以防止站点无法工作。

1、reset

最主要也是最常见的,就是浏览器对标签的默认支持不同,所以我们要统一,就要进行CSS reset 。但是不要为了reset而reset:

但是很多时候我们的CSS reset过于臃肿,主要有两个问题:

     1.1 把很多浏览器对元素的默认属性有设置了一边,比如div的padding和margin为0啊什么的,这是没有必要的

    1.2 把一些很不常用的元素的设置也写进了CSS reset。


2、上下margin重合问题

相邻的两个div margin-left margin-right 不会重合,但相邻的margin-top margin-bottom会重合。


3、td高度的问题 

 table中td的宽度都不包含border的宽度,但是oprea和ff中td的高度包含了border的高度 。

解决: 设置line-height和height一样。在ie中如果td中的没有内容,那么border将不会显示。

4、兼容ie8 或者ie9 或任意ie版本浏览器

       4. 1.条件注释法(IE10+已经不支持条件注释)
大于 gt || 大于等于 gte || 小于 lt || 小于等于 lte(<!--[if gte IE 8]><![endif]-->)
用ie浏览器独有的文档注释的方式。像这样:
<!DOCTYPE html> 

<!--[if IE 8 ]> <html class="ie8" lang="en"> <![endif]--> 

<!--[if IE 9 ]> <html class="ie9" lang="en"> <![endif]--> 

<!--[if (gt IE 9)|!(IE)]><!--> 

<html lang="en"> <!--<![endif]-->

可以独立的维护处理兼容ie浏览器的样式表,又不会淹没在一大堆css hack标识中,只需要在独立对ie8应用样式规则的地方

       4.2. 非IE(IE10+也能识别),此处多加的<-->,在IE中被当作内部注释,而在非IE浏览器中会闭合之前的注释(<!--[if !IE]><--><![endif]-->)
<!--[if !IE]><-->  

<div class="box" id="box"></div> 

<![endif]-->


5、对于360双核浏览器

可以添加以下头部meta信息可以使得网页用webkit内核渲染:
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
IE=edge:保持使用最高级别模式显示内容;
chrome=1:谷歌的外挂插件Google Chrome Frame(谷歌内嵌浏览器框架GCF),使用IE浏览网页时实际上是使用Chrome浏览器内核渲染,最低支持IE6,但前提是客户端已经安装GCF。

但实际上这个meta标识是ie浏览器所识别的,并不是公认的标准,所以有时你会发现360并不能总是以chrome内核渲染你的按现代标准开发的网页。

可以试试通过添加:<meta name="renderer" content="webkit">
这个meta标识是360自家实现的(详情:meta.html),表示强制要求360浏览器用chrome的内核渲染网页。se.360.cn/v6/help/met…


6、ie8的css兼容

     6.1 使用meta标签调节浏览器的渲染方式:
IE8中有一个“兼容性视图”的概念,当初IE8发布时,相对于IE6/7已经做出了非常大的改进,但是很多老站点仅针对IE6/7进行了优化,使用IE8渲染反而会一团糟。IE8加入了“兼容性视图”功能,这样的话就可以在IE8中使用IE6或IE7的内核渲染页面。这个当然不是我们想要的,所以需要使用meta标签来强制IE8使用最新的内核渲染页面,代码如下:
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
IE=edge表示强制使用IE最新内核,
chrome=1表示如果安装了针对IE6/7/8等版本的浏览器插件Google Chrome Frame(可以让用户的浏览器外观依然是IE的菜单和界面,但用户在浏览网页时,实际上使用的是Chrome浏览器内核),那么就用Chrome内核来渲染。
对比360:<meta name="renderer" content="webkit">
   

     6.2 ie8中的一些css 不支持

            6.2.1  ie8支持:first-child,但不支持:last-child。因为前者是css2.1标准,后者是css3标准。推荐的做法不是使用last-child,而是给最后一个元素设置一个.last的class,然后对此进行样式设置,这样就全部兼容了。

            6.2.2 html5shiv.js
IE8不支持HTML5的新标签,如<header><nav>等标签在IE8无法渲染。html5shiv.js可帮助IE6-8浏览器兼容HTML5语义化标签。
使用方法:在页面中引用html5shiv.js文件。必须添加在页面的<head>元素内,因为IE浏览器必须在元素解析前知道这个元素,所以这个js文件不能在页面底部引用。

            6.2.3. Respond.js
IE8不支持CSS媒体查询,对响应式设计大大不利。Respond.js可帮助IE6-8兼容“min/max-width”媒体查询条件。
使用方法:在页面中所有css文件的引用位置之后引用Respond.js。而且Respond.js的引用得越早,用户看到页面闪烁的机会越小。

           6.2.4. CSS3字体单位“rem”兼容方案:rem.js
CSS3引入了新的字体大小单位rem,与em的“相对于其父元素来设置字体大小”的功能不同,rem是相对于根元素<html>的字体大小比率单位,成了目前主流的单位之一。IE9+开始支持,IE8就只能通过引入js库来支持了。
使用方法:在页面中引用rem.js文件。需要引用在页脚,也就是<body>末尾,在所有css文件引用和DOM元素之后。


           6.2.5. 一些其它不支持的属性:
border-radius 圆角
box-shadow 盒子阴影
CSS3 Background 背景渐变


7、placeholder 

不支持ie10-以下的版本(可以通过使用一个span标签来模拟提示。)


关于css优化问题:

1、不要使用*{} 类似的通配符

这种方法虽然写起来简单,但是渲染起来,浏览器引擎要遍历所有的标签,很影响效率。为了对浏览器友好,可以把自己经常用的标签进行重置操作。

2、尽量少用绝对定位和浮动等高性能属性

虽然绝对定位可以很简洁的实现很棒的效果,但是由于浏览器的渲染机制,网页中如果用过多的绝对定位,会让网页加载速度变得很慢。

3、利用CSS继承减少代码量

  我们知道有一部分CSS代码是可以继承的,如果父元素已经设置了该样式,子元素就不需要去设置该样式,这个也是提高性能的行之有效的方法。
  常见的可以继承的属性比如:
  color,font-size,font-family,text-align,line-height等等
  不可继承的比如:
  position,display,float,display,background。width等等

4、CSS Sprites减少http请求

小图标 通过一张雪碧图 控制background-position来请求

5、合写css:

font
background
padding
margin

6、不要用标签或 class 来限制 ID 规则

很多人会写出#test.info或者div#test这样的选择器,这个只能说是画蛇添足,id已经可以唯一而且最快的定位一个元素了

7、避免通配选择器

CSS选择器对性能的影响源于浏览器匹配选择器和文档元素时所消耗的时间,所以优化选择器的原则是应尽量避免需要消耗更多匹配时间的选择器。而在这之前我们需要了解CSS选择器匹配的机制,如例子的子选择器规则:
#header a {font-weight:blod;}
我们中的大多数人都是从左到右的阅读习惯,可能也会习惯性的设定浏览器也是从左到右的方式进行匹配规则,因为会推测这条规则的开销并不高。我们这样假象浏览器会像这样的方式工作:找到唯一的id为header为的元素,然后把这个样式规则应用到直系子元素中的a元素上。我们知道文档中只有一个id为header的元素,并且它只有几个a类型的子节点,所以这个CSS选择器应该相当高效。
事实上,却恰好相反,CSS选择器是从右到左进行规则匹配。了解这个机制后,例子中看似高效的选择器在实际中的匹配开销是很高的,浏览器必须遍历页面中所有的a元素并且确定其父元素的id是否为header。
如果把例子的子选择器改为后代选择器则会开销更多,在遍历页面中所有a元素后还需向其上级遍历直到根节点。
#header a {font-weight:blod;}
理解了CSS选择器从右到左匹配的机制后,可以理解选择器中最右边的规则往往决定了浏览器继续左移匹配的工作量,我们把最右边选择规则称之为关键选择器。
通配选择器使用 * 符合表示,可匹配文档中的每一个元素。如下例规则将所有元素的字体大小设置为20px:
* { font-size:20px;}
通配选择器作用于所有的元素,如规则最右边为通配符:
.selected * {color: red;}
浏览器匹配文档中所有的元素后分别向上逐级匹配class为selected的元素,直到文档的根节点,因此其匹配开销是非常大的,通常比开销最小的ID选择器高出1~3个数量级,所以应避免使用关键选择器是通配选择器的规则。

8、避免单规则的属性选择器

属性选择器根据元素的属性是否存在或其属性值进行匹配,如下例规则会把herf属性值等于”#index”的链接元素设置为红色:
.selected [href=”#index”] {color: red;}
但其匹配开销是非常大的,浏览器先匹配所有的元素,检查其是否有href属性并且herf属性值等于”#index”, 然后分别向上逐级匹配class为selected的元素,直到文档的根节点。所以应避免使用关键选择器是单规则属性选择器的规则。

9、避免类正则的属性选择器

CSS3添加了复杂的属性选择器,可以通过类正则表达式的方式对元素的属性值进行匹配。当然这些类型的选择器定是会影响性能的,正则表达式匹配会比基于类别的匹配会慢很多。大部分情况下我们应尽量避免使用 *=, |=, ^=, $=, 和 ~=语法的属性选择器。

10、移除无匹配的样式:

移除无匹配的样式,有两个好处:
第一,删除无用的样式后可以缩减样式文件的体积,加快资源下载速度;
第二,对于浏览器而言,所有的样式规则的都会被解析后索引起来,即使是当前页面无匹配的规则。移除无匹配的规则,减少索引项,加快浏览器查找速度;