浏览器兼容性问题探究

作者:YJW

后台管理项目浏览器兼容性一览

IE / EdgeFirefoxChromeOpera360QQ
image.pngimage.pngimage.pngimage.png(图)360浏览器(图)QQ浏览器
IE10, Edgelast 2 versionlast 2 versionlatestlatestlatest

一、框架、配置与依赖库

我们的后台管理系统项目是基于 Ant Design 框架开发的,并使用了 Ant Design Pro 脚手架搭建,因此根据 Ant Design 的浏览器兼容性来说,是可以完全支持现代浏览器以及 IE 11、Edge 的,而对于 IE 9/10 也会有一定的支持。

对于 IE 9/10,我们可以通过 polyfill 解决部分兼容问题。

一般来说可以使用 babel-preset-env 来处理,但由于我们的后台项目使用了 Umi,也可以直接通过配置 targets 来实现。targets 的配置会自动引入 polyfill 和做语法转换,配置的 targets 会合并到默认值,所以不需要重复配置。

export default { 
    targets: {
        ie: 9, 
     },
  };

由于使用了 polyfill 进行语法转换,需要注意引用依赖库的时候必须是引用本地库,而不能引用外部 CDN,因为外部 CDN 是直接引用而没有经过 polyfill 的,这会导致 ES6 语法无法转为 ES5 语法, 而 IE 10 及以下版本不支持或者不完全支持 ES6 的。

export default {
  externals: {
    // if is production externals react react-dom and bizcharts
    // ...(NODE_ENV === 'production'
    //   ? { react: 'React', 'react-dom': 'ReactDOM', bizcharts: 'BizCharts' }
    //   : {}),
  },

}
<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- <script src="//gw.alipayobjects.com/os/lib/react/16.8.1/umd/react.production.min.js"></script> -->
    <!-- <script src="//gw.alipayobjects.com/os/lib/react-dom/16.8.1/umd/react-dom.production.min.js"></script> -->
    <!-- <script src="//gw.alipayobjects.com/os/lib/bizcharts/3.4.3/umd/BizCharts.min.js"></script> -->
  </head>
  <body>
  </body>
</html>

同样,由于 IE 10 及以下版本不支持 ES6 语法,我们在引用依赖库的时候,库里面的代码必须是已被转换成 ES5 语法的。在默认配置下,node_modules 里面所有库都不会在项目打包的时候进行语法转换,所以如果有一些库代码只有原始 ES6 版本的,可以配置项目打包的时候也对这些库进行语法转换。

在我们的项目中,sooncity 和 cn-validator 这两个库是需要转换的,如果在开发过程中遇到其他库也是用的 ES6 语法引起 IE 浏览器报错,也可以加入到 extraBabelIncludes 配置中。

export default {
  extraBabelIncludes: [
	path.resolve("node_modules/sooncity/src"),
    path.resolve("node_modules/cn-validator/lib")
  ]
}

注:webGL的原因 IE 10 及以下版本是不支持的
另外,IE 10 及以下版本对 umi-plugin-react 中 dva 的动态加载配置不支持,如果配置了动态加载浏览器会报错。

image.png 这个问题暂时未有解决方案。可参考这个 ISSUE 继续追踪。
因此如果要实现浏览器的 IE 10 兼容,只能禁用 dva 的动态加载

export default {
  plugins: [
    'umi-plugin-react',
    {
      dva: {
        dynamicImport: undefined,
      }
	}
  ]
};

最后,还需要注意依赖库的版本。有些依赖库在新版本中优化了浏览器兼容性问题,对我们开发来说是非常方便的。

  • Antd:建议更新到 3.25.3 及以上版本
  • Umi:建议更新到 2.12.5 及以上版本

如果项目的 package-lock.json 文件没有提交到 git 仓库,容易引起线上编译部署时依赖包版本不可控的问题,建议把 package-lock.json 从 .gitignore 中移除并提交。

二、代码兼容性优化

在开发过程中,可以注意一些保证浏览器兼容的代码细节,以下是一些比较常见的问题:

正则表达式

Chrome / FireFox 等现代浏览器支持 ES6 语法,因此也支持构建 RegExp 的时候使用正则表达式,例如:

console.log("1+2".replace(new RegExp(/\+/, 'g'), ' '));

但对于 IE,这种写法是不支持的,可以改成以下写法:

console.log("1+2".replace(new RegExp("\\+", 'g'), ' '));
console.log("1+2".replace(/\+/g, ' '));

ScrollBar

IE / Chrome / FireFox 等不同内核的浏览器对滚动条的写法都是不一样的,支持修改的属性也不一样。基本写法如下:

/* Chrome */

