跳到主要内容

CSS3 动画(animation):如何实现旋转/淡入等简单动画?

面试速答(30 秒版 TL;DR)

  • CSS3 动画核心是两件事:用 @keyframes 定义关键帧,用 animation(或其拆分属性)把关键帧“挂”到元素上。
  • 旋转加载最常见写法:transform: rotate(...) + animation: spin 1s linear infinite;,并根据需要设置 transform-origin
  • 动画要顺滑:尽量只动画 transform / opacity(更可能走合成层),少动 left/top/width/height 这类容易触发布局的属性。
  • animation vs transitiontransition 依赖状态变化(如 :hover)且通常只有起止两态;animation 可多关键帧、可循环、可独立播放。

心智模型:@keyframes 负责“时间轴”,animation 负责“播放参数”

可以把 CSS 动画理解成“把一个时间函数作用到样式上”:

  • @keyframes:描述 0% 到 100% 的过程中,哪些属性怎么变化。
  • animation-*:描述 播放(多久、延迟、速度曲线、循环次数、方向、结束后停在哪一帧等)。

最小可用:实现一个旋转动画(spinner)

HTML:

<div class="spinner" aria-label="loading"></div>

CSS:

.spinner {
width: 24px;
height: 24px;
border: 3px solid #ddd;
border-top-color: #333;
border-radius: 50%;
/* 性能友好:只动画 transform */
animation: spin 1s linear infinite;
}

@keyframes spin {
to {
transform: rotate(360deg);
}
}

面试补充点:

  • 旋转动画通常用 linear,避免 ease 带来的“忽快忽慢”。
  • 如果你需要绕某个点转:用 transform-origin: left center; 等调整旋转中心。

再给两个高频例子:淡入与“弹一下”

1)淡入(入场)

.fade-in {
animation: fadeIn 200ms ease-out both;
}

@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

要点:

  • both 等价于 animation-fill-mode: both:开始前应用 0% 帧,结束后保留 100% 帧(常用于入场动画)。
  • opacity + transform 一般比改 top/left 更顺滑。

2)“弹一下”(强调反馈)

.pop {
animation: pop 240ms cubic-bezier(0.2, 0.9, 0.2, 1);
}

@keyframes pop {
0% {
transform: scale(0.96);
}
60% {
transform: scale(1.04);
}
100% {
transform: scale(1);
}
}

animation 常用参数速记(能口述)

animation 简写常见形态:

/* name duration timing-function delay iteration-count direction fill-mode */
.box {
animation: spin 1s linear 0s infinite normal both;
}

拆分属性(面试常问你是否知道有哪些):

  • animation-name:关键帧名字(对应 @keyframes)。
  • animation-duration:持续时间,默认是 0s(这是“动画不播放”的常见原因)。
  • animation-timing-function:速度曲线,常见 linear/ease/ease-in/ease-out,也可用 cubic-bezier(...)steps(n, ...)
  • animation-delay:延迟多久开始。
  • animation-iteration-count:播放次数,infinite 表示无限循环。
  • animation-direction:方向,常用 normal/alternate(来回播放)。
  • animation-fill-mode:结束后停在哪一帧,常用 forwards/both
  • animation-play-staterunning/paused,用于暂停/继续。

高频追问:怎么让动画更流畅?会不会触发重排?

面试答法建议“先结论,再展开”:

  1. 结论:优先动画 transform/opacity,尽量避免动画 layout 属性(如 width/height/left/top)。
  2. 原因:transform/opacity 更可能只走合成(composite),不需要每帧做布局与重绘;而布局相关属性可能触发 重排/重绘
  3. 实战技巧(点到为止):
    • 需要提前提示浏览器:will-change: transform;(用完及时移除,别滥用)。
    • 对“转圈圈”这种长期动画,注意节能与可访问性,必要时降级。

易错点/坑(面试里很好加分)

  • 忘了写 animation-duration:默认 0s,看起来像没生效。
  • 同一元素上多个地方都在写 transformtransform 是一个整体属性,后写的会覆盖先写的。需要叠加时:
    • 合并成一个 transform: translate(...) rotate(...);或
    • 用嵌套元素(外层负责平移,内层负责旋转);或
    • 用 CSS 变量组合(进阶)。
  • display: none 无法做过渡/动画:入场/退场更常见做法是 opacity/transform 配合 visibility/pointer-events
  • 忽略“减少动态效果”偏好:可以用媒体查询尊重用户设置。
@media (prefers-reduced-motion: reduce) {
.spinner,
.fade-in,
.pop {
animation: none !important;
}
}

速记要点(可背诵)

  • CSS 动画 = @keyframes(时间轴) + animation(播放参数)。
  • 旋转 = transform: rotate + linear + infinite
  • 性能优先动画 transform/opacity,少动画 left/top/width/height
  • duration 默认 0sfill-mode: forwards/both 决定“播完停哪”。