滑屏 H5 开发实践九问

3,080
原文链接: isux.tencent.com

滑屏的交互形式自从在 H5 中流行起来,便广泛应用在产品宣传、广告、招聘和活动运营等场景中,作为微信朋友圈广告惯用的形式,其影响力更是得到了强化与放大。如今滑屏H5可谓玲琅满目,数不尽数。

作为一个 UI工程师,接过很多类似的项目,也曾写过滑屏的插件,在经历了不同的需求的“洗礼”并踩过若干个坑之后,不禁反问自己:应该如何面对每一次类似的需求,在已有的经验下如何做到体验更好?如何节省工作量提高效率?面对性能优秀的 iOS 与性能良莠不齐的 Android 平台,又如何做到体验统一与性能最优?

第一问:拖拽翻屏,还是滑动翻屏?

1_1      2_1
1                       2

页面随手势拖拽后翻屏                           滑动后(touchend)后翻屏

如上面两个 Gif 图所示,两种方式的差异在于:

  • 拖拽翻屏:页面随手指拖动而移动,手指松开(touchend)后翻页
  • 滑动翻屏:页面不随手指拖动而移动,手指松开(touchend)后翻页

看似差别不大的两种交互,实现复杂度差别巨大,在 Android 中的体验更是不一样。前者需要在每个 touchmove 的时候进行计算与定位,计算量庞大(关注数字变化):

5

而后者只需要在松开手指后再进行计算与翻页,性能大幅提升:

6

而且从第一种方案切换到第二种时,交互上的微妙改变并没有带来直观的影响。所以从性能角度上,滑动翻屏自然是最佳的选择。

第二问:滑屏技术的最佳实现方式是什么?

3 4

控制 wrapper 滑动                                  控制每一屏滑动

如上 Gif 图所示,滑屏可以在 wrapper 上操作,也可以将每一屏作为独立的滑动元素。简单的滑动可能两者并无太大差异,但假如把多样的需求和场景考虑到,可以发现在滑屏上也会细化出很多功能点:

  • 循环滑动
  • 滑动禁用与开启
  • 预加载 / 延时加载
  • 初始化时显示某一页
  • 滚动到某一页、跳过某一页
  • 提供滑动前、滑动中、滑动后的接口
  • 滑动时间、速度、缓动效果自定义
  • 考虑动态增删页数而无差错
  • 考虑页面缩放、横竖屏切换

在上述要求下,前者已显得分身乏术,而后者由于其元素间的自由性,可以满足上述的需求,且效果更佳,虽然实现复杂度会提高。

最关键的是,前者的实现方式在部分安卓上偶尔会出现卡在上一屏与下一屏中间的情况,一开始遇到时做了很多补救都无果,最终才无奈替换了整个滑动方案,采用第二种控制内部元素的方式,可谓血的教训。

QQ截图20151230102553

简单分析下原因,整个页面都通过在 body 上监测 touchmove 时增加 event.preventDefault() 来阻止自然的页面滑动,但唯独安卓有时候在有动画的元素上移动时,body 会捕捉不到 touchmove 事件,页面可以滚动了,便出现上述可以滑动 wrapper 的情况,而方案二控制每一屏滑动,每屏最宽最高就只是屏幕的宽高,也就不会出现页面滑动了。

第三问:首屏需要 Loading 页吗?

需不需要看需求对 H5 的定位,若是类似微信朋友圈广告的这种品牌运营 H5,有大量素材作为支撑的页面,是需要进入时 loading 页的,这一点希望提前跟产品经理达成共识;但假如页面是系列活动中比较重要的入口,需要多次进入,则不要有 loading 页,力求一进入就能直接看到。

是否一次性将所有资源 load 完?  no no no,即使有专门的 loading 页,都请分屏加载,否则这里将会流失大量用户。

那资源的体积跟时间之间应该形成一个怎样的认知呢? 看表(根据 Chrome 开发者工具 Network 换算数据):

QQ截图20160112120030

上述是理想数值,实际上根据腾讯云统计到的 2G/3G 的下载速率,远未达到理想的速度:

QQ截图20151229163254

根据《工信部及三大运营商发布11月用户发展情况》可得知:中国移动用户 2G 用户占 41.4%3G 用户占 31.3%4G 用户占 27.3%。现状远远没有长期处于 WiFi 环境下的我们想象的那么美好,虽然这些用户并非长期使用 2G/3G,但是页面必须确保在 2/3G 环境下有一个顺畅的浏览体验,避免用户流失。建议首屏资源在 300KB 左右(大概加载时间为 2~3s 左右),并设置缓存。

假如页面有比较丰富的动画,需要先加载资源才能被正常播放呢?   要么去掉动画,要么用 CSS 或 JS 来实现动画,必须要做出取舍。

