blog-md
blog-md copied to clipboard
无线性能优化--自动化编译响应式图片方案
响应式图片方案
现状
对于图片的处理,我们目前一律采用3倍图尺寸的原图格式(.jpg/.png等)。
然而,移动端设备千差万别,这样的原图在很大程度上都是一种加载资源的浪费。
从精细化运营出发
从精细化运营的角度思考,我们要关注以下几个问题:
-
devicePixelRatio:
设备是iphone 8这样的2倍图手机,还是iphone 8 plus等3倍图设备?2倍图手机加载三倍图片,这是一种不必要的流量消耗,同时也降低了性能。
-
是否支持webp:
安卓机器支持webp图片格式,相比原图,可以降低30-80%左右的图片体积,观感上没有区别,这样的收益是不可忽略的;然而苹果手机完全不支持。
- 图片资源的hash值:
图片的hash值是根据图片内容尺寸生成的,对于长缓存的资源,这是一种保护,然而也意味着hash值有可能频繁变动,如果需要在运行时做些图片的处理,处理hash值会很头疼。
-
压缩图片:
压缩是使用tinypng好,还是其他服务好?免费不?一次上传几张?解压再copy回来?
-
对首屏图片资源进行预加载:
现代mvvm框架,只有当生成的DOM元素进入renderTree后,匹配到的css中的图片资源才会开始加载。然而框架下载、初始化、解析模板、生成元素及渲染页面是有时间成本的,这个时间大概在100-1000ms不等。
如上图所示,如果等待页面生成renderTree后才开始下载图片,用户会看到明显的图片加载过程,这也是现代前端框架的弊病:浏览器多年以来针对html/css资源做出的优化在使用前端框架后,大部分都失效了。是否可以在框架下载前就开始关键图片的加载呢?
用户体验至上
以上的几点不仅需要在项目开发完进行图片压缩,构建时处理hash值,还要在运行时获取用户设备dpr信息,加载相应的图片资源,考虑是否支持webp等,同时要结合构建时、运行时的信息,将首屏的资源进行预加载。
同时,还有一些webpack编译流程中潜在的问题还未列出。
在频繁迭代的繁重业务中,还需要考虑这些问题,这是一件很不友好的事儿。
但优化图片的需求又是真实存在的,它可以极大的提高用户体验。
FOX中的图片方案
幸运的是,在FOX方案中,上述几点已经得到了解决。
-
开发者只需正常开发,即可让图片资源根据手机情况自动区分@2x/@3x、webp、progressive、图片压缩。
-
对于首屏中的关键图片,还可以声明式的预加载。
约定
一. 在stylus/css文件中使用url("")设置jpg/png/jpeg图片
FOX方案内置对css原生的url函数进行了劫持处理,所以确保严格按照以下约定开发:
-
图片资源切出3倍图,确保在
src/assets
文件夹下,不要建立子文件夹 -
无需压缩图片,上线后自动完成图片压缩
-
设置图片:
// App.san <style lang="stylus"> .test-image height rem(1000) width rem(1242) background-image url("~assets/background.jpg") </style>
所有使用url("")
声明的jpg/png/jpeg图片都会自动获得优化。
注意:使用background-image属性设置图片。
当使用background时,FOX内部处理属性无法正确判断类名优先级,这种防御式编程可能会带来不想要的结果。
开发体验不打折扣。
接下来,来解决最后一步的首屏资源预加载问题。
2. 在src/config/pagesConfig
中声明需要预加载的图片
如果不希望对首屏关键图片做预加载,那么可以忽略这一步。
虽然声明起来也相当简单:
module.exports = {
// 活动主页
home: {
path: '/activity/stargy/home',
title: '测试主页',
pageDataApiPath: '/api/index',
template: 'base.ejs',
preloadImages: [
'background.jpg' // 关键图片声明
]
},
// 分享页
share: {
path: '/activity/stargy/share',
title: '测试分享页',
pageDataApiPath: '/api/index',
template: 'base.ejs'
}
};
在src/config/pagesConfig
配置文件中的preloadImages
属性,声明需要预加载的图片即可。
此文件详细配置信息可以在src/config/pagesConfig.js 开发的pages配置找到。
深入
progressive排版
FOX响应式图片方案不但会智能区分webp,还默认使用了progressive图片排版。
对比baseline图片
体验对比
它和普通的baseline自上而下逐帧加载的排版方式有什么区别呢?来看下面的对比:
当图片需要一定的加载时间时,baseline图片很明显的有加载过程,而且这种体验是突兀的;progressive图片则是一种渐进式的转换,更符合人的感官体验。
性能对比
progressive图片比baseline图片加载要快。
通常,当baseline图片加载第一帧时,progressive图片已经将轮廓渲染好,而且浏览器也可以针对这种图片做渲染优化。
唯一的缺点就是几年前图片解码比较消耗cpu和内存,不过在现代移动端机器上已经不是问题了。
实际测试
我们使用chrome自带的lighthouse工具来进行测试,这两个页面都会加载一个140kb的背景图,只是图片排版方式不同。
来看页面加载过程及实际性能指标的对比:
很明显,使用progressive图片的页面,页面全白等待加载的时间更短,这体现在Speed Index
指标上: 2840ms => 1710ms,这说明页面填充的速度提高了1秒左右。
百度云BOS图片服务
stylus/css编译流程
模块resolve问题
运行时动态添加preload预加载
总结
这就是兼顾了性能及开发体验的FOX响应式图片方案。