兼容性不是“和浏览器打仗”,而是“在预算里买安心”。真有用户在用的版本,就兼容;没人用,就果断放弃。
一屏清单(先定目标,再动手)#
- 覆盖矩阵靠数据,不靠感觉:看你站点的真实用户(Analytics/埋点)
- iOS 上所有浏览器都是 WebKit,一刀切看 Safari 版本就够
- JS 优先“特性检测”,少做 UA 判断;CSS 用
@supports
包住新特性 - 工具链最小闭环:Browserslist → Autoprefixer(CSS)→ Babel/preset-env + core-js(JS)→ 可选 Vite Legacy
- 移动端三个常客:100vh 在 iOS、sticky + overflow、键盘顶起布局
- 避免第三方不受控的 Polyfill CDN,自己打包或自托管
第一步:三分钟定兼容目标(决策树)#
- 业务问答
- 我们的移动端流量占比?iOS/Android?哪些国家地区?
- 月活前 90% 的设备/浏览器版本落在哪?
- 决策
- 目标线用 Browserslist 表达。示例:
# .browserslistrc(标准档)> 0.5%last 2 versionsnot deadiOS >= 14Safari >= 14
- 如需更“稳”,上进阶档(成本更高):
# 进阶档:再覆盖一些旧安卓> 0.3%last 3 versionsnot deadiOS >= 13Android >= 7ChromeAndroid >= 90
[!tip] 跑一遍数据
npx update-browserslist-db@latest
保持 caniuse-lite 新鲜,减少“明明支持却被警告”的错觉。
第二步:CSS 兼容怎么落地(别扯,直接配)#
- Autoprefixer 接前面的 Browserslist 就行:
module.exports = { plugins: [require('autoprefixer')] };
- 新特性建议
- 容器查询(container queries):用
@supports (container-type: inline-size)
包起来 - 子网格(subgrid)、
:同理,先探测再用
- 容器查询(container queries):用
/* :has 增强版,有就用;没有就退化 */@supports selector(:has(*)) { .card:has(img) { /* 高级选择器样式 */ }}
- 移动端单位
- 新的
svh/lvh/dvh
很香,但旧 Safari 不全有;常用组合:
- 新的
/* 现代浏览器优先 */.main { min-height: 100dvh; }/* iOS 旧版兜底 */@supports (-webkit-touch-callout: none) { .main { min-height: -webkit-fill-available; }}
- sticky 的老梗
- 父级有
overflow
、transform
、perspective
等,position: sticky
会失效。能不用就别用;需要就保证祖先不遮。
- 父级有
第三步:JS 兼容怎么搞(两件事)#
-
语法降级(syntax)与 API 垫片(polyfill)是两码事
- 语法交给编译器:Babel/SWC/ESBuild
- API 用 core-js/自托管 polyfill
-
最小配置(Babel 党)
npm i -D @babel/core @babel/preset-env core-js
module.exports = { presets: [['@babel/preset-env', { targets: '> 0.5%, last 2 versions, not dead', useBuiltIns: 'usage', corejs: 3 }]],};