CSS 动画 第1级

W3C 工作草案,

更多关于本文档的详细信息
当前版本:
https://www.w3.org/TR/2023/WD-css-animations-1-20230302/
最新发布版本:
https://www.w3.org/TR/css-animations-1/
编辑草案:
https://drafts.csswg.org/css-animations/
历史版本:
历史记录:
https://www.w3.org/standards/history/css-animations-1
测试套件:
http://test.csswg.org/suites/css-animations-1_dev/nightly-unstable/
反馈:
CSS 工作组问题存储库
规范内问题
编辑:
(苹果公司)
L. David Baron (谷歌)
Tab Atkins Jr. (谷歌)
(受邀专家)
前编辑:
David Hyatt (苹果公司)
Chris Marrin (苹果公司)
(Adobe)
建议修改此规范:
GitHub 编辑器
问题列表:
https://github.com/w3c/csswg-drafts/labels/css-animations-1

摘要

本 CSS 模块描述了作者如何使用关键帧随时间为 CSS 属性的值添加动画。可以通过指定动画的持续时间、重复次数和重复行为来控制这些关键帧动画的行为。

CSS 是一种用于描述结构化文档(例如 HTML 和 XML)在屏幕、纸张等上的渲染的语言。

本文件的状态

本节描述了本文档在出版时的状态。当前 W3C 出版物的列表及本技术报告的最新修订版可在 W3C 技术报告索引 中找到。

本文档由 CSS 工作组 作为 工作草案 发布,使用了 推荐路线。 作为工作草案发布并不意味着 W3C 及其成员的认可。

这是一个草案文档,可能会随时更新、替换或被其他文档取代。将本文档作为非正式的工作进展引用是不合适的。

请通过 在 GitHub 上提交问题 (优选方式)提供反馈,在标题中包括规范代码 “css-animations”,格式如下:“[css-animations] …评论摘要…”。 所有问题和评论均被 归档。 另外,反馈也可以发送到 (归档的) 公共邮件列表 www-style@w3.org

本文档受 2021年11月2日 W3C 流程文档 管辖。

本文档由在 W3C 专利政策 下运作的小组编制。W3C 维护了与本小组交付物相关的任何专利披露的公共列表;该页面还包括专利披露的指示。 个人如果知道某项专利,并认为该专利包含 必要声明,则必须根据 W3C 专利政策第 6 节 披露该信息。

1. 引言

本节不具规范性

CSS 过渡 [CSS3-TRANSITIONS] 提供了一种在底层属性更改后插值 CSS 属性值的方法。 这为简单动画提供了便捷的方法,但动画的开始和结束状态由现有属性值控制,并且过渡仅为作者提供了有限的动画进程控制。

该提案引入了定义的动画,作者可以通过一组关键帧指定 CSS 属性随时间的变化。 动画与过渡相似,都是随时间改变 CSS 属性的表现值。 主要区别在于,过渡是在属性值更改时隐式触发,而动画是在应用动画属性时显式执行。 因此,动画需要为正在动画化的属性显式指定值。 这些值使用动画关键帧来指定,下面将描述。

动画的许多方面可以控制,包括动画迭代的次数、是否在开始和结束值之间交替,以及动画是否运行或暂停。 动画还可以延迟其开始时间。

1.1. 值的定义

本规范遵循 CSS 属性定义惯例,源自 [CSS2],并使用 值定义语法,源自 [CSS-VALUES-3]。 本规范未定义的值类型定义在 CSS 值与单位 [CSS-VALUES-3] 中。 与其他 CSS 模块的组合可能会扩展这些值类型的定义。

除了在定义中列出的属性特定值外,本规范定义的所有属性还接受 CSS 通用关键词 作为其属性值。 为了可读性,这些值未在此重复列出。

2. 动画

CSS 动画影响计算的属性值。 这种效果是通过向 CSS 层叠中添加一个指定的值([CSS3CASCADE])来实现的(在 CSS 动画的层级上),该值将为动画的当前状态生成正确的计算值。 如 [CSS3CASCADE] 所定义,动画会覆盖所有普通规则,但会被 !important 规则覆盖。

如果在某个时间点有多个动画为同一属性指定行为,则 animation-name 属性中最后出现的动画将覆盖其他动画。

动画在应用动画之前(即在元素上设置 animation-name 属性时)或在移除之后不会影响计算值。此外,通常动画在动画延迟结束之前或在动画结束之后不会影响计算值,但根据 animation-fill-mode 属性,它可能会影响计算值。

在运行时,动画会计算它所动画化的属性的值。根据 CSS 层叠([CSS3CASCADE]),其他值可能会优先于动画值。

当动画正在应用但尚未结束,或已结束但其 animation-fill-modeforwardsboth 时,用户代理必须将该元素的 will-change 属性([css-will-change-1])视为还包括动画化的所有属性。

动画的开始时间是应用动画的样式和相应的 @keyframes 规则都已解析的时间。 如果为元素指定了动画,但相应的 @keyframes 规则尚不存在,则动画无法启动; 一旦可以解析匹配的 @keyframes 规则,动画将从头开始。 通过动态修改元素样式指定的动画将在此样式解析时启动; 对于伪样式规则(例如 hover),这可能是立即的,或者当脚本引擎将控制权返回给浏览器时(在脚本应用样式的情况下)。 请注意,动态更新关键帧样式规则不会启动或重新启动动画。

