本文做者:IMWeb IMWeb团队 原文出处:IMWeb社区 未经赞成,禁止转载html
在企鹅辅导品牌页中,咱们须要实现一个动画以下:前端
页面滚动到动画区域,播放动画, 对应动画部分以下:react
帧动画当前的实现有如下几种方式:ios
GIF 动画git
你们比较熟悉的图片格式github
lottieweb
Airbnb 开源项目,经过解析 AE 动画为 json 数据,支持跨平台的动画效果解决方案;lottie 在辅导中已经有实际应用,使用过的同窗都表示对其实现效果和开发速度表示称赞和推荐,若是你还不了解 lottie, 推荐 lottie 系列学习文章,请戳我ajax
APNG (Animated Portable Network Graphics)chrome
基于 PNG 格式扩展的一种动画格式,增长了对动画图像的支持,其诞生是为了替代老旧的 GIF 格式,但部分浏览器不支持,须要考虑兼容;json
HTML video 元素
GIF 动画适用于处理色彩简单、动效简单的动画,如 logo 、 icon 图这样的小图动画,在上面须要实现的动画中明显细节比较多,区域也比较大,考虑到质量 GIF 排除在外
在使用哪一种方式实现该动画上,结合同事 @ajaxchen 的调研结论:
能够看到实现仍是存在着差别,颜色、数字倾斜度、虚线的透视都没有达到预期,因而放弃lottie 的使用,但这并不否认 lottie 在实现其它动画的优秀效果
APNG
在对设计师给到的分段的动画帧图片压缩以后,其实现结果 apng 大小高达 29M,webp 格式 17M, 如此庞大的体积,且实现清晰度达不到预期,也只能放弃该方式;因为 APNG 在一些浏览器上不支持,在实现时需引入 apng-canvas 将 apng 转化为 canvas;
createJS
在我将 ISUX 上的文章《你离高效制做动画只差一篇文章的距离》发送给咱们的设计小哥
以后,他如此回复我
HTML video
在上面尝试无果以后,个人同事@zzbozheng 向我展现了一个 lol 的页面,神奇,竟然是用video来实现!我怎么就没想到!
查看 video 标签的兼容性,不管是咱们品牌页的 PC 版仍是移动 web 端,兼容性均可以知足咱们的需求
设计小哥哥给到的动画 MP4 视频大小是 350k, 350k对比几十兆简直就是轻量,查了一番 video 的自动播放实现,有一些坑,跟设计师小哥哥也沟通了一番综合考虑以后毅然踩上了 video 的坑
video 标签有对应的事件方法, 可查阅文档
下面是在移动端 web 使用 video 过程当中的采坑总结:
video 在 safari 和桌面端 chrome 中可能没法自动播放
这里的自动播放,不管是 video 标签的 autoplay 属性仍是经过 js 自动调用 video 的 play 方法都是自动播放
桌面端 chrome 自动播放主要受制于 autoplay policy ,遵循对应的策略则能够自动播放,这主要考量于用户的体验;由于使用muted(静音)属性能够容许自动播放, 咱们的动画原本就是没有声音的,因此在 video 标签中加上 muted 属性
<video muted />
复制代码
隐藏视频控制条
在 video 标签中,只要不加 controls 属性,通常是不会显示控制条的,这样就看不出来是一个视频了,固然有些安卓机器的浏览器的确处于一种失控状态,后面会提到 ○| ̄|_
IOS 视频自动全屏播放
查阅资料,video 标签添加两个属性便可小屏播放
<video muted playsInline webkit-playsinline="true" />
复制代码
微信不容许自动播放视频,必须经过用户交互才能播放
开始的时候就有过来人的同事提醒过要我注意下微信的视屏自动播放,通过别人的反馈,其实不止是微信不容许,有些机器浏览器也是不容许,这个时候该怎么办?结合 touch 事件一块儿实现。视频播放是监听 scroll 事件,等到可视范围内调用 video.play() 自动播放,既然有些浏览器须要用户交互,那能够选择 touch 事件,当用户 touch 到这块展现播放区域,触发 touch 事件调用 play, 这里咱们的动画区域足够大,不担忧用户 touch 不到。这里使用变量来表示视频是否已经播放,若是已经播放就再也不执行 touch 事件,避免频繁调用 play
有些安卓浏览器没法自动播放,touch 事件也没法触发播放
video 标签的 play 方法返回一个 promise,可经过 promise 来检测到 video 是否可自动播放
video.play()
.then(() => {
// play success
})
.catch( err => {
// auto play fail
})
复制代码
当 catch 到 error 时,只能启用兼容方案,设计小哥哥给了我几张帧图片,让我渐隐渐现实现图片播放。
无奈之下, 针对安卓的微信端,视频所有启用兼容模式(几张图片渐隐渐现)
我:"设计小哥哥,这我无能为力
设计: "找出全部对应的机型和浏览器,对这些不支持的浏览器使用兼容模式播放动画
我:"这全部的机型实在难以控制和所有覆盖到...
设计: "那就先对全部的安卓都使用兼容模式吧,后面对此优化
因而就这样干掉了全部的安卓 video
复制代码
mtt-playsinline=”true“
复制代码
至此附上实现的部分代码块,项目使用 react 技术栈
<video
muted
src="***"
preload="auto"
playsInline
webkit-playsinline="true"
mtt-playsinline="true"
loop
ref={this.videoRef}
/>
复制代码
playVideo = () => {
const { isVideoCanAutoPlay, isPlayedVideo } = this.state;
// 播放视频
const videoDom = this.videoRef.current;
if (videoDom && !isPlayedVideo && isVideoCanAutoPlay) {
const playPromise = videoDom.play();
if (playPromise) {
playPromise
.then(() => {
this.setState({
isPlayedVideo: true,
});
})
.catch((err) => {
badjs.info(`[品牌页][AI VIDEO 动画]: 自动播放出错 ${err}`);
++this.catchVideoErrorCount;
// 经过点击和scroll后都没法播放视屏,使用兼容性方案
if (this.catchVideoErrorCount >= 2) {
this.setState({
isVideoCanAutoPlay: false,
});
}
});
}
}
};
复制代码
最后总结:
移动端 web 对于 video 自动播放的兼容性是在太差,尤为安卓,一些浏览器对 video 标签进行拦截,并以本身的方式实现,或是悬浮置顶播放,或是两个视屏播放冲突,或是控制条没法隐藏,或是播放默认全屏,若是用其它方式能够实现动画尽可能仍是用其它方式
对于 video 的自动播放,考虑一些浏览器限制必须经过用户交互才能使用,若是视屏是在第一屏则有点难度,仍是须要用户经过点击才能播放,若是不是第一屏则可经过 touch 事件来触发,毕竟用户下拉滚动仍是会触发 touch 事件
video 的 play 方法返回的 promise 存在华为荣耀8 微信里返回 play 成功,可是却没有播放视频
参考文档和网站:
感谢在这次采坑过程当中给予帮助的同事~