其实,骨架屏(Skeleton Screen)已经不是什么新奇的概念了,Luke Wroblewski 早在 2013 年就首次提出了骨架屏的概念,并将这一概念成功得运用到他当时的产品「Polar app」中,2014 年,「Polar」加入 Google,Luke Wroblewski 本人也成为了Google 的一位产品总监。
A skeleton screen is essentially a blank version of a page into which information is gradually loaded.
他是这样定义骨架屏的,他认为骨架屏是一个页面的空白版本,通过这个空白版本传递信息,我们的页面正在渐进式的加载过程中。
苹果公司已经将骨架屏写入到了 iOS Human Interface Guidelines(
https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/LaunchImages.html), 只是在该手册中,其用了一个新的概念「launch images」。在该手册中,其推荐在应用首屏中包含文本或者元素基本的轮廓。
2015 年,Facebook 也首次在其移动端 App 中使用了骨架屏的设计来预览页面的加载状态。
随后,Twitter,Medium,YouTube 也都在其产品设计中添加了骨架屏,骨架屏一时成为了首屏加载的新趋势,国内一些公司也紧随其后,饿了么、知乎、掘金、腾讯新闻等也都在其 PC 端或者移动端加入了骨架屏设计。
为什么需要骨架屏?
- 在最开始关于 MIT 2014 年的研究中已有提到,用户大概会在 200ms 内获取到界面的具体关注点,在数据获取或页面加载完成之前,给用户首先展现骨架屏,骨架屏的样式、布局和真实数据渲染的页面保持一致,这样用户在骨架屏中获取到关注点,并能够预知页面什么地方将要展示文字什么地方展示图片,这样也就能够将关注焦点移到感兴趣的位置。当真实数据获取后,用真实数据渲染的页面替换骨架屏,如果整个过程在 1s 以内,用户几乎感知不到数据的加载过程和最终渲染的页面替换骨架屏,而在用户的感知上,出现骨架屏那一刻数据已经获取到了,而后只是数据渐进式的渲染出来。这样用户感知页面加载更快了。
- 再看看现在的前端框架, React 、Vue 、Angular 已经占据了主导地位,市面上大多数前端应用也都是基于这三个框架或库完成,这三个框架有一个共同的特点,都是 JS 驱动,在 JS 代码解析完成之前,页面不会展示任何内容,也就是所谓的白屏。用户是极其不喜欢看到白屏的,什么都没有展示,用户很有可能怀疑网络或者应用出了什么问题。 拿 Vue 来说,在应用启动时,Vue 会对组件中的 data 和 computed 中状态值通过 Object.defineProperty 方法转化成 set、get 访问属性,以便对数据变化进行监听。而这一过程都是在启动应用时完成的,这也势必导致页面启动阶段比非 JS 驱动(比如 jQuery 应用)的页面要慢一些。
饿了么移动 web 页面在 2016 年开始引入骨架屏,是完全通过 html 和 CSS 手写的,手写骨架屏当然可以完全复刻页面的真实样式,但也有弊端:
举个例子,突然有一天,产品经理跑到了我面前,这个页面布局需要调整一下,然后这一块推广内容可以去掉了,我当时的心情可能是这样的。
手写骨架屏带来的问题就是,每次需求的变更我们不仅需要修改业务代码, 同时也要去修改骨架屏的样式和布局,这往往是比较机械重复的工作,手写骨架屏增加了维护成本。
因此饿了么前端团队一直在寻找一种更好、更快的将数据呈现到用户面前的方案。
在选择骨架屏之前,我们也调研了其他两种备选方案:服务端渲染(ssr)和预渲染(prerender)。
现在,前端领域,不同框架下,服务端渲染的技术已经相当成熟,开箱即用的方案也有,比如 Vue 的 Nuxt.js。那么为什么不直接使用服务端渲染来加快内容展现?
首先我们了解到,服务端渲染主要有两个目的,一是 SEO,二是加快内容展现。在带来这两个好处的同时,我们也需要评估服务端渲染的成本,首先我们需要服务端的支持,因此涉及到了到了服务构建、部署等,同时我们的 web 项目是一个流量较大的网站,也需要考虑服务器的负载,以及相应的缓存策略,特别是一些外卖行业,由于地理位置的不同,不同用户看到的页面也是不一样的,也就是所谓的千人千面,这也为缓存造成了一定困难。