下表汇总 31 个高频前端特性的最低支持版本,覆盖 Chrome、Edge、Firefox、Safari 与 iOS Safari 五端。单元格数字为该浏览器首个完整支持的版本;◐ 表示该版本起仅部分支持(脚注说明);✗ 表示从未支持。
| 特性 | Chrome | Edge | Firefox | Safari | iOS Safari |
|---|---|---|---|---|---|
| CSS Flexbox 布局 | 29 | 12 | 28 | 9 | 9 |
| CSS Grid 布局 | 57 | 16 | 52 | 10.1 | 10.3 |
| position: sticky | 56 ◐ | 16 ◐ | 32 ◐ | 7.1 | 8 |
| aspect-ratio 宽高比 | 88 | 88 | 89 | 15 | 15 |
| 容器查询 @container | 106 | 106 | 110 | 16.0 | 16.0 |
| :has() 选择器 | 105 | 105 | 121 | 15.4 | 15.4 |
| CSS 自定义属性 var() | 49 | 16 | 31 | 10 | 10 |
| flex 中的 gap | 84 | 84 | 63 | 14.1 | 14.5 |
| CSS color-mix() | 111 | 111 | 113 | 16.2 | 16.2 |
| inset 简写属性 | 87 | 87 | 66 | 14.1 | 14.5 |
| text-wrap: balance | 130 | 130 | 121 | 17.5 | 17.5 |
| <dialog> 元素 | 37 | 79 | 98 | 15.4 | 15.4 |
| details / summary | 12 | 79 | 49 | 6 | 6 |
| picture / srcset 响应式图片 | 38 | 13 | 38 | 9.1 | 9.3 |
| WebP 图片格式 | 32 | 18 | 65 | 16.0 | 14 |
| AVIF 图片格式 | 85 | 121 | 93 | 16.4 | 16.0 |
| fetch API | 42 | 14 | 39 | 10.1 | 10.3 |
| async / await | 55 | 15 | 52 | 11 | 11 |
| 可选链 ?. | 80 | 80 | 74 | 13.1 | 13.4 |
| 空值合并 ?? | 80 | 80 | 72 | 13.1 | 13.4 |
| Array.prototype.at() | 92 | 92 | 90 | 15.4 | 15.4 |
| structuredClone() | 98 | 98 | 94 | 15.4 | 15.4 |
| IntersectionObserver | 51 ◐ | 16 | 55 | 12.1 | 12.2 |
| ResizeObserver | 64 | 79 | 69 | 13.1 | 13.4 |
| WebSocket | 16 | 12 | 11 | 7 | 6 |
| Service Worker | 45 | 17 | 44 | 11.1 | 11.3 |
| ESM import | 61 | 16 | 60 | 11 | 11 |
| import.meta | 64 | 79 | 62 | 12 | 12 |
| Web Components(Custom Elements v1) | 67 | 79 | 63 | ◐ 10.1 | ◐ 10.1 |
| CSS 原生嵌套 | 120 | 120 | 117 | 17.2 | 17.2 |
| :is() / :where() 选择器 | 88 | 88 | 78 | 14 | 14 |
这是应对兼容差距的两种方向相反的工程哲学。
| 对比维度 | 渐进增强(Progressive Enhancement) | 优雅降级(Graceful Degradation) |
|---|---|---|
| 出发点 | 先保证所有浏览器可用的核心内容与功能,再向上叠加高级体验 | 先按最新浏览器完整实现,再为旧浏览器打补丁、退化体验 |
| 实现顺序 | 语义化 HTML → 基础 CSS → 增强布局 → 增强交互(JS) | 完整方案 → 缺失 API 时转降级分支或提示升级 |
| 典型手段 | @supports 特性检测、无 JS 的可用性、结构化降级样式 | polyfill 补齐 API、浏览器嗅探、功能开关回退 |
| 适用场景 | 内容型站点、SEO 友好、面向广泛用户(如电商、资讯) | 工具型应用、内部系统、交互复杂且用户可控(如在线编辑器) |
| 风险 | 增强代码量随特性增加,需克制 | 降级分支容易长期堆叠,维护成本高 |
实际项目中两者常组合使用:内容与核心链路渐进增强(弱网、旧设备也能完成主任务),辅助能力优雅降级(如不支持 container queries 时退回媒体查询布局)。
与其猜测浏览器版本,不如直接问浏览器「你支持吗」。CSS 的 @supports 与 JS 的 CSS.supports() 是标准答案,比 UserAgent 嗅探可靠得多。
最小代码示例:CSS 与 JS 两种特性检测
/* CSS:仅当浏览器支持容器查询时才启用增强布局 */ @supports (container-type: inline-size) { .card { container-type: inline-size; } @container (min-width: 480px) { .card__body { display: grid; grid-template-columns: 1fr 2fr; } } } /* 不支持时整体降级为媒体查询方案 */ @media (min-width: 768px) { .card__body { display: grid; grid-template-columns: 1fr 2fr; } } // JS:运行时探测后再加载 polyfill 或走降级分支 if ('IntersectionObserver' in window) { const io = new IntersectionObserver(lazyLoad); io.observe(imgEl); } else { // 不支持时直接用 loading="lazy" 或滚动事件兜底 imgEl.loading = 'lazy'; } if (window.structuredClone) { clone = structuredClone(obj) } else { clone = JSON.parse(JSON.stringify(obj)) }
特性检测决定「要不要补」,Polyfill 负责「补什么」,Babel 负责「把语法编译成目标浏览器能解析的形式」。两者分工:语法转译(箭头函数、可选链等)靠 Babel/SWC 编译,运行时 API 缺失(Promise、Array.prototype.at 等)靠 Polyfill 注入(见 Babel 与 Polyfill 词条)。
| 手段 | 解决问题 | 典型配置 / 说明 |
|---|---|---|
| @babel/preset-env + targets | 按目标浏览器按需转译语法 | 设置 targets: { chrome: '90', ios: '13' },编译器自动决定转译范围 |
| core-js / polyfill | 补齐 Promise、Array.at、structuredClone 等运行时 API | 配合 useBuiltIns: 'usage' 只注入用到的 API,控制体积 |
| browserslist | 统一声明目标浏览器范围 | > 0.5%, last 2 versions, not dead,Autoprefixer、Babel、ESLint 共用 |
| 动态 polyfill 服务 | 避免全量打包 | 按请求头 UA 返回所需 polyfill;也可配合模块隔离自行实现 |
最小代码示例:browserslist 与 Babel targets
// .browserslistrc(被 Babel、Autoprefixer、ESLint 共用) > 0.5% last 2 versions not dead not ie 11 // 明确放弃 IE // babel.config.js module.exports = { presets: [[ '@babel/preset-env', { targets: { chrome: '90', firefox: '88', safari: '14', ios: '13' }, useBuiltIns: 'usage', // 按代码实际用到的 API 注入 core-js corejs: 3 } ]] };
CSS 的兼容成本主要在厂商前缀与属性命名差异。Autoprefixer 基于 browserslist 自动补齐 -webkit- / -moz- 等前缀,PostCSS 生态还能配合 PostCSS 插件把现代 CSS(如嵌套)降级编译,让书写体验与兼容性解耦(见 CSS 嵌套语法)。
/* 源码(只写标准语法) */ .sticky { position: sticky; top: 0; } /* Autoprefixer 按 browserslist 自动输出: */ .sticky { position: -webkit-sticky; /* Safari 6.1~13 需要 */ position: sticky; top: 0; }
兼容目标不是「支持所有浏览器」,而是「覆盖目标用户的主流环境」。决策建议:
这些是兼容史上反复出现的问题。现代环境下多数已无需处理,但面试与存量项目维护中仍是高频考点。
| 问题 | 兼容背景 | 经典方案(旧写法) | 现代方案 |
|---|---|---|---|
| 半透明 | IE 8 不支持 rgba / opacity 会被子元素继承 | filter: alpha(opacity=50);或 PNG24 背景图 trick | 直接用 rgba() / opacity;毛玻璃用 backdrop-filter(Safari 需 -webkit-) |
| 圆角 | IE 8 及以下不支持 border-radius | -webkit-border-radius + border-radius: 0\9 或九宫格图片圆角 | 直接写 border-radius;前缀由 Autoprefixer 处理 |
| Flexbox 2009 旧语法 | IOS 6 / Android 4.4 以下只支持 display:-webkit-box | 三套写法并列:display:-webkit-box; display:-ms-flexbox; display:flex | 仅写 display:flex;参见 flex(现代设备全覆盖) |
| 1px 边框过粗 | 高 DPR 屏上 1px CSS 像素对应 2~3 物理像素 | transform: scaleY(0.5) 伪元素细边框;border-image 或 0.5px(iOS 8+ 支持) | 0.5px(Chrome 129+ / Safari 16.4+ 已稳定)或保留 scale 方案(兼容性最稳) |
| position: sticky 失效 | Safari 13 前需 -webkit-;IE 全系不支持 | 加 position:-webkit-sticky;IE 用 JS 滚动监听模拟 | Autoprefixer 自动补前缀;详见 position: sticky |
| 图片懒加载 | 旧浏览器无 IntersectionObserver | scroll 事件 + getBoundingClientRect 判断(配合 节流);或 IntersectionObserver + 降级 | 原生 <img loading="lazy">(Chrome 76+ / Safari 15.4+),见 图片懒加载 |
| 移动端 300ms 点击延迟 | 双击缩放检测导致 | FastClick 库 / touchstart 模拟 | 设置 touch-action: manipulation 或现代浏览器已默认消除(viewport 含 width=device-width 时) |
| input 占位符样式 | 旧版 IE / Safari 不支持 :placeholder | JS 模拟占位文本(value + focus 判断) | ::placeholder 加 :-ms-input-placeholder(Autoprefixer 已覆盖) |