第2章 主流浏览器介绍:版本与内核差异
2.1 浏览器格局演变
做前端兼容性测试,第一步得先搞懂现在市面上谁说了算。我记得2015年那会儿,IE还占着企业市场的大头,我每天上班第一件事就是打开IE11测一遍,生怕哪块JavaScript报错。这几年变化太大了——IE退役,Edge换壳,Chrome一家独大,Safari靠苹果生态活得挺好,Firefox还在坚持开源路线。
你想想看,这些浏览器的内核和渲染引擎都不一样,同一个CSS属性在不同浏览器里渲染结果能差出几个像素。我建议每个前端同学都养成一个习惯:开发时至少打开Chrome、Firefox、Safari三个窗口,随时看一眼差异。等SDK接进去之后,更要逐个版本跑一遍。
2.2 核心浏览器速览
下面这张表帮你快速对齐每款浏览器的“家底”。我一般把它贴在工位墙上,记不清了就瞄一眼。
| 浏览器 | 内核 | 渲染引擎 | JS引擎 | 当前主流版本 | 更新周期 |
|---|---|---|---|---|---|
| Chrome | Chromium | Blink | V8 | 128+ (2025) | 6周 |
| Edge | Chromium | Blink | V8 | 128+ | 4周 |
| Firefox | Gecko | Gecko | SpiderMonkey | 135+ | 4周 |
| Safari | WebKit | WebKit | JavaScriptCore | 17+ | 跟随macOS/iOS |
| IE (退役) | Trident | Trident | Chakra | 11 (停止支持) | — |
注意:Edge从79版本开始改用Chromium内核,旧版EdgeHTML已废弃。我现在接SDK测试时,Chrome和Edge兼容性基本可以共用一套测试用例,但Firefox和Safari仍然需要单独跑。
2.3 版本差异关键点
下面这几条是我这些年踩坑踩出来的重点,你接SDK的时候一定要逐条核对。
- CSS前缀 – 早期flexbox、grid、transform都需要加厂商前缀。现在Chrome和Firefox都支持无前缀写法,但Safari对部分属性还很保守。我在项目中遇见过border-radius在Safari 13上渲染异常,原因是旧版WebKit需要加-webkit-前缀,而我当时只写了标准写法。
- ES6+语法支持 – V8和SpiderMonkey一直走得很靠前,JavaScriptCore略慢。举个例子:
Array.prototype.flat在Safari 12以下不存在,你要是不加polyfill,SDK在iOS 12的老设备上直接崩。我建议SDK发布前先用Can I Use查一遍目标版本。 - 渲染差异 – 盒模型、
box-sizing、flex布局的基线对齐、grid的gap实现,这些在Blink和Gecko之间基本一致,但WebKit有时会冒出一些奇怪的间距。我遇到过Safari里display: flex的子元素默认min-height行为不同,折腾了半天才发现要显式写min-height: 0。 - Web API 实现 –
IntersectionObserver、ResizeObserver、WebSocket等接口在不同引擎上有细微差异。比如IntersectionObserver在Safari 12.1之前是实验特性需要前缀,而Firefox 55才正式支持。我建议你在SDK的入口处做一个API检测,不支持的版本直接降级或报错提示。 - 安全策略 – 各浏览器对CORS、SameSite Cookie、混合内容、Service Worker生命周期的实现有先后和严格程度的不同。Chrome最激进,Safari最保守。你想想看,如果SDK里用到了
localStorage的第三方访问,Safari的智能防追踪可能会直接拦截。
我的小技巧:在SDK的CI流程里加入BrowserStack或者Sauce Labs,同时跑Chrome最新版+上一版、Firefox ESR版、Safari最新版+上一版、Edge稳定版。这样每次发版前都能自动发现版本差异导致的异常,就不用等QA来报bug了。
警告:不要相信“Chrome能跑就没事”。我曾经把一个SDK只放在Chrome上测,上线后用户反馈在Firefox上按钮点不了,排查发现是Firefox对event.target的规范更严格,Chrome宽容处理了。这件事实在太坑了,从那以后我坚持三个浏览器一起测。
2.4 兼容性测试关注清单
下面这个清单是我每次接SDK测试时都会过一遍的,你可以直接复制进自己的checklist里:
- 确认目标浏览器列表(IE11?Edge旧版?iOS Safari最低版本?)
- 检查SDK中是否使用了
@supports、@media (prefers-*)等条件查询 - 对
Array、Object、Promise、fetch等基础API做polyfill覆盖 - 测试CSS Grid / Flexbox在Safari上的布局是否错位
- 测试WebSocket/SSE在Firefox和Safari上的连接稳定性
- 测试Cookie设置与读取在Safari隐私模式下是否正常
- 测试Service Worker注册与更新在Chrome无痕模式下的行为
- 记录每个浏览器的console error,归类到“引擎差异”或“版本缺失”
2.5 内核关系一览
下面这张SVG图可以帮你快速理清主流浏览器之间的内核继承关系。我画的时候特意把Chromium家族放在中间,因为现在大部分浏览器都基于它了。
从图里能看出来,Blink引擎占了半壁江山。好处是Chrome、Edge、Opera、Vivaldi、Brave这些浏览器共用同一套渲染和JS行为,你只要测好Chrome,其他几个基本能复用结果。但Firefox的Gecko和Safari的WebKit总是会给你来点“惊喜”。我个人的建议是:把Chrome作为主要开发环境,Firefox和Safari作为必须覆盖的补充测试环境,IE如果还有客户在用就单独加一个降级方案。
2.6 版本策略建议
最后说一个我常用的版本检测思路。SDK接入时,不要硬编码来判断浏览器,而是检测特性是否存在:
// ✅ 推荐做法:特性检测
if ('IntersectionObserver' in window) {
// 使用 IntersectionObserver
} else {
// 降级为 scroll 监听
}
// ❌ 不推荐:UA 检测
// const ua = navigator.userAgent;
// if (ua.includes('Chrome')) { ... }
为什么要这样?因为Chrome和Edge的UserAgent里都有“Chrome”字样,Edge新版连内核都和Chrome一样,UA检测会误判。我手头就有一个线上bug就是因为UA检测把Edge当成了Chrome,结果Edge特有的一个安全策略没处理,直接导致SDK初始化失败。