Github 文章存档:Link
在一次 Web 页面开发中需要实现可交互动画(根据滚动高度控制动画进度),对接中使用了 Airbnb 研发开源的 Lottie 方案 (lottie-web)。
Lottie 依赖轻量、对接方便、还原度高,可以作为通用的动效方案,在此记录一次对接信息供参考。
线上应用 ?
字节跳动小程序开放平台首页循环动效 —— SVG + Image
地址:字节跳动小程序开发者平台 – Creating future with excellent developers
协作对接 ✏️
设计同学动效开发
在与设计师同学的合作中,了解到一些便于设计与前端顺利对接的 Tips
开发:动效设计师的常用开发软件(After Effects + 用于导出 Lottie 资源的 BodyMovin 插件)
产物(美术资产)导出:
- 一个 .json 文件,用于描述动画表现(后面会讲到)
- 如果动画本身有图片资源,需要一起导出,导出的图片名称应与 json 中描述的资产一致,便于 Lottie 直接相对引用
- 可能还有 SVG 资源或其嵌在 json 文件中的描述
优化要点:
- 选用 png 素材,减少 jpeg 格式蒙层图片、工具图片
- 导出的 seq_x_x 图片资源可以直接压缩后再使用,保证名称和路径不变即可
- 尽可能使用矢量素材(开发软件中直接绘制的素材),最终可以使用 SVG 进行动画绘制,减少实际上线后的图片资源请求
前端同学动效嵌入
Lottie 接入:
- 具体接入过程参见官网文档,与使用普通工具包无异,常见的有 Vanilla CDN Script 引入和 npm 安装
- 可以使用 Lottie Market 下的免费动画作为 demo,进行占位开发
工程化 – 打包构建:
- 如果打包过程中有资源路径替换(CDN 化、图片哈希等),需要要在引用 json 的代码中替换 json 文件路径,并在 json 文件中替换图片路径
- Lottie 读取 json 中的资源都是相对路径访问,在 assets 数组中每个资源有 u 和 p 两个字段,分别表示中间路径——如 images/,和实际图片名,如 seq_0_0.png,这两个会直接拼接成相对 json 文件的路径,加上 json 文件本身的引用路径进行图片访问
- 总的来说,打包时需要对 json 进行 CDN + 哈希名替换,对 json 内图片名称,即 u 字段进行哈希名替换,依赖 gulp 打包流程或者 Webpack 插件都可以实现
On Lottie ?
讲完基本概念和使用,接下来从一个前端开发的视角,再介绍、解析一下 Lottie 本身。
这部分没有代码,说起来不干,也可能不够干货,但能聊明白基础就好。
Lottie 解决了什么问题
像小程序开平那样的动画板块,在整个平台主站的 web 页面中占据了首屏主要视图,对效果、性能都有较高要求。对于这样的动效需求,直观地看可能会得到两个方向的解决方案:
- 多媒体资源实现(切图 / 视频 / …),要么资源过大、影响加载;要么效果不好;
- 研发绘制(Canvas / SVG / …),开发工作量大、技术能力有限,并且难以维护,难以应对变化;
这两类方案都存在的问题是,设计与研发沟通成本高,实现灵活性差。
面对这样的问题,Lottie 做到的是:
- “无痛”设计。Lottie 工作流支持美术同学在自己熟悉的环境中开发动效,如 AE,加上插件即可将动画导出为研发直接可用的 .json 格式,一个文件表达整个动画,美术资产管理方便高效;
- “无缝”对接。准备好资源和运行环境,一个 JSON(视动画素材形式可能还有对应的图片资源、字体等)即可在页面上动起来,动画效果、进度控制可干预程度高;
- 还不错的性能:
- 支持多种渲染模式(lottie-web 支持 HTML、Canvas、SVG,一般 SVG 最好,可以最大程度矢量化,特性也最多,如果是图片资源,一样会包装成 SVG Image 并进行变换);
- 模式的优劣跟平常可视化基础聊的一样:视画幅大小、元素多寡不同,Canvas 在大画幅下的表现肯定会略逊一筹,SVG 和 HTML 遇到大量元素时缺点也会体现出来。各个模式有不同的能力侧重与偏差;
- 矢量化、原子化,美术开发过程中可以矢量化的素材都能被序列化,图片素材也都与位移、基础形变抽离,最小化数据表示,我个人开发中的一个页面,首屏一个千像素大小的流畅、清晰的动画,全部 Lottie 资源加起来体积 2MB 多一点点,使用和控制都比较方便。
目前 Lottie 已经是一套比较成熟的动效方案,并且,除了 Web,其在各种 Native 开发场景下也有比较不错的表现。
顺便一提之前看到的类似的东西:蚂蚁金服在 SEE Conf 2020 上,由前端大哥烧鹅分享的一套工作流 Oasis,从 3D 动效开发到资源对接同步到前端嵌入,成熟度、对接效率等还没有太多体验,不便评价。但整个平台的设计和愿景非常帅,也算是领域比较尖端的技术。(分享视频地址)
怎么解决的
资产管理
在 Lottie 工作流的第一步,美术同学设计好动效之后,可以通过插件将动画工程导出为 Lottie 协议下的格式,主要是一个表示动画信息的 .json 文件和可能会有的资源素材。
JSON 描述了整个动画的基础信息,如画布尺寸、帧率、起讫帧、资源信息、图层信息等(甚至支持 3D)。资源和图层中,通过层级关系表示了动画中的素材(依赖资源、动画元素)和绘制情况(图层分布、元素表现)。
数据动了
在 Lottie 载入一个动画 JSON 时,除了最基本的参数初始化之外,最重要的就是渲染器选择,前面提到的 HTML、Canvas、SVG 各有不同的 Renderer。
Renderers 首先读取前面提到的整个动画的基础信息,相当于初始化画布、帧配置,并准备好资源。资源全部加载完毕才开始真正的绘制。
Lottie 协议的灵活性和完整性在于其内容是“可枚举”的,动效开发过程中的元素类型,如文本、矢量形状、图片等,都是可被枚举和定义的。针对各种不同 assets,renderer 会调用不同的构造器去创建(如对于图像,Canvas 会 “drawImage”,SVG 会插入 <image> 元素)。
以此为基础,加上帧动画的形式中,每一帧每个元素干了什么(定位、形变、透明度、显隐)都可以通过数据协议精确、低成本地表示或计算(这里说计算,因为有时候需要“补间”,不可能每一帧都列举描述),这样一来,渲染过程就不难理解了。
让动画飞
动画绘制大同小异,推荐读者拓展了解之前分享的相关链接:? 一起学习可视化图表库 AntvF2 及字节小程序适配 —— 4.2 节 「动画」怎么做。
说到动画绘制,则依然离不开 requestAnimationFrame,在每个计算的时间片内读到帧信息,根据元素运动信息进行计算,再调用对应渲染器的绘制方法,按需绘制或者改变元素。
requestAnimationFrame 固定约 16.66ms 跑一次,60FPS,像 20 / 30 FPS 的动画则需要通过计算百分比来实现。即:
依然会每隔大约 16.66ms 跑一次图形计算,每次计算中通过上一次计算和这一次的时间 diff,乘帧速算出“前进”了多少帧(当然帧数也可能是浮点数,像用 AE 处理视频常见的 29.97 帧)。然后根据每个元素的运动状态和缓动函数设置求插值。通俗地说,也就是算出这个在动的元素当前动到什么程度,更新元素属性,按需更新绘制。
对于按需绘制,这块的具体实现了解不多。但可以有大致的推论:HTML、SVG 大部分是通过 CSS 属性(了解下来很多时候是 Opacity + Transform Matrix 一把梭),所以不更新则自动不绘制,依赖很底层的渲染引擎,性能和实现都比较有保障;Canvas 因为重叠重绘问题,有时候计算按需更新还不如直接全体重绘,辅以绘制层面的优化方法。
总结 & 想法
说明白了的话,大概一看没有太多难点和精妙之处,但是如此完全与灵活的系统、完整的多平台 / 多种渲染器兼容、较为完善的工作流,以及还不错的体验,整个设计实现还是比较牛的,技术层面和产品层面都很赞。还得看看代码。
感谢阅读。