
面向仍需支持 IE11 的项目,目标是在不牺牲核心可用性的前提下,对 JS 的 ES6 语法与常用 Web API、以及 CSS 的现代特性做可控的转译、垫片与降级。本文给出工程实践、常见坑位与测试清单,帮助前端团队稳定交付。
ie 11useBuiltIns: "usage" 搭配 core-js@3regenerator-runtime 用于 async/await.browserslistrc
> 0.5%
last 2 versions
ie 11
not deadbabel.config.js
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: { ie: '11' },
useBuiltIns: 'usage',
corejs: 3
}
]
]
}Webpack 示例(按需转译第三方依赖)
module.exports = {
module: {
rules: [
{
test: /\.(js|mjs)$/,
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules/some-esm-lib')
],
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{ targets: { ie: '11' }, useBuiltIns: 'usage', corejs: 3 }
]
]
}
}
}
]
}
}class、arrow function、template string、destructuring、for-of 均由 Babel 处理Promise、Map/Set、Object.assign、Array.from、String.includes 等由 core-js 自动注入async/await 依赖 regenerator-runtime,入口文件引入 import 'regenerator-runtime/runtime'whatwg-fetch 或通过 axios 规避原生缺失URL、URLSearchParams 在 IE11 缺失,按需引入 core-js/web/urlNodeList.forEach,由 core-js 或自行降级循环for-of 需要 Symbol.iterator,确认 core-js 注入到全局tsconfig.json
{
"compilerOptions": {
"target": "ES5",
"module": "ESNext",
"lib": ["ES2015", "DOM"],
"downlevelIteration": true,
"esModuleInterop": true,
"skipLibCheck": true
}
}ts-loader 输出后再经 BabeldownlevelIteration 确保 for-of 与展开操作在对象/Map/Set 上正确运行postcss.config.js
module.exports = {
plugins: [
require('postcss-preset-env')({
stage: 3,
autoprefixer: { grid: 'autoplace' },
features: { 'custom-properties': false }
})
]
}.browserslistrc 自动补齐前缀,启用 grid: 'autoplace' 为 IE11 生成 -ms-gridcustom-properties 的编译以便用运行时垫片或手动降级@supports 做条件启用,默认使用 Flex 作为基础布局.container { display: -ms-flexbox; display: flex }
@supports (display: grid) {
.container { display: grid; grid-template-columns: repeat(12, 1fr) }
}-ms-grid 时,显式定义行列并用手动定位.wrapper { display: -ms-grid; -ms-grid-columns: 1fr 1fr; -ms-grid-rows: auto }
.item-a { -ms-grid-column: 1; -ms-grid-row: 1 }
.item-b { -ms-grid-column: 2; -ms-grid-row: 1 }display: -ms-flexbox; display: flex-ms-flex: 1 0 auto 对齐 IE11 的伸缩语法min-height: 0 带来的溢出问题,必要时显式设置容器尺寸css-vars-ponyfill<script src="https://unpkg.com/css-vars-ponyfill@2"></script>
<script>cssVars({ onlyLegacy: true })</script>position: sticky:用 stickyfilljs 针对 IE11 进行模拟object-fit: cover:用包裹元素加 background-size: cover 进行降级will-change,用 transform 与 opacity 实现woff、ttf 双份,避免老环境渲染问题if (!window.Promise) {
// 加载轻量垫片或关闭依赖该能力的分支
}IE11 的兼容关键在于构建期的系统性配置与运行期的必要垫片,再辅以清晰的视觉与交互降级策略。通过 Babel、PostCSS 与特性检测配合,绝大多数 ES6 与 CSS 新特性都能以可接受的姿态在低版本浏览器中运行,帮助团队在历史包袱与现代体验之间达成平衡。
import legacy from '@vitejs/plugin-legacy'
export default {
plugins: [legacy({ targets: ['ie >= 11'], modernPolyfills: true })]
}export default {
output: { format: 'iife' }
}@babel/preset-env 搭配 @babel/plugin-transform-runtime,减少重复辅助代码体积module.exports = {
presets: [['@babel/preset-env', { targets: { ie: '11' }, useBuiltIns: 'usage', corejs: 3 }]],
plugins: [['@babel/plugin-transform-runtime', { corejs: false }]]
}import 'core-js/stable'
import 'regenerator-runtime/runtime'useBuiltIns: 'usage' 按需注入,避免过度膨胀if (!('closest' in Element.prototype)) { await import('element-closest') }passive: true,统一使用普通监听或在新浏览器分支下条件开启(function () {
if (typeof window.CustomEvent === 'function') return
function CustomEvent(event, params) {
params = params || { bubbles: false, cancelable: false, detail: undefined }
var evt = document.createEvent('CustomEvent')
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail)
return evt
}
CustomEvent.prototype = window.Event.prototype
window.CustomEvent = CustomEvent
})()classListvar nodes = Array.prototype.slice.call(document.querySelectorAll('.item'))Intl 在 IE11 可能缺失或实现不完整,按需加载 intl 与对应 locale 数据import 'intl'
import 'intl/locale-data/jsonp/zh'Intl.NumberFormat 与 Intl.DateTimeFormat,避免自实现出现地区差异whatwg-fetch 或统一采用 axiosresponseType = 'json' 的依赖,改为文本后手动解析var xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.responseType = 'text'
xhr.onload = function () { var data = JSON.parse(xhr.responseText) }
xhr.send()picture 与 srcset:在旧环境用单一 img 源或引入 picturefillobject-fit:改用包裹元素加 background-size: cover 实现karma-ie-launcher 和 Jasminemodule.exports = function (config) {
config.set({
frameworks: ['jasmine'],
browsers: ['IE'],
files: ['dist/bundle.js', 'test/**/*.spec.js']
})
}@babel/plugin-transform-runtime 减少 helper 重复.grid { display: -ms-grid; -ms-grid-columns: 1fr 1fr 1fr; -ms-grid-rows: auto auto }
.grid { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(2, auto) }
.a { -ms-grid-column: 1; -ms-grid-row: 1 }
.b { -ms-grid-column: 2; -ms-grid-row: 1 }
.c { -ms-grid-column: 3; -ms-grid-row: 1 }
.d { -ms-grid-column: 1; -ms-grid-row: 2 }
.e { -ms-grid-column: 2; -ms-grid-row: 2 }
.f { -ms-grid-column: 3; -ms-grid-row: 2 }core-js 注入.browserslistrc 并统一构建配置