如果动画的名称出现在 animation-name 属性的计算值中,并且动画使用有效的 @keyframes 规则,则动画适用于元素。 一旦动画开始,它会持续到结束或 animation-name 被移除。 动画运行期间对动画属性值的更改将应用为动画从开始时就具有这些值的方式。例如,缩短 animation-delay 可能会导致动画前进,甚至立即完成并触发 animationend 事件。 相反,延长 animation-delay 可能会导致动画重新开始并触发 animationstart 事件。

相同的 @keyframes 规则名称可以在 animation-name 中重复。 对 animation-name 的更新通过从后向前迭代新的动画列表来更新现有动画,并且对于每个动画,找到现有动画列表中的最后一个匹配动画。 如果找到匹配项,则使用新动画列表中与其位置对应的动画属性更新现有动画,同时保持其当前播放时间,如上所述。 匹配的动画将从现有动画列表中删除,因此不会匹配两次。 如果未找到匹配项,则创建新动画。 因此,将 animation-name 从 ‘a’ 更新为 ‘a, a’ 将导致现有的 ‘a’ 动画成为列表中的第二个动画,并为列表中的第一个项目创建新动画。

div {
  animation-name: diagonal-slide;
  animation-duration: 5s;
  animation-iteration-count: 10;
}

@keyframes diagonal-slide {

  from {
    left: 0;
    top: 0;
  }

  to {
    left: 100px;
    top: 100px;
  }

}

这将生成一个动画,将元素从 (0, 0) 移动到 (100px, 100px),持续五秒,并重复九次(共十次迭代)。

display 属性设置为 none 将终止应用于该元素及其后代的任何正在运行的动画。 如果元素的 displaynone,将 display 更新为 none 以外的值将启动所有应用于该元素的动画属性以及所有应用于后代的动画, 只要它们的 display 不是 none

虽然作者可以使用动画来创建动态变化的内容,但动态变化的内容可能会导致某些用户发生癫痫发作。有关如何避免可能导致癫痫发作的内容的信息,请参阅准则 2.3:癫痫发作:不要以已知会引发癫痫发作的方式设计内容([WCAG20])。

当渲染媒介不具有交互性时,例如打印时,实施可能会忽略动画。 本规范的未来版本可能会定义如何为这些媒介渲染动画。

3. 关键帧

关键帧用于在动画过程中指定动画属性在不同点的值。 关键帧指定动画一个周期的行为;动画可以迭代零次或多次。

关键帧使用 @keyframes at-rule 指定,定义如下:

@keyframes = @keyframes <keyframes-name> { <rule-list> }

<keyframes-name = <custom-ident> | <string>

<keyframe-block = <keyframe-selector># { <declaration-list> }

<keyframe-selector> = from | to | <percentage [0,100]>

<rule-list> 只能包含 <keyframe-block> 规则。

<declaration-list> 接受除本规范定义的属性之外的任何 CSS 属性,但接受 animation-timing-function 属性,并对其进行特殊解释。 这些属性不与层叠交互(因此在它们上使用 !important 是无效的,会导致属性被忽略)。

@keyframes 块的名称由其前导中的 <custom-ident><string> 指定。 这两种语法在功能上是等效的;名称是标识符或字符串的值。 与 <custom-ident><string> 一样, 名称是完全 区分大小写 的; 只有当它们逐个代码点相等时,两个名称才相等。 <custom-ident> 另外排除了 none 关键字。

例如,以下两个 @keyframes 规则具有相同的名称,因此第一个将被忽略:
@keyframes foo { /* ... */ } 
@keyframes "foo" { /* ... */ } 

另一方面,以下 @keyframes 规则的名称与前两个规则不同:

@keyframes FOO { /* ... */ } 

以下 @keyframes 规则无效,因为它们使用了不允许的 <custom-ident> 值:

@keyframes initial { /* ... */ } 
@keyframes None { /* ... */ } 

然而,这些名称可以使用 <string> 指定,因此以下两者都是有效的:

@keyframes "initial" { /* ... */ } 
@keyframes "None" { /* ... */ } 

<keyframe-selector> 是一个由百分比值或关键字 fromto 组成的逗号分隔列表。 选择器用于指定关键帧表示的动画持续时间的百分比。 关键帧本身由选择器上声明的属性值块指定。 关键字 from 相当于值 0%。 关键字 to 相当于值 100%。 小于 0% 或大于 100% 的值是无效的,并导致它们的 <keyframe-block> 被忽略。

请注意,百分比值必须使用百分比单位说明符。 因此,0 是无效的关键帧选择器。

如果未指定 0%from 关键帧,则用户代理使用正在动画化的属性的计算值构造 0% 关键帧。 如果未指定 100%to 关键帧,则用户代理使用正在动画化的属性的计算值构造 100% 关键帧。

<keyframe-block> 包含属性和值。 本规范定义的属性在这些规则中被忽略,animation-timing-function 除外,其行为将在下面描述。 此外,带有 !important 的属性是无效的并被忽略。

如果定义了多个具有相同名称的 @keyframes 规则,则文档顺序中的最后一个将获胜,所有前面的规则将被忽略。

div {
animation-name: slide-right;
animation-duration: 2s;
}

@keyframes slide-right {

from {
margin-left: 0px;
}

50% {
margin-left: 110px;
opacity: 1;
}

50% {
opacity: 0.9;
}

to {
margin-left: 200px;
}

}

上面的两个 50% 规则也可以合并为一个等效的单一规则,如下所示:

