Menu

CSS 动画:@keyframes、属性与示例

CSS 动画让元素按照你在 @keyframes 中定义的步骤变化,自动播放,想重复几次都可以。学习 @keyframes 语法、全部八个 animation 属性、fill-mode 和 direction、加载动画、暂停动画,以及如何尊重“减少动态效果”设置。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

一个例子看懂 CSS 动画

动画由两部分组成:描述步骤的 @keyframes,以及把这些步骤连同时长应用到元素上的 animation 属性。下面这张卡片会在页面加载时滑入并淡入:

修改代码(或者把时长改成 2s),预览就会重新加载,你可以再看一次卡片进场的效果。@media (prefers-reduced-motion: reduce) 代码块只对系统设置了减少动态效果的读者生效,把关键帧替换为单纯的淡入。

@keyframes 语法

@keyframes pulse {
  0%   { transform: scale(1); }
  50%  { transform: scale(1.08); }
  100% { transform: scale(1); }
}
  • from 等同于 0%,to 等同于 100%。
  • 百分比步骤想加多少就加多少。样式相同的步骤可以写在同一行:0%, 100% { ... }。
  • 如果某个属性在第一个或最后一个关键帧中没有出现,它会从元素自身的值开始动画,或者以元素自身的值结束。
  • 名字(pulse)就是传给 animation-name 的值。它区分大小写,而且不能是 none 这样的关键字。

animation 属性

属性设置什么默认值
animation-name运行哪一个 @keyframesnone
animation-duration一个周期的时长0s
animation-timing-function关键帧之间的速度曲线ease
animation-delay第一个周期开始前的等待时间(负值表示从中途开始)0s
animation-iteration-count周期数,或 infinite1
animation-directionnormal、reverse、alternate、alternate-reversenormal
animation-fill-mode动画前后的样式:none、forwards、backwards、bothnone
animation-play-staterunning 或 pausedrunning

简写几乎可以按任意顺序书写。唯一的规则是:第一个时间值是时长,第二个是延迟:

.loader {
  animation: pulse 1.2s ease-in-out 0.2s infinite alternate both;
  /*         name  duration timing  delay count   direction fill */
}

direction 和 fill-mode 实时演示

选择一个方向、一种填充模式和一个次数,然后点击 Play。方块会移动 200px 到轨道末端。动画结束后,下面的读数会告诉你它停在了哪里:

注意观察:

  • fill-mode: none(默认值):最后一帧之后,方块跳回 x = 0,并重新变成琥珀色。
  • forwards:方块停在最后一个关键帧上。配合 normal 时是 x = 200 和绿色;配合 reverse 时停在 x = 0 和蓝色,因为最后播放的关键帧是 from。
  • alternate 配合次数 2 会去了再回来,所以即使用 forwards 也会停在 x = 0。

无限循环:加载动画

infinite 会一直重复,而给每个子元素设置不同的 animation-delay 可以让它们错开,依次运动。循环动画要保持平缓:慢一点、幅度小一点、不要闪烁。

role="status" 加上 aria-label 会告诉屏幕阅读器用户有内容正在加载,而光靠几个圆点是表达不出这一点的。如果想做一个旋转的圆圈,请看 rotate 页面。

暂停和控制动画

animation-play-state: paused 会把动画冻结在当前位置,running 则从那里继续。把鼠标悬停在下面的条上就能暂停它:

在 JavaScript 中,element.getAnimations() 会返回正在运行的 CSS 动画,每个动画都有 pause()、play()、cancel(),以及一个可以读取或设置的 currentTime。非无限循环的动画结束时会触发 animationend 事件,每个周期结束时会触发 animationiteration 事件。

尊重减少动态效果,绝不闪烁

有两条无障碍规则适用于所有动画:

  1. 减少动态效果。 有些人会因为画面运动而感到不适,因此可以在系统中要求减少动态效果。最稳妥的做法是:只有在他们没有要求减少动态效果时才添加动画:
@media (prefers-reduced-motion: no-preference) {
  .hero-title { animation: slide-in 0.8s ease-out both; }
}
  1. 不要闪烁。 一秒内闪烁超过三次的内容可能诱发癫痫发作。完全避免快速、高对比度的闪烁。

让动画保持流畅

尽量对 transform 和 opacity 做动画。浏览器应用它们时不需要重新排版页面,所以即使在性能较差的手机上也能保持流畅。对 width、height、top、left 或 margin 做动画,每一帧都会重新计算布局。要移动元素,请使用 transform 页面中介绍的 translate()。

常见错误

  • 没有时长。 animation: fade; 没有任何效果,因为默认时长是 0s。
  • 名字对不上。 animation-name 必须与 @keyframes 的名字完全一致,包括大小写。
  • 结束时跳回原样。 加上 forwards(或 both)来保持最后一个关键帧。
  • 延迟动画开始前闪一下。 在 animation-delay 期间,元素显示的是它原本的样式。backwards(或 both)会在延迟期间应用第一个关键帧。
  • 通过设置相同的值来重新播放动画。 再次设置同样的 animation 不会有任何效果。要先移除它,强制一次重排(el.offsetWidth),再重新设置,就像上面的 Play 按钮那样。
  • 对 display 做动画。 它会瞬间切换。改为对 opacity 和 transform 做动画。

常见问题

如何用 CSS 制作动画?

先用 @keyframes name { from { ... } to { ... } } 定义步骤,然后通过 animation 属性加上时长把它应用到元素上:animation: name 1s ease-out;。时长是必需的,因为它的默认值是 0s。

animation-fill-mode: forwards 有什么作用?

它让元素在动画结束后保持最后一个关键帧的样式。没有它,元素会跳回自己原本的样式。backwards 会在延迟期间应用第一个关键帧,both 则两者兼有。

如何让 CSS 动画无限循环?

设置 animation-iteration-count: infinite,或者在简写中加上 infinite:animation: spin 1s linear infinite;。再加上 alternate,每个周期就会先正向播放、再反向播放。

CSS 动画和过渡有什么区别?

过渡(transition)在属性值改变时,在两个值之间产生动画,通常由悬停或类名变化触发。动画(animation)一旦应用就会自动播放,可以有任意数量的关键帧,还可以重复、反向和暂停。

如何暂停 CSS 动画?

在元素上设置 animation-play-state: paused,比如放在 :hover 中,或者通过 JavaScript 添加的类来设置。把它改回 running,动画就会从停下的地方继续。

如何为偏好减少动态效果的用户关闭动画?

把动画放进 @media (prefers-reduced-motion: no-preference) { ... } 中,或者在 @media (prefers-reduced-motion: reduce) { ... } 中把它去掉。这个查询跟随用户操作系统中的“减少动态效果”设置。

Coddy 编程语言插图

和 Coddy 一起学编程

开始