Web编程技术营地
研究、演示、创新

Web Animations

撰写时间:2026-03-02

修订时间:2026-03-17

概述

Web Animations是 Web 平台呈现变化的时序同步规范。其他相关规范应基于本规范、通过声明的方式来展现这些特性。它同时定义了一组APIs,可通过脚本对动画进行精细的控制。

动画的本质是,随着时间的变化,某个对象的特定属性值不断发生变化。例如,有个div元素,在第0秒时,其width属性值为0px,在第2秒时,其该属性值为10px

上述首尾关键帧的属性值是确定的,但为了产生平滑的动画效果,系统需要根据最适合的帧率,在2秒的时间之间自动插入一系列的插值。例如,在第0.5秒,width值应为2.5px,在第1秒,width值应为5px,如此等等。

Web Animations的核心义务,是需在不同的时间点,自动计算特定属性值。因此,Web Animations采用了以下的体系结构:

web-animations-model
Web Animations Model Overview

两大模块分别为Timing modelAnimation model,其中,Animation model将根据Timing model的输出值,自动计算出相应的属性值。

SafariChrome的最新版本均支持Web Animations Module Level 2

CSS Animations 的本质

CSS Animations 与 Web Animations 的关系

本站的CSS Animations详细介绍了CSS Animations,而其本质就是Web Animations。下面代码说明了此点。

使用CSS Animations为一个div元素设置了一个背景颜色变化的动画,然后调用该元素的getAnimations方法,返回只有一个元素的数组,该元素类型为CSSAnimation,继承于Animation。而Animation正是Web Animations的核心对象。

因此,CSS Animations的本质就是Web Animations

深入动画细节

上面代码声明了一段动画,动画时长为9秒,设置了3个关键帧(故每帧动画时长3秒),背景颜色依序从红、绿、蓝变化。

我们在第0秒时将背景设置为红色,在第3秒开始时将背景颜色为绿色,在第6秒开始时将背景颜色为绿色。这些手工设置的帧,称为关键帧 (keyframe)。而从动画效果来看,除了我们显式地设置的3个关键帧之外,系统还帮我们设置了在其他帧时的背景颜色,以实现平滑的动画过滤效果。这些由系统自动设置的帧,称为关键帧插值 (keyframe interpolation)。

因此,div元素在9秒之内,被自动设置了较多的背景颜色。

我们能否获知,在特定的时间点,div元素的背景颜色是什么?

仅通过CSS Animations技术肯定不行,因为它只是通过声明的方式定义了一组关键帧,系统据此渲染为动画,然后任务就完成了。我们无从得知具体内幕细节。

当我们声明了一组动画关键帧后,在各个不同的时间点,div背景颜色虽总是处于不断变化的状态,但在特定时间点,其背景颜色的状态是确定的,这些状态必定存储于某个地方。Web Animations中的Animation对象正好充当这个存储池。它记录了元素在时间轴 (timeline) 上的各个时间点时的不同状态。

明白上述这些基本的动画术语,有助于我们了解、掌握Web Animations的相关技术。

初识Animation对象

Animation对象的属性及方法

下面分类打印出CSSAnimation的属性及其方法。

可以看出,CSSAnimation继承于Animation。与原型相比,CSSAnimation只多出了一个animationName的属性,因此上面分类打印的效果可视为打印Animation的属性及方法。

动画就绪与结束时的回调

在动画准备就绪时,我们可以调用Animationready方法,返回一个注入了Animation实例的Promise对象。

所注入的animObjanimation是同一对象。上面代码,在动画就绪时,我们调用animObjpause方法以暂停动画播放,并打印其playState以查看其当前播放状态。

pause方法可以不必放在ready的回调函数中进行调用。默认情况下,通过CSS Animations所声明的动画,在准备就绪时会调用其play方法以自动播放。如果希望取消这种自动播放的功能,可直接调用其pause方法以暂停播放。

同理,在动画播放完毕时,我们可以调用Animationfinished方法,返回一个注入了同一Animation实例的Promise对象。

与时间戳相关的属性

timeline

Animationtimeline属性,其类型为DocumentTimeline,原型为AnimationTimeline,用于同步时间值。

默认值被设置为:

因此,这两个timeline属性值都指向同一对象。

当页面加载时,documenttimeline属性值所向的DocumentTimeline对象将被自动创建,其currentTime属性为自页面加载以来所流逝的毫秒值。

startTime

AnimationstartTime属性表示动画开始的时间戳。

startTime属性值受ready属性值的影响。即使显式地调用play方法(默认行为),startTime的值仍为null。只当动画准备就绪时,startTime的值才被设置为时间轴线上当前时间值。

startTime属性值同时受动画是否已经开始播放的影响。

当一开始时,立即调用pause方法以暂停播放,此时,即使动画已经准备就绪,startTime的值仍为null值。只有当开始播放时,startTime才被赋值。

有时会不小心掉入陷阱:

我们已经依序设置了ready就绪的代码,以及开始播放,但为何开始播放后,startTime的值仍为null

因为ready所返回的Promise中的代码在主线程中将延后执行。最简便的解决方案是:

在主线程中等待动画就绪,再使用startTime属性值。

currentTime

AnimationcurrentTime属性表示自动画开始以来的时间偏移值。

一开始,currentTime的初始值为0,即使动画还未就绪、还未开始播放。

