第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里:

  1. 确认目标浏览器列表(IE11?Edge旧版?iOS Safari最低版本?)
  2. 检查SDK中是否使用了@supports、@media (prefers-*)等条件查询
  3. 对Array、Object、Promise、fetch等基础API做polyfill覆盖
  4. 测试CSS Grid / Flexbox在Safari上的布局是否错位
  5. 测试WebSocket/SSE在Firefox和Safari上的连接稳定性
  6. 测试Cookie设置与读取在Safari隐私模式下是否正常
  7. 测试Service Worker注册与更新在Chrome无痕模式下的行为
  8. 记录每个浏览器的console error,归类到“引擎差异”或“版本缺失”

2.5 内核关系一览

下面这张SVG图可以帮你快速理清主流浏览器之间的内核继承关系。我画的时候特意把Chromium家族放在中间,因为现在大部分浏览器都基于它了。

主流浏览器内核生态图 Chromium(Blink) Chrome Edge Opera Firefox(Gecko) Safari(WebKit) IE(Trident,已退役) ※ 注:IE已停止支持,Edge已于2019年转向Chromium内核。 Firefox和Safari仍使用自研引擎,需重点关注差异。

从图里能看出来,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初始化失败。