@keyframes slide-right {

from {
margin-left: 0px;
}

50% {
margin-left: 110px;
opacity: 0.9;
}

to {
margin-left: 200px;
}

}

为了确定关键帧集,选择器中的所有值按时间顺序升序排序。 然后 @keyframes 规则中的规则会层叠;关键帧的属性因此可能来自具有相同选择器值的多个 @keyframes 规则。

如果未为关键帧指定某个属性,或该属性无效,则该属性的动画将继续进行,仿佛该关键帧不存在。 从概念上讲,仿佛为每个属性构建了一组关键帧,该属性存在于任何关键帧中,并且为每个属性独立运行动画。

@keyframes wobble {
0% {
left: 100px;
}

40% {
left: 150px;
}

60% {
left: 75px;
}

100% {
left: 100px;
}
}

为名为 "wobble" 的动画指定了四个关键帧。 在动画周期开始时的第一个关键帧中,正在动画化的 left 属性的值为 100px。 到动画持续时间的 40% 时,left 已经动画化到 150px。 在动画持续时间的 60% 时,left 已经动画化回 75px。 在动画周期结束时,left 的值回到了 100px。 下图显示了动画的状态,如果它的持续时间为 10s

关键帧指定的动画状态

本规范需要定义如何从关键帧中确定值, 就像 CSS 过渡的应用 部分为 CSS 过渡所做的那样。

3.1. 关键帧的时间函数

关键帧样式规则还可以声明在动画移动到下一个关键帧时要使用的时间函数。

@keyframes bounce {

  from {
    top: 100px;
    animation-timing-function: ease-out;
  }

  25% {
    top: 50px;
    animation-timing-function: ease-in;
  }

  50% {
    top: 100px;
    animation-timing-function: ease-out;
  }

  75% {
    top: 75px;
    animation-timing-function: ease-in;
  }

  to {
    top: 100px;
  }

}

为名为 "bounce" 的动画指定了五个关键帧。在第一个和第二个关键帧之间(即 0% 和 25% 之间)使用了 ease-out 时间函数。 在第二个和第三个关键帧之间(即 25% 和 50% 之间)使用了 ease-in 时间函数。以此类推。 效果看起来像是一个元素向上移动了 50px,当到达最高点时减速,然后在回落到 100px 时加速。动画的后半部分以类似的方式运行,但元素只向上移动 25px。

to100% 关键帧上指定的时间函数将被忽略。

有关更多信息,请参阅 animation-timing-function 属性。

3.2. animation-name 属性

animation-name 属性定义了适用的动画列表。 每个名称用于选择提供动画属性值的关键帧 at-rule。 如果名称不匹配任何关键帧 at-rule,则没有要动画化的属性,动画将不会执行。 此外,如果动画名称为 none,则不会有任何动画。 这可以用来覆盖来自层叠的任何动画。 如果多个动画尝试修改相同的属性,则最接近名称列表末尾的动画胜出。

名称列表中的每个动画都应具有对应的其他动画属性值。 如果其他动画属性的值列表长度不同,则 animation-name 列表的长度决定了在启动动画时检查的每个列表中的项目数。 列表从第一个值开始匹配:末尾的多余值不使用。 如果其他属性之一没有足够的逗号分隔值来匹配 animation-name 的值数量,则用户代理必须通过重复值列表来计算使用的值,直到有足够的值。 此截断或重复不会影响计算值。

注意:这类似于 background-* 属性的行为,其中 background-image 类似于 animation-name

名称: animation-name
值: [ none | <keyframes-name> ]#
初始值: none
适用于: 所有元素
继承:
百分比: 不适用
计算值: 列表,每个项目要么是区分大小写的 css 标识符,要么是关键字 none
规范顺序: 按语法规则
动画类型: 不可动画化

animation-name 的值具有以下含义:

none
未指定任何关键帧,因此不会有任何动画。 为该动画指定的任何其他动画属性均无效。
<keyframes-name>
动画将使用由 <keyframes-name> 指定的关键帧,如果它们存在的话。 如果没有该名称的 @keyframes 规则,则没有动画。

3.3. animation-duration 属性

animation-duration 属性定义了单个动画周期的持续时间。

名称: animation-duration
值: <time [0s,∞]>#
初始值: 0s
适用于: 所有元素
继承:
百分比: 不适用
计算值: 列表,每个项目是一个持续时间
规范顺序: 按语法
动画类型: 不可动画化
<time [0s,∞]>
<time> 指定了动画完成一个周期所需的时间。 负 <time> 是无效的。

如果 <time>0s,如初始值,动画的关键帧没有效果, 但动画本身仍然瞬时发生。 具体来说,开始和结束事件都会触发; 如果 animation-fill-mode 设置为 backwardsboth, 在 animation-direction 定义的情况下, 动画的第一帧将在 animation-delay 期间显示。 在 animation-delay 之后, 如果 animation-fill-mode 设置为 forwardsboth,最后一帧将显示。 如果 animation-fill-mode 设置为 none,动画将不会有可见效果。

3.4. animation-timing-function 属性

animation-timing-function 属性描述了动画在每对关键帧之间的进展方式。 时间函数在单独的 CSS 缓动函数模块中定义 [css-easing-1]

使用的 输入进度值 是当前关键帧与下一个关键帧之间的经过时间百分比,在包含 animation-direction 属性的效果后计算。

animation-delay 期间,animation-timing-function 不适用。

注意:此定义是必要的,因为否则具有 阶跃缓动函数阶跃位置start 的函数会产生一个向后的填充,等于函数中第一个阶梯的顶部。

