浏览器兼容性问题
常见浏览器兼容性问题及解决方案
问题
前端开发中常见的浏览器兼容性问题有哪些?如何解决?
解答
CSS 兼容性问题
1. 厂商前缀
/* 不同浏览器需要不同前缀 */
.box {
-webkit-transform: rotate(45deg); /* Chrome, Safari */
-moz-transform: rotate(45deg); /* Firefox */
-ms-transform: rotate(45deg); /* IE */
-o-transform: rotate(45deg); /* Opera */
transform: rotate(45deg); /* 标准写法放最后 */
}
/* 使用 Autoprefixer 自动添加前缀(推荐) */
/* 只需写标准写法,构建时自动补全 */
.box {
transform: rotate(45deg);
}
2. CSS Reset / Normalize
/* 简单的 CSS Reset */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* 或使用 Normalize.css 保留有用的默认样式 */
3. Flexbox 兼容写法
.container {
display: -webkit-box; /* 旧版 Safari */
display: -webkit-flex; /* Chrome 21-28 */
display: -ms-flexbox; /* IE 10 */
display: flex;
}
JavaScript 兼容性问题
1. 特性检测
// 检测特性是否存在,而不是检测浏览器
if ('querySelector' in document) {
document.querySelector('.box');
} else {
document.getElementById('box');
}
// 检测 localStorage
if (typeof Storage !== 'undefined') {
localStorage.setItem('key', 'value');
} else {
// 降级方案:使用 cookie
}
// 检测 fetch
if (window.fetch) {
fetch('/api/data');
} else {
// 使用 XMLHttpRequest 或引入 polyfill
}
2. Polyfill 示例
// Array.prototype.includes polyfill
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement, fromIndex) {
if (this == null) {
throw new TypeError('this is null or undefined');
}
const o = Object(this);
const len = o.length >>> 0;
if (len === 0) return false;
const n = fromIndex | 0;
let k = Math.max(n >= 0 ? n : len + n, 0);
while (k < len) {
if (o[k] === searchElement) return true;
k++;
}
return false;
};
}
// 使用 core-js 按需引入 polyfill(推荐)
import 'core-js/features/array/includes';
import 'core-js/features/promise';
3. 事件兼容
// 事件绑定兼容
function addEvent(element, type, handler) {
if (element.addEventListener) {
// 标准方式
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
// IE8 及以下
element.attachEvent('on' + type, handler);
} else {
element['on' + type] = handler;
}
}
// 事件对象兼容
function getEvent(e) {
return e || window.event;
}
function getTarget(e) {
return e.target || e.srcElement;
}
function preventDefault(e) {
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false; // IE
}
}
function stopPropagation(e) {
if (e.stopPropagation) {
e.stopPropagation();
} else {
e.cancelBubble = true; // IE
}
}
工程化解决方案
Babel 配置
// babel.config.js
module.exports = {
presets: [
['@babel/preset-env', {
targets: {
browsers: ['> 1%', 'last 2 versions', 'not dead']
},
useBuiltIns: 'usage', // 按需引入 polyfill
corejs: 3
}]
]
};
Browserslist 配置
# .browserslistrc
> 1%
last 2 versions
not dead
not ie <= 10
PostCSS + Autoprefixer
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
};
常见兼容问题速查
| 问题 | 解决方案 |
|---|---|
| IE 不支持 ES6+ | Babel 转译 + polyfill |
| CSS3 属性不生效 | Autoprefixer 添加前缀 |
| 默认样式不一致 | Normalize.css |
| 图片在 IE 下有边框 | img { border: 0; } |
| IE 盒模型差异 | box-sizing: border-box |
| 移动端 300ms 延迟 | FastClick 或 touch-action: manipulation |
关键点
- 特性检测优于浏览器检测:检测功能是否存在,而非判断浏览器类型
- 使用构建工具:Babel 处理 JS,Autoprefixer 处理 CSS 前缀
- 按需 Polyfill:配置
useBuiltIns: 'usage'避免打包冗余代码 - 渐进增强:先保证基础功能,再为现代浏览器添加增强体验
- 明确目标浏览器:通过 Browserslist 统一配置支持范围
目录