回到目录

[前端知识体系] 兼容性

2017-11-26

对于前端工程师来说,兼容性指的是其主要宿主环境——浏览器的兼容性。为什么会有兼容性的问题,究其根源即浏览器的不同内核和不同版本对 HTML 标签、CSS 属性、JS API 的解析和支持度不同,当然还包括了浏览器引擎实现上的一些 bug。想要解决兼容性问题,不仅仅需要有手段,还要深入浏览器的渲染原理。

正如我在 [前端知识体系] 自我认知 提及的,兼容性是前端工程师最大的「脏活累活」工作量来源:

前端(后面的「前端工程师」简称为「前端」)面对的是这么一个世界:你的上游(视觉设计师)完全不懂编程并充满感性思维,你的下游(后台开发)完全不懂设计并忽略视觉呈现。而你,需要面对几大不同系统(Windows、Mac、Android、iOS)里的 N 个风格各异的浏览器,去保证统一的视觉效果,还得去适配好不同分辨率和尺寸的屏幕,再优化好页面的加载速度和页面体积,然后增加必要的动效和新颖的交互,同时把准确无误的数据从后台拉取并合理呈现,最后合并压缩发布上线迭代维护改版。

我们先来回顾下历史:

0x1 PC 时代

PC 时代,IE 如同毒瘤一般,成为了每个前端工程师中无法避开的一个心病。于是乎,各种肮脏的写法,各种 hack 层出不穷,只为了保证页面在 IE 浏览器中的一致性。幸运的是,移动时代的来临,PC 的地位越来越弱化,而国产浏览器的各种预装和病毒般的「全家桶」也缓解了很大的问题。

但作为有当担的商业公司的一名前端工程师,自然还是无法避开对 IE 的兼容,目前越来越多的公司只兼容到 IE8,非常多的前端框架也采取了同样的策略。但 IE8 依旧存在了一系列兼容性问题以及对新特性的不支持。

这里本着怀旧的态度,列举一些常见的 IE 兼容问题,「老一辈」前端工程师应该倍感情切:

  • DOCTYPE 文档类型:未声明时,IE6 的 Quirk 模式
  • hover 兼容:IE6 中只支持 a 标签的 hover 样式
  • PNG 透明:IE6 浏览器不支持 PNG alpha 透明
  • IE8/9 不支持 Array.indexOf
  • ......

这个时期的前端工程师,谁的电脑上没有装上各种各样的浏览器,或者是 IETester 这类体验极差但又不得不用的软件?谁的收藏夹里不放 Caniuse 网址?要我说最实用的,还是 BrowserHack 这种针对浏览器的 hack 大全。

0x2 移动时代

移动时代比起 PC 时代要幸福的多,虽然也出现过 Android 2.3 这种「移动时代的 IE」,但由于硬件更新的速度远远快于 PC,用户更换手机的频率也缩短至一两年,大部分的问题随着时间的推移逐渐消失。所以兼容性在移动时代几乎不再成为主要问题。

而且移动时代,打开浏览器去浏览页面的场景相对较少,用户最主要的内容消费是在 App 里。从业务和开发层面来考虑,更多的技术选型是 Hybric App 的模式:即 App 中部分场景承载内容的 Web,只不过因为套了一层 App 的壳,很多用户都意识不到这就是网页。

这对前端开发来说同理,因为这些内嵌 Web 页面的壳正如浏览器客户端这层壳一样,都依托于不同的渲染引擎来实现对内容的解析和呈现。那在移动端,最主流的渲染引擎即 Webkit。在 iOS 中浏览器组件有 UIWebView,它是 iOS 上对 WebKit 的封装,WebKit 是渲染引擎,UIWebView 是渲染引擎和 JavaScript 引擎的组合(你可以理解为「壳」)。

在 WWDC 2014 发布会上发布 iOS 8 中,Apple 公布了 Webkit 框架,并使用 WKWebView 组件来代替 iOS 的 UIWebView,摆脱过去 UIWebView 的老旧笨重特别是内存占用量巨大的问题。

相比起 iOS 强制统一使用自家的渲染内核(甚至 iOS 中的 Chrome 都是直接引用 WKWebView 组件,UA 直接显示的是 Safari),开放 Android 的浏览器内核则琳琅满目,UC 浏览器、QQ 浏览器、百度浏览器、Android 自带浏览器等等。这里梳理了一下:

  • 腾讯系:X5 内核(基于 Webkit 二次修改)
  • UC 系:U3 内核(基于 Webkit 二次修改)
  • Android 系:Webkit (4.4 之前)、Chromium (4.4 之后,Webkit 的分支 Blink)

Chromuim 项目是 Google 公司以苹果开源项目 WebKit 作为内核,创建的一个新的项目,该项目的目标是创建一个快速的、支持众多操作系统的浏览器。在 Chromium 项目基础上,Google 发布了自己的浏览器产品 Chrome。与使用 WebKit 作为内核的 Safari 浏览器不同,Chromium 本身就是一个浏览器,而不是Chrome 浏览器的内核,再未从 WebKit 项目分离之前,Chrome 浏览器使用的是 WebKit 内核。2013 年 4月,Google 宣布从 Webkit 复制出来并独立运作 Blink 项目,该项目也就是目前 Android4.4 及以上系统浏览器采用的内核。**