输出进度值 用作在当前关键帧和下一个关键帧之间插值属性值时的 p 值。

名称: animation-timing-function
值: <easing-function>#
初始值: ease
适用于: 所有元素
继承:
百分比: 不适用
计算值: 列表,每个项目为已计算的 <easing-function>
规范顺序: 按语法
动画类型: 不可动画化

当在关键帧中指定时,animation-timing-function 定义了动画属性在当前关键帧和下一个关键帧之间的进展顺序,按排序后的关键帧选择器顺序(可能是隐式的 100% 关键帧)。

3.5. animation-iteration-count 属性

animation-iteration-count 属性指定了动画周期播放的次数。 初始值为 1,这意味着动画将从头到尾播放一次。 该属性通常与 animation-directionalternate 结合使用,这将导致动画在交替的周期中以相反的顺序播放。

动画活动期间的时间窗口 (duration x iteration-count) 被称为 活动持续时间

名称: animation-iteration-count
值: <single-animation-iteration-count>#
初始值: 1
适用于: 所有元素
继承:
百分比: 不适用
计算值: 列表,每个项目要么是数字,要么是关键字 infinite
规范顺序: 按语法
动画类型: 不可动画化

<single-animation-iteration-count> = infinite | <number [0,∞]>

infinite
动画将无限次重复。
<number [0,∞]>

动画将重复指定的次数。 如果该数字不是整数, 动画将在最后一个周期的中途结束。 负数是无效的。

0 是有效的,类似于 animation-duration0s 的情况, 导致动画瞬间发生。

如果动画的持续时间为 0s,则它将在任何有效的 animation-iteration-count 值下瞬间发生,包括 infinite

3.6. animation-direction 属性

animation-direction 属性定义动画在某些或所有周期是否应反向播放。 当动画反向播放时,时间函数也会反转。 例如,反向播放时 ease-in 动画将看起来像 ease-out 动画。

名称: animation-direction
值: <single-animation-direction>#
初始值: normal
适用于: 所有元素
继承:
百分比: 不适用
计算值: 列表,每个项目为指定的关键字
规范顺序: 按语法
动画类型: 不可动画化

<single-animation-direction> = normal | reverse | alternate | alternate-reverse

normal
所有动画迭代按指定方式播放。
reverse
所有动画迭代都以相对于指定方式的反向播放。
alternate
奇数次动画周期按正常方向播放,偶数次动画周期按反向播放。
alternate-reverse
奇数次动画周期按反向播放,偶数次动画周期按正常方向播放。

注意: 在确定迭代是偶数还是奇数时, 迭代从 1 开始计数。

3.7. animation-play-state 属性

animation-play-state 属性定义了动画是运行还是暂停。

名称: animation-play-state
值: <single-animation-play-state>#
初始值: running
适用于: 所有元素
继承:
百分比: 不适用
计算值: 列表,每个项目为指定的关键字
规范顺序: 按语法
动画类型: 不可动画化

<single-animation-play-state> = running | paused

running
当该属性设置为 running 时, 动画正常进行。
paused
当该属性设置为 paused 时, 动画暂停。 动画继续应用于元素,并保留暂停前已取得的进度。 当取消暂停(再次设置为 running)时,动画从其停止的位置重新开始, 就像控制动画的“时钟”停止并重新启动一样。

如果在动画的延迟阶段将属性设置为 paused, 延迟时钟也会暂停,并在 animation-play-state 被重新设置为 running 后恢复。

3.8. animation-delay 属性

animation-delay 属性定义动画何时开始。它允许动画在应用后的一段时间后开始执行, 或者在应用前的一段时间之前看起来像已经开始执行。

名称: animation-delay
值: <time>#
初始值: 0s
适用于: 所有元素
继承:
百分比: 不适用
计算值: 列表,每个项目为时长
规范顺序: 按语法
动画类型: 不可动画化
<time>
<time> 定义了动画开始与应用之间的延迟时间 (即动画通过这些属性应用于元素的时刻) 与动画实际开始执行之间的时间。 0s 的延迟(初始值)意味着动画将在应用时立即执行。

负延迟是有效的。 类似于 0s 的延迟,这意味着动画会立即执行, 但会自动按延迟的绝对值推进, 就像动画在指定的时间之前已经开始, 因此它看起来在其活动持续时间的某个位置开始。 如果动画的关键帧有隐含的起始值, 则这些值是从动画开始时获取的, 而不是从过去的某个时间。

3.9. animation-fill-mode 属性

animation-fill-mode 属性定义动画在其执行时间之外应用的值。 默认情况下,动画不会影响在应用时间和开始执行之间(animation-name 属性被设置在元素上) 的属性值,也不会影响动画结束后的属性值(由 animation-durationanimation-iteration-count 属性决定)。 animation-fill-mode 属性可以覆盖此行为。属性的动态更新将根据需要反映在属性值中, 无论是在动画延迟期间还是动画结束之后。

名称: animation-fill-mode
值: <single-animation-fill-mode>#
初始值: none
适用于: 所有元素
继承:
百分比: 不适用
计算值: 列表,每个项目为指定的关键字
规范顺序: 按语法
动画类型: 不可动画化

<single-animation-fill-mode> = none | forwards | backwards | both