由于动画默认一开始就自动运行,因此若将上面的animation.pause();语句屏蔽掉,则该值不为0

动画开始播放后,存在以下的等量关系:

可通过设置currentTime的值,将动画时间戳的偏移值调节到指定的位置,然后,直接读取元素在该时间戳的动画样式值。

动画时长为3秒,先暂停动画播放,然后来到动画总时长的一半的位置,查看元素在该时间点位置上的CSS样式值。

这种向currentTime直接赋值的方式,将导致系统自动同步所有的内部状态后,再返回结果。

若将上面的animation.pause();语句屏蔽,则将从当前位置开始播放动画。

effect属性

Animation有一个effect属性,用以计算并存储不同关键帧的效果值。

属性分类

本节中先从总体上查看effect对象有哪些属性。

getKeyframes

getKeyframes方法返回用户所显式声明的各个关键帧。

composite
属性值是否需要叠加。
可选值为:
  • replace
  • add
  • accumulate
此为单个关键帧的效果组合方式。如果没有为单个关键帧设置组合方式,则组合方式取自effectcomposite属性值。
easing
动画是否需要缓进缓出效果。不同的动画效果将影响到在不同时间的属性值的计算。
offset
当前关键帧在整个动画中的偏移值。值域为[0, 1],或者null

此外,各个关键帧对象都存储了需要动画的对象属性值,如上面的backgroundColor, width

因此,各个关键键对象是动态计算动画值的存储池。对于关键帧插值,均会自动创建此对象来计算并存储它们在不同的时间点上的值。

获取时间信息

getTiming

getTiming方法返回一个EffectTiming对象,打包了用户所声明的与时间相关的属性。

EffectTiming的类型为:

getComputedTiming

getComputedTiming方法返回一个ComputedEffectTiming对象,该对象继承自EffectTiming,用以存储特定时间戳下需计算的与时间有关的属性值。

ComputedEffectTiming的类型为:

下面暂停动画,并查看动画开始2秒时的ComputedEffectTiming的值:

duration表示动画每次持续时间为3000毫秒,iterations表示需播放2次。activeDuration表示动画总持续时间,其值公式为:

iterationStart表示播放次数的基始值,值为0,用以显式表示从0开始计算播放计数,类似于数组元素索引值基于0开始的计算方式。currentIteration表示当前播放次数,从iterationStart开始计算。当我们上面将时间戳设置为2000毫秒时,属于第1次播放,因此currentIteration的值为0

当我们上面通过代码:

引擎在后台将自动创建一个KeyframeEffect对象,并与Animation关联,用以存储特定时间点下的关键帧状态。此时,localTime的值即为animation.currentTime的值。

endTime表示从动画开始以来,到动画停止的总时长。

progress表示当前播放进度,即所指定时间戳占每次播放所需花费时间的百分比进度。

我们在上面指定当前时间戳为2000毫秒,而每次需持续3000毫秒,则progress的值为:

若将当前时间戳指定为4000毫秒,则属于第2次播放,且由于第2次播放时间开始于3000毫秒,则在第2次播放中,当前时间戳的偏移值为4000 - 3000 = 1000,则progress的值将变为:

Animation还有一个overallProgress属性,是当前时间戳占动画持续总时长的总进度。当前时间戳为4000毫秒时,动画持续总时长为6000毫秒,则overallProgress的值将为:

如下所示;

Composition

数值的结合

在不同的时间点,当需要根据两个CSS属性值生成一个属性值时,称为数值的结合 (combining values)。这两个属性值都须为已计算的值 (computed values)。

f(Va, Vb) => Vresult

存在以下3种结合方式:

interpolation
插值。
VaVb两值之间生成插值。
在坐标系的X轴上取两点p0(0, 0)p1(1, 0)p0对应于数值Vap1对应于数值Vb,则在p0p1范围内的任意一个位置p,均可生成相对应的数值。
对于计时函数 (timing functions),范围值域不限定于[0, 1],可为[−∞, ∞]
addition
求和。
根据VaVb,返回这两个数值的和Vresult
accumulation
累积。
对于VaVb,将Vb视为Va的偏移值,计算出Vb的实际数值Vresult,返回该数值。

对于动画中诸如numberslength的大部分数值来讲,accumulationaddition意义相同。但对于列表,它们的含义不一样。例如对于列表中的两个数值blur(2)blur(3),相加的结果为blur(2) blur(3),而累积的结果为blur(5)

插值

首尾帧只有一种属性

首尾帧有两种动画属性

中间所生成的每一个插值帧,均对两种属性分别独立计算插值。

矩阵的插值计算

当需要为矩阵计算插值时,前后两个矩阵都均先拆分 (decomposed) 为相应的平移、旋转、缩放及扭曲等4个成分。每个成分均单独地进行插值,最后再将这4个成分重新构成为一个矩阵。

参考资源

  1. CSS Transforms Level 1: Interpolation of Matrices

综合应用

记住动画状态

参考资源

Web Animations

  1. Web Animations Module Level 1
  2. Web Animations Module Level 2
  3. Additive Animation with the Web Animations API

CSS Animations

  1. CSS Animations Level 1
  2. CSS Animations Level 2

CSS Transforms

  1. CSS Transforms Module Level 1
  2. CSS Transforms Module Level 2

CSS Values

  1. Combining Values: Interpolation, Addition, and Accumulation

CSS Cascading and Inheritance

  1. Computed Values