/* 滚动条 */
::-webkit-scrollbar {
  width: 4px;
  height: 4px;
  background-color: transparent;
}
/* 滚动条轨道 */
::-webkit-scrollbar-track {
  background-color: transparent;
  border-radius: 4px;
}
/* 定义滑块 */
::-webkit-scrollbar-thumb {
  background-color: green;
  border-radius: 24px;
}
/* 滚动条上的按钮 (上下箭头) */
::-webkit-scrollbar-button{
}
/* 滚动条没有滑块的轨道部分 */
::-webkit-scrollbar-track-piece {
}
/* 当同时有垂直滚动条和水平滚动条时交汇的部分 */
::-webkit-scrollbar-corner {
/* FireFox */
/* 滚动条属性只对指定元素作用,不会自动继承,需要对所有需要的元素设置滚动条属性,或者全局对所有元素设置 */
.scroller {
  scrollbar-width: thin; // 滚动条宽度,可选 auto / thin / none
  scrollbar-color: #0A4C95 #C2D2E4; // 滑块颜色 滚动条颜色
}
/* IE */
 
/* 滚动条样式 */
.scroller {
  scrollbar-arrow-color: #f4ae21; // 三角箭头的颜色
  scrollbar-face-color: #333; // 立体滚动条的颜色
  scrollbar-3dlight-color: #666; // 立体滚动条亮边的颜色
  scrollbar-highlight-color: #666; // 滚动条空白部分的颜色
  scrollbar-shadow-color: #999; // 立体滚动条阴影的颜色
  scrollbar-darkshadow-color: #666; // 立体滚动条强阴影的颜色
  scrollbar-track-color: #666; // 立体滚动条背景颜色
  scrollbar-base-color:#f8f8f8; // 滚动条的基本颜色
}
 
/* 控制元素内容溢出时滚动条的行为, 可选值如下:     */
/* auto:初始值等同于inherit                        */
/* scrollbar:出现传统滚动条                        */
/* -ms-autohiding-scrollbar:出现会自动隐藏的滚动条 */
/* none:不出现滚动条                               */
.scroller {
  -ms-overflow-style: scrollbar;
}

注:IE Edge 已删除旧版本 IE 中滚动条相关的非标准CSS属性配置,因此无法进行任何滚动条属性修改。

在处理滚动条样式的时候,还会遇到滚动条宽高度不确定性的问题。这个时候我们可以巧妙利用 vw / vh 和 %。当赋值 width: 100vw 的时候,所得到的宽度是包含滚动条宽度的,而  width: 100% 的时候则不包括,在适当的时候用适合的写法,或者计算两者只差,都有助于我们开发需要的样式。

渐变色

CSS3 的 gradient 属性在 IE 9 及以下版本是无效的,可以通过 IE 滤镜添加渐变效果:

.button {
  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#000000', endColorstr='#ffffff',GradientType=0 ); // 兼容 IE 9  
  background: -moz-linear-gradient(top, #000000 0%, #ffffff 100%); 
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#000000), color-stop(100%,#ffffff)); 
  background: -webkit-linear-gradient(top, #000000 0%,#ffffff 100%); 
  background: -o-linear-gradient(top, #000000 0%,#ffffff 100%); 
  background: -ms-linear-gradient(top, #000000 0%,#ffffff 100%); 
  background: linear-gradient(to bottom, #000000 0%,#ffffff 100%); 
}

Chrome / FireFox 等现代浏览器支持 ES6 语法,因此也支持构建 RegExp 的时候使用正则表达式,例如:

console.log("1+2".replace(new RegExp(/\+/, 'g'), ' '));

Flex布局
IE 9 及以下版本不支持 display: flex 布局,需要通过其他样式写法来回避这个问题。
跨域请求
IE 9 及以下版本不支持带 header 的跨域请求,可以通过服务端渲染等其他手段回避这个问题。 Placeholder
IE 9 及以下版本不支持 / 标签的 placeholder 属性。可以通过配置 value 并监听 Focus 和 Blur 事件实现类似 placeholder 的效果。

文字溢出

IE / Firefox 不支持 text-overflow: ellipsis 的自动继承,需要在该元素中做对应配置。

.button {
  display: block;
  max-width: 116px;
  height: 32px;
  text-overflow: ellipsis;
  -ms-text-overflow: ellipsis;
  overflow: hidden;
  > span {
    display: block;
    max-width: 116px;
    text-overflow: ellipsis;
    -ms-text-overflow: ellipsis;
    overflow: hidden;
  }
}

拖放事件

IE 使用 dragEvent.dataTransfer.setData 方法时,key 必须是 'Text',对于其他浏览器没有限制。

dragEvent.dataTransfer.setData('Text', JSON.stringify(model))

文件读取

IE 不支持 FileReader 的 readAsBinaryString 方法,如果需要前端处理非文本文件的数据读取,可以采用 readAsArrayBuffer 代替,并对 arrayBuffer 进行转换处理。

if (!FileReader.prototype.readAsBinaryString) {
  FileReader.prototype.readAsBinaryString = function (fileData) {
    var binary = '';
    var pt = this;
    var reader = new FileReader();
    reader.onload = function (e) {
      var bytes = new Uint8Array(reader.result);
      var length = bytes.byteLength;
      for (var i = 0; i < length; i++) {
          binary += String.fromCharCode(bytes[i]);
      }
      if(pt.target) {
        pt.target.result = binary
      } else {
        pt.target = { result: binary };
      }
      pt.onload(pt);
    }
    reader.readAsArrayBuffer(fileData);
  }
}

style 写入

我们想给元素的 style 赋值的时候,如果直接给 style 赋值,IE 会报 “strict 模式下不允许分配到只读属性” 这个错误。可以通过以下方法解决:

ele.style = 'height: 6px;width: 200px;' // 错误写法,在严格模式下ele.style会被认定为只读属性。

ele.style.height = '6px' // 正确写法,给某个样式赋值
ele.className = 'classA' // 正确写法,把需要改写的样式写在某个类名下