简而言之,Webkit 内核是移动时代的老大哥,也正是苹果正在使用的内核,它在 iOS 的壳是 UIWebview 和 WKWebview。谷歌基于 Webkit 开源项目弄出了一个分支,叫 Blink,也正是 Android 4.4 及以上系统浏览器采用的内核,它的壳是 WebView。知道内核能帮助我们对兼容性有更深层次的理解。

那移动端的兼容问题都有哪些?它主要来自 Android,并且花样更多了:

  • 在 Android 2.3 下,为元素添加 overflow:auto/scroll 无法滚动
  • :before、:after 伪元素动画在 Android 4.4 以下无法播放
  • CSS Animation 的顺序不对可能会导致解析错误
  • CSS Animation 在页面加载后立即执行会引发页面滑动丢帧的问题
  • Flexbox 的兼容性问题
  • ......

0x3 兼容性处理两大原则

首先不妨问问自己下面两个问题:

  • 页面是否需要在所有浏览器中保持视觉一致?
  • 网页动效是否要在所有浏览器中流畅无卡顿?

这里涉及两个概念:渐进增强优雅退化。两者好像是一回事,但又不太一样。取决于出发点是什么。以「渐进增强」为例,我们要在登录界面中做一个高斯模糊的背景,看起来逼格更高。那一般的实现方式即把设计稿里的高斯模糊背景保存为图片即可。但针对性能和兼容性都更好的 iOS 系统,我们可以使用 CSS3 的 filter 来实时计算高斯模糊的效果,这样一来还能满足产品经理定期替换背景图片而无需二次开发的需求。「渐进增强」是立足于当前可满足的前提下,为提供了更好条件和环境的平台提供更优的体验。

假如我收到另外一个需求:在页面上展示可视化图表,目前最佳选型自然是 WebGL 或 SVG,能够做到效果最好,矢量高保真。主流浏览器也都支持。然而低端浏览器或 IE 却并不支持。为了能让这个功能顺利实现,让所有用户都能正常使用。这里我只能针对这些不支持 WebGL 和 SVG 的浏览器使用 Canvas 来绘制图表。若还遇到不支持 Canvas 的浏览器,那只能后台绘制并返回图片了。此为「优雅退化」,即立足于当前可满足的前提下,为更差的平台提供退化方案以确保功能正常。

我们一般在解决兼容问题的时候,往往都是采用「优雅退化」的原则,先确保功能可用。「渐进增强」那是锦上添花的事情。熟悉了这两个原则之后,我们不妨再次回答上面的两个问题:

1. 页面是否需要在所有浏览器中保持视觉一致?

对于大部分用户来说,他们看到的内容理所当然是要保持一致。但是对于少数用户,他们所在的环境已经很「艰难」了,对良好的体验已经无过多追求,那只要保证界面可看,功能可用,并不需要完全保证页面视觉或效果跟大众的一致。而且,从效益来说,这部分用户能提供的价值是否值得你花大量时间去做兼容,这个就让产品经理去思考把。而且这里还有个误区存在:产品经理或者测试人员自然希望你做到所有平台一致,因为他们不需要去解决问题,只需要验收问题而已。如果你没有足够的说服力,那么你只能闷声花上几倍的时间去弄这个破事。所以要把时间成本、人力成本、性价比、优先级抛出来,让参与人意识到做兼容是一件有成本的事情。

2. 网页动效是否要在所有浏览器中流畅无卡顿?

同理,谁都希望在不同手机,特别是在 iOS 上的动画能在 Android 中也一样流畅,但这是不可能的。 Android 本身的操作流畅度就不及 iOS,为何要求要在网页里就同样流畅呢?所以我的建议就是,对于有性能瓶颈的动画,在 Android 中直接使用更简单的实现方式。至于如果在 Android 中做性能优化,可以参考我后面的动画性能优化文章。

0x4解决问题

这里的解决问题并非要把所有兼容性问题罗列出来并一一提供解决办法,因为几乎大部分兼容性问题都可以在网络上查找到解决方案,这里更多的是讨论一些指导性的方法。

1. PC

PC 时代已经过去,再花大力气去做全浏览器支持是性价比非常低的一件事,基于时间成本和效益来考虑,对于 2B 业务,个人人为可以激进一些,比如支持到 IE9~10,甚至是不支持(因为用户有限,而且目标群众可控)。而针对 2C 业务,支持到 IE8 就已经非常负责了。为什么这里只提 IE,因为只要写法正确,有兼容性问题的就只有 IE 了。

那不支持的用户怎么办,可以提示他们更新浏览器:

甚至像微博、豆瓣一样支持不予理睬,既不提示升级,部分功能也用不了(可看到报错)。

2. Mobile

这里的大部分问题主要来自于 Android,特别是对于样式上的解析,以及 Android 性能不足带来的问题。iOS 很流畅,Android 很卡顿,这是大家普遍的感知。所以在写动画的时候尤其要注意动画降级。

3. 常用调试方法

Android 和 iOS 都提供了非常方便的提示工具,比如在 PC 中可以通过 USB 连接安卓手机并执行 chrome://inspect/ 查看手机中的 Chrome 浏览的页面,而 iOS 同样可以通过 Safari 的开发者工具调试,具体方式可以网上搜索。

也许还可能遇到浏览器没有问题,但是在内嵌 Webview 中有问题的情况,一般的原因就是 App 的 Webkit 内核过低,或者被人为定制过导致的。这种情况也可以借助 Weinre 来实现远程调试。

除了工具的介绍,还有问题的定位,经验丰富后一般都可以根据现象判断出问题所在。若实在无解也可以进行二分法删除定位(CSS)。