什么是浏览器兼容器
浏览器兼容性指的是不用浏览器拥有不同的内核,而不同的浏览器又分为两种:一是渲染引擎,另一个是js引擎。(一般也指css兼容,js兼容)因此在解析html和css,js时就会有不同的处理,因为不同浏览器展示情况也不同。 不过好在微软已经不维护IE浏览器了,以后前端再也不用因为处理低版本的IE浏览器绞尽脑汁,秃头有救了。
浏览器内核
不同的浏览器内核是不一样的,下面我们主要介绍几种常见的浏览器的内核
- trident内核:代表就是IE浏览器。百度浏览器,世界之窗浏览器也是用的这个。
- webkit内核:苹果的safari浏览器就是这个内核,以前的谷歌浏览器也是这个内核
- Blink内核:现在的谷歌浏览器
- Gecko内核:火狐浏览器的内核
- Presto内核:Opera浏览器,后来加入了谷歌大军,变成了webkit,最后又变成了Blink
- IE + Chrome双内核:360浏览器,猎豹浏览器,2345浏览器以前是IE内核,现在也是双内核了
- Trident(兼容模式) + Webkit(高速模式): 搜狗,遨游,QQ浏览器
- UC浏览器内核:这个众口不一,UC说是他们自己研发的U3内核,但好像还是基于Webkit和Trident,还有说是基于火狐内核。
常见浏览器兼容性问题
上面也提到过,对于浏览器兼容性问题,主要分为两类:css兼容性问题和js兼容性问题。
css兼容性问题
- 不同浏览器的标签默认的margin和padding不同
- 表现: 随便写一个标签,在不同的浏览器中,各自的margin和padding差异很大
- 解决方式:新建一个重置样式文件,将这种类型的元素统一设置
- css3新属性在不同浏览器中效果不同,有的不生效
- 块元素设置浮动后,又有水平方向的margin,在IE浏览器下margin加倍
- 解决方式: 给浮动元素设置display: inline, 将其转换为行内元素
- 给元素的高度设置值很小(小于10px), 在遨游,IE6,IE7下高度超过自己甚至的高度
- 表现:这种情况一般出现在我们设置小圆角背景的标签里。出现这个问题的原因是IE8之前的浏览器都会给标签一个最小默认的行高的高度。即使你的标签是空的,这个标签的高度还是会达到默认的行高。
- 解决方式:给容器添加overflow: hidden;或者line-height设置为小于我们设置的高度。
- 行内元素设置display: black后采用浮动,又有水平方向的margin时,IE间距出现问题
- 表现:IE6里的间距比超过设置的间距
- 说明:行内元素,为了设置宽高,需要设置display: block;(除input外),在用float布局并有横向的margin后,在IE6下,他就具有了块属性float后的横向margin的bug。不过因为它本身就是行内属性标签,所以我们再加上display:inline的话,它的高宽就不可设了。这时候我们还需要在display:inline后面加入display:talbe。
- 解决方式:在display:block;后面加入display:inline;display:table;
- IE浏览器div最小高度和宽度的问题
- 表现:min-height本来就是一个不兼容的属性
- 解决方式:设置为:{min-height: 200px; height: auto !important; height: 200px; overflow: visable;}
- 超链接访问过hover样式就不出现的问题
- 表现:被点击访问过的超链接样式不再具有hover和active了。
- 解决方式:改变css属性的排列顺序。L-V-H-A(:link -> :visited -> :hover -> :active)
- 图片默认有间距
- 表现: 几个img标签放在一起的时候,有些浏览器会有默认的间距,通配符清除间距也不起作用
- 解决方式:通过给所有的图片设置浮动或者给所有的img标签设置display: block;
- css hack解决浏览器兼容性问题 不同浏览器,识别不同的样式,css hack本身就是处理浏览器的兼容性问题的。 比如:height: 300px; *height: 200px; _height: 100px;
- 百分比的bug
- 表现:父元素的宽度为100%,子元素宽度各为50%,在IE6下各个元素宽度之和超过100%
- 解决方式:给右边浮动的元素添加clear: right;
- 透明度属性
- 表现:IE浏览器和其他浏览器对于透明度属性的支持写法不一样
- 解决方式:针对IE浏览器:filter: alpha(opacity=value); (取值范围1--100)。 兼容其他浏览器:opacity: value; (取值范围0--1)
- 上下margin的重叠问题
- 表现:给上边元素设置margin-bottom,给下边元素设置margin-top,浏览器只会识别最大值
- 解决方式:其实这个也不算是兼容性问题,我们只设置其中一个就可以了
js兼容性问题
- 事件绑定 表现:IE:dom.attachEvent('onclick', function(){}); 标准浏览器:dom.addEventListener('click', function(event){}, false); 解决方式:
var x = document.getElementById('myBtn');
if (x.addEventListener) {
// 所有主流浏览器, ie9+
x.addEventListener('click', myFunction);
} else if (x.attachEvent) {
// IE8及更早版本
x.attachEvent('onclick', myFunction);
}
- event事件对象问题 表现:
document.onclick = function(ev) {
// 谷歌火狐的写法,IE9以上支持
var e = ev;
}
document.onclick = function() {
// 谷歌和IE支持
var e = event;
}
解决方式
document.onclick = function(ev) {
var e = ev || window.event;
}
- event.srcElement(事件源对象)问题 表现:IE: event对象有srcElement属性,但是没有target属性; 火狐:event对象有target属性,但是没有srcElement属性。 解决方式:
srcObj = event.srcElement ? event.srcElement : event.target;
- 获取元素的非行间样式值 表现: IE: dom.currentStyle['width']获取元素高度; 标准浏览器:window.getComputedStyle(obj, null)['width']; 解决方式:
function getStyle(obj, attr) {
if (obj.currentStyle) {
// 兼容IE
return obj.currentStyle[attr];
} else {
return window.getComputedStyle(obj, null)[attr];
}
}
- 阻止事件冒泡传播 表现:IE:e.cancelBubble = true; 标准浏览器:e.stopPropagation(); 解决方式:
document.onclick = function (e) {
var e = e || window.event;
if (e.stopPropagation) {
// 标准浏览器
e.stopPropagation();
} else {
// IE浏览器
e.cancelBubble = true;
}
}
- 阻止事件默认行为 表现:js阻止默认事件,一般是阻止a链接href,form表单submit提交. 标准浏览器: event.preventDefault(); IE浏览器:e.returnValue = 'false';
document.onclick = function (e) {
var e = e || window.event;
if (e.preventDefault) {
// 标准浏览器
e.preventDefault();
} else {
// IE浏览器
e.returnValue = 'false';
}
}
- ajax兼容问题 表现:IE: ActiveXObject. 其他标准浏览器:XMLHttpRequest 解决方式:
// 创建ajax对象
var oAjax = null;
if (window.XMLHttpRequest) {
// 只支持非IE6浏览器
oAjax = new XMLHttpRequest();
} else {
// 只支持IE6浏览器
oAjax = new ActiveXObject('Microsoft.XMLHTTP');
}
// 连接服务器,这里加个时间参数,每次访问地址都不一样,浏览器就不用浏览器里的缓存了,服务器那端也不会解析这个时间
oAjax.open('get', 'a.txt?=' + new Date().getTime(), true);
// 发送
oAjax.send(null);
// 接受信息
oAjax.onreadystatechange = function() {
if (oAjax.readyState === 4) {
if (oAjax.status == 200) {
alert('成功' + oAjax.responseText);
} else {
alert('失败')
}
}
}
总结
以上是关于浏览器兼容性的问题,对于工作时间比较早的同学来说,可能或多或少的遇到过这些问题,对于最近一两年才工作的同学来说,可能见都没见过这些问题,没有关系,我们只需要了解一下就好,毕竟现在项目开发很少去兼容低版本的IE浏览器了,而且前端时间微软也正式公布不再维护IE浏览器了,所以以后基本上也不用处理IE浏览器兼容性问题了。
在vue项目中如何处理浏览器兼容性问题
我们在开发过程中,主要还是基于主流js框架来开发,比如:vue或者react。还会结合一些UI框架来开发,而且用到的JavaScript也基本是es6语法,或者ts这种,下面我们就来看看这里面会存在哪些兼容性问题,以及怎么处理。 我主要使用的是vue.js, 所以我主要以vue来举例
常见UI框架兼容性问题
对于css中的一些样式,比如像flex布局这种,一般使用post2css-loader来处理。对于一般的elementUI框架都会兼容一些主流浏览器版本,如果还需要额外兼容别的浏览器则需要另外处理。 针对具体的样式兼容性,我们会根据ie浏览器具体去补充。 关于样式这块,我们就先写到这,后续有什么问题我们会在这里继续补充的。
需要注意的是:vue3不再支持ie11,对应的elementUIplus也不再支持ie11.
vue.js中的兼容性问题
这里面的主要兼容性问题有以下几个方面
- vue 只兼容IE8以上版本。 (IE8之前的版本太低,我们可以不考虑,不做任何处理)
- IE不兼容axios的promise对象 主要是下载插件包es6-promise来解决。
- IE不兼容ES6语法 大家在开发项目的时候,基本上都会遇到浏览器页面白屏,控制台报错的问题,然后大家可能会疑惑,我在谷歌浏览器中运行的好好的呀。为什么在IE11中就不行了呢。这个主要原因就是IE浏览器不支持es6的语法啦,下面我们一起来看一下如何兼容ie11这类不兼容es6的问题。
推荐给大家两个比较好用的网站
- 查看es6在各大浏览器不同版本的支持情况: css和兼容性检查平台:caniuse.com/?search=es6 这个网站可以很清楚地看出浏览器对es6的支持情况。
- 查看es6语法和api的兼容性详细统计情况: github统计es6兼容性站点:kangax.github.io/compat-tabl… 从这个网站可以看出各大浏览器和插件对es6里面详细API的支持,因此我们就可以很轻松的找到解决方案了。然后我惊喜地发现IE11现在对es6的语法支持变多了。但是这并不影响我们处理我们兼容性问题,因为总可能遇到会存在兼容性问题的时候,根据这个网站也能帮我们找到解决问题的思路:那就是编译器里面Babel 7 + core-js 3基本上能解决浏览器不支持es6语法的问题。
引入babel7
需要注意的是,babel默认只转换js语法(如=>, class等),不转换新的api(如:Iterator, Generator, set, maps, proxy, reflect, symbol, Promise等全局对象,以及一些定义在对象上的方法:Object.assign等),因此还需要引入转换新api的工具库
引入core-js3
想要兼容/转换es6+的新api, 就需要core-js3来支持了。 core-js可以有效支持promises, symbols, collections, iterators, typed arrays等,需要注意的是,转换新api的方案叫做pollyfill, babel-polyfill是兼容版api的延续至今的一套方案。它内部引入了core-js2, 又集成了regenerator-runtime,但是使用这套方案会把全部api特性全部打包,会导致为使用的新的api的引入导致文件过大或全局污染。那么对应的按需加载的方案就来了:babel-runtime。 babel-time不同babel-polyfill的是它可以结合babel插件babel-plugin-transform-runtime,按需引入babel-runtime中的polyfill.但是babel-runtime也有其缺点:它只支持静态方法。includes, Object.assign等实例下es6方法支持不足,解决这个问题就需要相应插件来满足。
babel插件化
刚刚说到babel插件化,babel有很多解决特定问题的插件,比如:babel-plugin-array-includes 、@babel/plugin-transform-arrow-functions、 babel/plugin-proposal-class-properties等,但是这些插件如果一个一个引入也是很麻烦的,有没有可以一起引入所有插件的方法呢?
babel插件整合方案
最早期的插件整合方案常用的叫babel-preset-es2015,它解决了最早期es6特性的兼容性问题,但是随着es6+的各种特性的出现,后面由扩展出了babel-preset-stage-1、babel-preset-stage-2、babel-preset-stage-2、babel-preset-stage-3,具体差别和功能不做赘述,大家可以自行了解一下。随着以上方案的扩展,慢慢babel-preset-es2015需要一个最新的集成方案,于是就有了babel-preset-env,就是那个每次npm安装babel-preset-2015时都提醒我们的babel-preset-env安装提醒,它可以根据目标浏览器或者运行环境配置来自动转换es2015+的代码。
babel配置
关于babel配置,vue项目中有很多地方都可以配置处理,如packge.json、babel.config.js、.babelrc、.browserlistrc。大家根据实际情况配置和查看相应文件里面的配置。 这里面需要注意的是,从babel7开始,.babelrc的作用范围仅限于当前项目,默认不再作用于 node_modules 和工作区 (./packages/*),如果需要,可以指定作用范围。一般通过babel.config.js和.browserlistrc来做babel的转译处理了。具体的配置,这里不做详细解读了,官网有比较详细的解释:www.babeljs.cn/docs/config…
- babel.config.js
module.exports = {
env: {
test: {
presets: [
[
'@babel/preset-env',
{
targets: {node: 'current'},
}
]
]
}
},
presets: ['@vue/cli-plugin-babel/preset', '@babel/preset-env'],
};
- .browserlistrc
> 0.25%
last 2 versions