既然是无 loading 的页面,自然对速度有要求,还能提高加载速度吗?    可以,请分屏加载。若希望做到体验无缝,请在前一屏加载后一屏的资源。

第四问:内部滚动怎么办?

内部滚动即某屏内部还有滚动(但实际上系统的滚动跟滑屏的滚动是冲突对立的),如果这一屏不涉及复杂的 DOM,我还是觉得可以使用 iScroll,虽然它在安卓上的性能一直被诟病,但经过非常多安卓机的检验,效果还是在可接收范围内的,但别忘了前提:DOM 不复杂(如活动规则页)。

那是否有更好的解决方案呢?不妨回看之前滑屏的最佳实现方式:

3

可以看到,在每一屏上进行操作,当上一屏或下一屏滑动到当前屏时,之前的那一屏会去掉 translate 属性,回归到最初的状态(被当前屏盖在下面,即 position:absolute; left:0; top:0),这个时候,将当前屏的 position:absolute; height:100% 去掉,使其回归文档流,那么 body 将会被撑开,页面可以被正常滑动,是不是连 iScroll 都省了?

尝试着写了个 Demo:best_pratice

正如你体验到的那样,理想很丰满,现实很骨感,在 PC 上的体验这个Demo是没有问题的(请在 Chrome 下模拟手机滑动),然而因为 iOS 和 Android 中很多浏览器都自带 bounce 回弹效果,而 iOS 和 Android 的大部分浏览器中,页面滚动时是会阻止页面重绘的(JS 的执行也无法立刻生效在页面中),所以Demo 里看到的效果就是回弹后才翻屏。所以目前这个方案页仅限于某些场景使用。

第五问:背景音乐是默认开启或是关闭?

之前在做一个宣传活动 H5 的时候,默认开启过音乐,发现 28w 曝光只有 800 个人主动关闭音乐。所以默认开启还是最优的,在制作音频的时候注意体积最好在 100~200k 范围,并且默认音量不应该太高,收尾渐入渐出,还得注意版权。

然而目前不管是手 Q 或是微信,都存在一个偶现的 bug:在手机中切换页面或者回到主屏幕,H5 的背景音乐依旧在播放,除非杀掉进程。初步猜测为 Webview 未正确得到释放。

第六问:H5 页面需要兼顾 PC 平台吗?

很多 H5 页面都只针对移动设备展示,但如果分享的链接被人在 PC 中打开呢?比如分享到微博或QQ 空间的链接,被正在电脑上浏览的人打开,看到的是一个显示不正常的页面,这样的体验是非常不好的。所以最好的做法就是准备一个 PC 的扫码页面或将内容搬到 PC,打通回路,为 H5 页面引流。

正如之前做过的 QQ 时光机项目:

未标题-1

第七问:动画如何做低版本退化?

移动端对 CSS3、Canvas、SVG 动画的支持已经不错了,目前兼容性较差的系统主要有 Android 2.3,它不支持 animtion-fill-mode 属性,这会导致动画播放完后无法保持在最后状态;不支持 before/after 伪元素的动画;不支持 animation-timing-function: steps,所以也无法玩转图片序列帧;所以可以特别针对这个版本进行差异化处理,通过判断 UA 对其展示静态页面。

然而最佳的退化方式不应该是版本检测,而是能力检测,可以通过 Modernizr 这个组件判断设备具备的能力。

第八问:如何做好适配?

适配的核心就是确保内容在不同的屏幕分辨率下显示正常,经常采用的方式有 REM、Media Query 和 JS+CSS,没有一套永恒不变的适配方案,往往需要多种结合。如果是比较简单的展示类H5,可以参考如下的代码:

QQ截图20160112154929

当然,少不了横竖屏的提示:

QQ截图20160112160154

不过在 iPhone4/4s 这种小屏幕下,也可以尝试取消分屏滑动,直接用浏览器原生的滚动。

第九问:…

我们也许还会遇到如下情况:

  • 分享到各个社交平台(准备分享引导浮层)
  • 使用自定义字体(font spiderfontmin
  • 图片资源自动合并成雪碧图(Compass)

相信对于大部分 UI 开发来说,写出一个安卓下不卡顿,没有兼容性问题的页面是最美好的愿望,有时候甚至可以针对 iOS 跟 Android 专门写一套代码,看似工作量大,其实可以规避掉很多不必要的麻烦。同时也需要跟产品、设计师们在安卓上的体验退化上达成一致,以免页面做出来后带来预期上的落差。

在追求最佳实践的路上,永远少不了层出不穷的问题。不一而足,无法穷举,滑屏只是一种形式,内容才是 H5 的精华所在,切勿舍本逐末。如今可以看到越来越多的创意融入 H5 中(视频、Canvas、SVG 等),前端世界变得越来越丰富多彩,这对开发者来说是机遇也是挑战,你我共勉!