none
动画在应用时但未执行时没有效果。
forwards
动画结束后(由 animation-iteration-count 确定),动画将应用动画结束时的属性值。当 animation-iteration-count 是大于零的整数时,应用的值将是最后一次迭代结束时的值。
backwards
在由 animation-delay 定义的期间, 动画将应用定义在开始第一个动画迭代的关键帧中的属性值。
both
同时应用 forwardsbackwards 填充的效果。

3.10. animation 简写属性

animation 简写属性是一个逗号分隔的动画定义列表。列表中的每个项目提供所有子属性的一个值,这些子属性称为动画属性。(参见 animation-name 的定义,了解当这些 属性具有不同长度的列表时会发生什么情况,这种问题在仅使用 animation 简写时不会发生。)

名称: animation
值: <single-animation>#
初始值: 参见各个属性
适用于: 所有元素
继承:
百分比: 不适用
计算值: 参见各个属性
规范顺序: 按语法
动画类型: 不可动画化

<single-animation> = <time> || <easing-function> || <time> || <single-animation-iteration-count> || <single-animation-direction> || <single-animation-fill-mode> || <single-animation-play-state> || [ none | <keyframes-name> ]

注意,每个动画定义中的顺序很重要:在每个 <single-animation> 中第一个可以解析为 <time> 的值分配给 animation-duration, 每个 <single-animation> 中第二个可以解析为 <time> 的值分配给 animation-delay

同样,区分 <keyframes-name> 值与其他关键字时,顺序也很重要。解析时,尚未在简写中找到的适用于 animation-name 之外的属性的关键字必须为这些属性接受,而不是为 animation-name。此外,在序列化时,必须在至少区分可作为其他属性值的 animation-name 的情况下输出其他属性的默认值,且可以在其他情况下输出。

例如,从值 animation: 3s none backwards 解析时(其中 animation-fill-modenoneanimation-namebackwards), 不能被序列化为 animation: 3s backwards (其中 animation-fill-modebackwardsanimation-namenone)。

4. 动画事件

通过 DOM 事件系统,可以获取多个与动画相关的事件。动画的开始和结束,以及每次动画迭代结束时,都会生成 DOM 事件。一个元素可以同时对多个属性进行动画处理。这可以通过包含多个属性的单个 animation-name 值的关键帧,或者通过多个 animation-name 值实现。对于事件的目的,每个 animation-name 表示单个动画。因此,每个 animation-name 值都会生成一个事件,而不一定是每个正在动画的属性。

为定义了有效关键帧规则的任何动画都将运行并生成事件;这包括具有空关键帧规则的动画。

每个生成的事件都会带上动画已运行的时间。这使事件处理程序能够确定循环动画的当前迭代次数或交替动画的当前状态。此时间不包括动画处于 暂停状态的时间。

4.1. AnimationEvent 接口

AnimationEvent 接口提供与动画事件相关的特定上下文信息。

4.1.1. IDL 定义

[Exposed=Window]
    interface AnimationEvent : Event {
      constructor(CSSOMString type, optional AnimationEventInit animationEventInitDict = {});
      readonly attribute CSSOMString animationName;
      readonly attribute double elapsedTime;
      readonly attribute CSSOMString pseudoElement;
    };
    dictionary AnimationEventInit : EventInit {
      CSSOMString animationName = "";
      double elapsedTime = 0.0;
      CSSOMString pseudoElement = "";
    };
    

4.1.2. 属性

animationName, 类型为 CSSOMString,只读
触发事件的动画的 animation-name 属性的值。
elapsedTime, 类型为 double,只读
动画运行的时间(以秒为单位),在此事件触发时,排除动画暂停的时间。此成员的精确计算在每种事件类型中定义。
pseudoElement, 类型为 CSSOMString,只读
动画在其上运行的 CSS 伪元素的名称(以两个冒号开头),如果动画运行在一个元素上(这意味着事件的目标是该元素),则为一个空字符串。

AnimationEvent(type, animationEventInitDict) 是一个 事件构造器

4.2. AnimationEvent 类型

可能发生的动画事件类型有:

animationstart
animationstart 事件在动画开始时发生。 如果有 animation-delay,则此事件会在延迟时间过后触发。

负延迟将导致事件触发时 elapsedTime 等于延迟的绝对值,最大值被限制为动画的活动持续时间,即: min(max(-animation-delay, 0), 活动持续时间); 在这种情况下,无论 animation-play-state 是设置为 running 还是 paused,事件都会触发。

  • 冒泡: 是
  • 可取消: 否
  • 上下文信息: animationName, elapsedTime, pseudoElement
animationend
animationend 事件在动画结束时发生。 在这种情况下,事件的 elapsedTime 成员等于 活动持续时间
  • 冒泡: 是
  • 可取消: 否
  • 上下文信息: animationName, elapsedTime, pseudoElement
animationiteration
animationiteration 事件在每次动画迭代结束时发生,除非动画end事件在同一时间触发。 这意味着对于迭代次数为一或更少的动画,此事件不会发生。

在这种情况下,elapsedTime 成员等于 当前迭代animation-duration 的乘积,其中 当前迭代 是新迭代的从零开始的索引。例如,假设没有负 animation-delay, 在一次迭代完成后,当前迭代 将为一。

  • 冒泡: 是
  • 可取消: 否
  • 上下文信息: animationName, elapsedTime, pseudoElement
animationcancel
animationcancel 事件在动画以不触发 animationend 事件的方式停止时发生,例如 animation-name 的改变移除了动画,或者正在动画的元素或其祖先之一变成了 display:none

此事件的 elapsedTime 成员指示从动画开始到动画被取消时经过的秒数。 这不包括动画暂停的时间。如果动画有负的 animation-delay,则动画的开始时间是 动画实际触发时的绝对值 animation-delay 秒之前的时刻。 另一方面,如果动画有正的 animation-delay 且 事件在动画的延迟期未过期前触发,则 elapsedTime 将为零。

  • 冒泡: 是
  • 可取消: 否
  • 上下文信息: animationName, elapsedTime, pseudoElement

4.3. 元素、Document 对象和 Window 对象上的事件处理程序

以下是必须由所有 事件处理程序(及其对应的 事件处理程序事件类型)支持的HTML 元素,同时作为 事件处理程序内容属性事件处理程序 IDL 属性;同时还必须由所有 DocumentWindow 对象作为 事件处理程序 IDL 属性支持:

事件处理程序 事件处理程序事件类型
onanimationstart animationstart
onanimationiteration animationiteration
onanimationend animationend
onanimationcancel animationcancel

5. DOM 接口

CSS 动画通过一对新接口向 CSSOM 公开,描述了关键帧。

注意:下面定义的接口反映了此规范级别的可互操作 API。未来的级别可能会弃用此 API 的某些部分,并扩展其他部分。

5.1. CSSRule 接口

以下两种规则类型被添加到 CSSRule 接口中。它们提供了对新关键帧规则和关键帧的识别。

5.1.1. IDL 定义

partial interface CSSRule {
    const unsigned short KEYFRAMES_RULE = 7;
    const unsigned short KEYFRAME_RULE = 8;
};

5.2. CSSKeyframeRule 接口

CSSKeyframeRule 接口表示单个关键帧的样式规则。

5.2.1. IDL 定义

[Exposed=Window]
interface CSSKeyframeRule : CSSRule {
  attribute CSSOMString keyText;
  [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
};

5.2.2. 属性

keyText, 类型为 CSSOMString
此属性表示关键帧选择器,作为以逗号分隔的百分比值列表。fromto 关键字分别映射到 0% 和 100%。

如果 keyText 被更新为无效的关键帧选择器,则必须抛出 SyntaxError 异常,并且 keyText 的值必须保持不变。

style, 类型为 CSSStyleDeclaration, 只读
必须为关键帧规则返回 CSSStyleDeclaration 对象,其具有以下属性:
只读标志
未设置。
声明
规则中声明的声明,以指定的顺序
父 CSS 规则
上下文对象(即此 CSSKeyframeRule)。
所有者节点
为空。

5.3. CSSKeyframesRule 接口

CSSKeyframesRule 接口表示单个动画的一组完整关键帧。

5.3.1. IDL 定义

[Exposed=Window]
interface CSSKeyframesRule : CSSRule {
           attribute CSSOMString name;
  readonly attribute CSSRuleList cssRules;
  readonly attribute unsigned long length;

  getter CSSKeyframeRule (unsigned long index);
  undefined        appendRule(CSSOMString rule);
  undefined        deleteRule(CSSOMString select);
  CSSKeyframeRule? findRule(CSSOMString select);
};

5.3.2. 属性

name, 类型为 CSSOMString
此属性是关键帧的名称,由 animation-name 属性使用。
cssRules, 类型为 CSSRuleList, 只读
此属性提供访问列表中关键帧的功能。
length, 类型为 unsigned long, 只读
此属性表示列表中关键帧的数量。

5.3.3. 索引属性 getter

索引属性 getter indexed property getter 返回位置上的 CSSKeyframeRule 列表中的关键帧。

参数:

index 类型为 unsigned long
要返回的规则的从零开始的索引。

返回值:

CSSKeyframeRule
找到的规则,或者 undefined 如果在指定索引处没有规则。

无异常

5.3.4. appendRule 方法

appendRule 方法 将传入的 CSSKeyframeRule 添加到关键帧规则的末尾。

参数:

rule 类型为 CSSOMString
要追加的规则,其语法与 @keyframes 规则中的一个条目相同。即使其键已经存在,也会始终追加有效规则。

无返回值

无异常

5.3.5. deleteRule 方法

deleteRule 方法 删除与指定关键帧选择器匹配的最后声明的 CSSKeyframeRule 。如果没有匹配的规则,则该方法不执行任何操作。

参数:

select 类型为 CSSOMString
要删除的规则的关键帧选择器:0% 到 100% 之间的百分比值的逗号分隔列表,或解析为 0% 和 100% 的 fromto 关键字。

指定关键帧选择器中的值的数量和顺序必须与目标关键帧规则的值匹配。匹配不区分列表中值周围的空格。

无返回值

无异常

5.3.6. findRule 方法

findRule 返回与指定关键帧选择器匹配的最后声明的 CSSKeyframeRule。 如果没有匹配的规则,则该方法不执行任何操作。

参数:

select 类型为 CSSOMString
要查找的规则的关键帧选择器:0% 到 100% 之间的百分比值的逗号分隔列表,或解析为 0% 和 100% 的 fromto 关键字。

指定关键帧选择器中的值的数量和顺序必须与目标关键帧规则的值匹配。匹配不区分列表中值周围的空格。

返回值:

CSSKeyframeRule
找到的规则。

无异常

例如,给定以下动画:
@keyframes colorful-diagonal-slide {

  from {
    left: 0;
    top: 0;
  }

  10% {
    background-color: blue;
  }

  10% {
    background-color: green;
  }

  25%, 75% {
    background-color: red;
  }

  100% {
    left: 100px;
    top: 100px;
  }

}

假设变量 anim 持有此动画的 CSSKeyframesRule 对象的引用,那么:

anim.deleteRule('10%');
var tenPercent = anim.findRule('10%');

将首先删除最后一个 10% 规则,即绿色背景颜色规则;然后找到剩下的蓝色背景规则并将其返回到 tenPercent 中。

以下操作:

var red = anim.findRule('75%');

将把 red 设置为 null。必须使用红色背景颜色规则的完整选择器:

var red = anim.findRule('25%,75%');

由于 from 映射为 0%,而 to 映射为 100%,我们可以使用任一值查找这些规则:

var from = anim.findRule('0%'); // 返回 from { left: 0; top: 0; } 规则
var to = anim.findRule('to');   // 返回 100% { left: 100px; top: 100px; } 规则

5.4. 扩展 GlobalEventHandlers 接口混合

本规范扩展了 HTML 中的 GlobalEventHandlers 接口混合, 为 事件处理程序 IDL 属性添加了用于 动画事件的扩展,如在 § 4.3 元素、Document 对象和 Window 对象上的事件处理程序中定义。

5.4.1. IDL 定义

partial interface mixin GlobalEventHandlers {
  attribute EventHandler onanimationstart;
  attribute EventHandler onanimationiteration;
  attribute EventHandler onanimationend;
  attribute EventHandler onanimationcancel;
};

6. 隐私考虑

该规范未报告任何隐私问题。

7. 安全考虑

该规范未报告任何安全问题。

8. 变更

8.1. 2018年10月11日工作草案以来的变更

以下是实质性变更:

9. 致谢

特别感谢以下人员的反馈: Tab Atkins, Brian Birtles, Shane Stephens, Carine Bournez, Christian Budde, Anne van Kesteren, Øyvind Stenhaug, Estelle Weyl, 以及 www-style 社区的所有成员。

10. 其他未解决问题

需要 明确关键帧的交互方式

11. 等待编辑的工作组决议

此部分为信息性且临时性内容。

编辑者目前未及时编辑此规范。以下工作组决议仍需要进行编辑:

合规性

文档约定

合规性要求通过描述性声明和 RFC 2119 术语的组合进行表达。关键字“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL”在本文件的规范性部分中应按照 RFC 2119 的描述进行解释。为了可读性,这些词在本规范中未完全大写。

除明确标注为非规范性、示例和注释的部分外,本规范的所有文本均为规范性内容。[RFC2119]

本规范中的示例以“例如”开头或通过 class="example" 与规范性文本区分开来,例如:

这是一个信息性示例。

信息性注释以“注释”开头,并通过 class="note" 与规范性文本区分开来,例如:

注释:这是一个信息性注释。

建议性条款为规范性部分,特别强调的内容通过 <strong class="advisement"> 样式进行标注,例如: 用户代理必须提供可访问的替代方案。

合规性类别

本规范的合规性分为三个类别:

样式表
CSS 样式表
渲染器
用户代理(UA),用于解释样式表的语义并渲染使用样式表的文档。
创作工具
用户代理(UA),用于编写样式表。

如果样式表的所有语句都符合本模块中定义的通用 CSS 语法和各功能定义的语法,则该样式表符合本规范。

如果渲染器除了按相关规范定义解释样式表外,还正确解析并支持本规范定义的所有功能并相应地渲染文档,则该渲染器符合本规范。然而,由于设备限制导致用户代理无法正确渲染文档并不意味着该用户代理不符合规范。(例如,用户代理不必在单色显示器上渲染颜色。)

如果创作工具编写的样式表在语法上符合通用 CSS 语法和本模块中每个功能的语法,并符合本模块描述的样式表的所有其他合规性要求,则该创作工具符合本规范。

部分实现

为了让作者能够利用向前兼容的解析规则分配后备值,CSS 渲染器必须将无法支持的 at-rule、属性、属性值、关键字和其他语法结构视为无效,并 适当忽略。尤其是,用户代理不得在单个多值属性声明中选择性地忽略不支持的值并采用支持的值:如果任何值被认为无效(如不支持的值必须那样),则 CSS 要求整个声明被忽略。

不稳定和专有功能的实现

为了避免与未来稳定的 CSS 功能发生冲突,CSS 工作组建议遵循最佳实践,以实现不稳定的功能和 专有扩展

非实验性实现

一旦规范达到候选推荐阶段,便可以进行非实验性实现,实施者应发布任何符合 CR 级别功能的未加前缀的实现,前提是他们能够证明这些功能已按规范正确实现。

为了在各实现之间建立并保持 CSS 的互操作性,CSS 工作组要求非实验性 CSS 渲染器在发布任何 CSS 功能的未加前缀实现之前,向 W3C 提交实现报告(如有必要,还应提交实现报告中使用的测试用例)。提交给 W3C 的测试用例将由 CSS 工作组审查和更正。

有关提交测试用例和实现报告的更多信息,请访问 CSS 工作组网站:https://www.w3.org/Style/CSS/Test/。 如有问题,请联系 public-css-testsuite@w3.org 邮件列表。

索引

本规范定义的术语

其他规范中定义的术语

参考文献

规范性引用

[CSS-DISPLAY-3]
Tab Atkins Jr.; Elika Etemad. CSS Display 模块级别 3. 2022年11月18日. CR. URL: https://www.w3.org/TR/css-display-3/
[CSS-EASING-1]
Brian Birtles; Dean Jackson; Matt Rakow. CSS 缓动函数级别 1. 2023年2月13日. CR. URL: https://www.w3.org/TR/css-easing-1/
[CSS-SHAPES-2]
CSS 形状模块级别 2 URL: https://drafts.csswg.org/css-shapes-2/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS 语法模块级别 3. 2021年12月24日. CR. URL: https://www.w3.org/TR/css-syntax-3/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS 值与单位模块级别 3. 2022年12月1日. CR. URL: https://www.w3.org/TR/css-values-3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS 值与单位模块级别 4. 2022年10月19日. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS-WILL-CHANGE-1]
Tab Atkins Jr.. CSS Will Change 模块级别 1. 2022年5月5日. CR. URL: https://www.w3.org/TR/css-will-change-1/
[CSS2]
Bert Bos; et al. 级联样式表级别 2 修订版 (CSS 2.1) 规范. 2011年6月7日. REC. URL: https://www.w3.org/TR/CSS21/
[CSS22]
Bert Bos. 级联样式表级别 2 修订版 2 (CSS 2.2) 规范. 2016年4月12日. WD. URL: https://www.w3.org/TR/CSS22/
[CSS3CASCADE]
Elika Etemad; Tab Atkins Jr.. CSS 级联与继承级别 3. 2021年2月11日. REC. URL: https://www.w3.org/TR/css-cascade-3/
[CSSOM-1]
Daniel Glazman; Emilio Cobos Álvarez. CSS 对象模型 (CSSOM). 2021年8月26日. WD. URL: https://www.w3.org/TR/cssom-1/
[DOM]
Anne van Kesteren. DOM 标准. 现行标准. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML 标准. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[RFC2119]
S. Bradner. 在 RFC 中指示需求级别的关键字. 1997年3月. 最佳现行实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WCAG20]
Ben Caldwell; et al. 网页内容无障碍指南 (WCAG) 2.0. 2008年12月11日. REC. URL: https://www.w3.org/TR/WCAG20/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 现行标准. URL: https://webidl.spec.whatwg.org/

参考性引用

[CSS-BACKGROUNDS-3]
Bert Bos; Elika Etemad; Brad Kemper. CSS 背景与边框模块级别 3. 2023年2月14日. CR. URL: https://www.w3.org/TR/css-backgrounds-3/
[CSS-POSITION-3]
Elika Etemad; Tab Atkins Jr.. CSS 定位布局模块级别 3. 2023年2月17日. WD. URL: https://www.w3.org/TR/css-position-3/
[CSS3-TRANSITIONS]
David Baron; et al. CSS 过渡. 2018年10月11日. WD. URL: https://www.w3.org/TR/css-transitions-1/

属性索引

名称 初始值 适用于 继承 百分比 动画类型 规范顺序 计算值
animation <single-animation># 查看各个属性 所有元素 不适用 不可动画 按照语法 查看各个属性
animation-delay <time># 0s 所有元素 不适用 不可动画 按照语法 列表,每项为持续时间
animation-direction <single-animation-direction># normal 所有元素 不适用 不可动画 按照语法 列表,每项为指定的关键字
animation-duration <time [0s,∞]># 0s 所有元素 不适用 不可动画 按照语法 列表,每项为持续时间
animation-fill-mode <single-animation-fill-mode># none 所有元素 不适用 不可动画 按照语法 列表,每项为指定的关键字
animation-iteration-count <single-animation-iteration-count># 1 所有元素 不适用 不可动画 按照语法 列表,每项为数字或关键词 infinite
animation-name [ none | <keyframes-name> ]# none 所有元素 不适用 不可动画 按照语法 列表,每项为大小写敏感的 CSS 标识符或关键词 none
animation-play-state <single-animation-play-state># running 所有元素 不适用 不可动画 按照语法 列表,每项为指定的关键字
animation-timing-function <easing-function># ease 所有元素 不适用 不可动画 按照语法 列表,每项为计算的 <easing-function>

IDL 索引

[Exposed=Window]
interface AnimationEvent : Event {
  constructor(CSSOMString type, optional AnimationEventInit animationEventInitDict = {});
  readonly attribute CSSOMString animationName;
  readonly attribute double elapsedTime;
  readonly attribute CSSOMString pseudoElement;
};
dictionary AnimationEventInit : EventInit {
  CSSOMString animationName = "";
  double elapsedTime = 0.0;
  CSSOMString pseudoElement = "";
};

partial interface CSSRule {
    const unsigned short KEYFRAMES_RULE = 7;
    const unsigned short KEYFRAME_RULE = 8;
};

[Exposed=Window]
interface CSSKeyframeRule : CSSRule {
  attribute CSSOMString keyText;
  [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
};

[Exposed=Window]
interface CSSKeyframesRule : CSSRule {
           attribute CSSOMString name;
  readonly attribute CSSRuleList cssRules;
  readonly attribute unsigned long length;

  getter CSSKeyframeRule (unsigned long index);
  undefined        appendRule(CSSOMString rule);
  undefined        deleteRule(CSSOMString select);
  CSSKeyframeRule? findRule(CSSOMString select);
};

partial interface mixin GlobalEventHandlers {
  attribute EventHandler onanimationstart;
  attribute EventHandler onanimationiteration;
  attribute EventHandler onanimationend;
  attribute EventHandler onanimationcancel;
};

问题索引

本规范需要定义如何从关键帧中确定值, 就像 过渡应用 部分对 CSS 过渡所做的那样。
需要 指定关键帧如何交互