10动画高级
第 07 课把动画基础打好了:animation 简写、@keyframes 分镜、缓动、循环方向。
这一课往上走一阶——让动画「长出耳朵」(监听开始/结束事件)、
缓动曲线自己画(贝塞尔 & 阶梯函数)、
让动画跟着滚动条走(滚动驱动 + view-timeline)、
再把加载旋转、进度条、悬停反馈串成实战。学会这一课,动画就能「按你的指挥棒表演」。
一、回顾 + 进阶地图
07 课我们掌握了一张牌:@keyframes 分镜表 + animation 简写绑定,
浏览器自动播放。基础够用了,但要做出产品级的动效,还需要四把进阶钥匙。
| 方向 | 解决什么 | 本课出现位置 |
|---|---|---|
| animation 八属性细分 | fill-mode 让动画停在末态、首帧就位 | 第二节 |
| 缓动函数深度 | cubic-bezier 画曲线、steps 走阶梯 | 第三节 |
| 动画事件 | JS 监听开始 / 结束 / 迭代,串联行为 | 第四节 |
| 滚动驱动 | scroll-timeline / view-timeline 跟滚动走 | 第六节 |
二、animation 属性的细分:fill-mode 三态
07 课列了 animation 八个子属性:name / duration / timing-function / delay /
iteration-count / direction / fill-mode / play-state。
本节只展开 fill-mode——它最容易让人踩坑:
不写它,动画演完立刻弹回基态。
| 值 | 延迟期间定格 | 演完定格 | 典型场景 |
|---|---|---|---|
| none(默认) | 显示基态 | 弹回基态 | 循环动画(无所谓定格) |
| forwards | 显示基态 | 停在末帧 | 入场动画演完就位 |
| backwards | 应用首帧 | 弹回基态 | 有 delay 时藏首帧出场 |
| both | 应用首帧 | 停在末帧 | 既要 delay 藏身,又要结尾就位 |
三只方块各跑同一动画 + 1.6s 延迟,但 fill-mode 不同——看「等待期」与「结束后」的姿态:
弹回基态
延迟期用首帧
首末都定格
forwards 或 both。入场动画只演一次就停是默认值办不到的,必须显式写 fill-mode。三、缓动函数 timing-function 深度
07 课说过缓动函数是「每两站之间怎么跑」。基础五件套:linear / ease /
ease-in / ease-out / ease-in-out。
这一节走得更深——cubic-bezier 自定义曲线 + steps 阶梯函数。
| 函数 | 形状 | 适用场景 |
|---|---|---|
| linear | 匀速直线 | loading 转圈、机械位移 |
| ease(默认) | 慢-快-慢 | 通用入场、退场 |
| ease-in | 慢启动 | 出场(飞走) |
| ease-out | 快启动慢收 | 入场(飞入到位) |
| ease-in-out | 两头慢中间快 | 往复、节奏感动画 |
| cubic-bezier(x1,y1,x2,y2) | 自绘曲线 | 回弹、弹性、过冲效果 |
| steps(n, jump-term) | 阶梯跳变 | 逐帧动画、打字机、雪花飘落 |
cubic-bezier 是一条贝塞尔曲线,两个控制点决定它的「性格」。第一个控制点 y 轴负值会让动画「冲过头再回弹」:
cubic-bezier(0.68, -0.55, 0.27, 1.55)——方块滑过终点又拉回来再就位(控制点 y 为负产生回弹)y1 = -0.55 → 起步阶段冲过终点;y2 = 1.55 → 末段反弹到位
steps(n) 把动画切成 n 个离散步阶——适合「逐帧精灵图」或打字机效果:
steps(8) 把一段 0→100% 的位移切成 8 个等距停顿——点数字看「瞬移」效果对比组:连续位移(linear)vs 逐帧(steps(8))
cubic-bezier.com 拖两个控制点看实时曲线,
调满意了复制四参数到代码里。y 值允许为负(冲过头)或大于 1(停留更久),
这正是回弹、阻尼效果的来源。四、动画事件:让 JS 听到 CSS 的脚步声
CSS 动画不只是「看」——它在开始 / 结束 / 每次迭代时会派发 DOM 事件, JS 可以监听它们去做别的事:
| 事件 | 触发时机 | 常见用途 |
|---|---|---|
| animationstart | 动画开演瞬间(含 delay 期开始) | 打点统计、初始化下一帧 |
| animationend | 动画全部跑完(含 forwards 后定格) | 链式启动下一个动画、隐藏元素 |
| animationiteration | 每轮迭代之间(infinite 时反复触发) | 轮询打点、节奏灯 |
标准监听写法(JS):
事件对象的两个关键字段:
五、@keyframes 高级技巧:多动画并行 + 无障碍
07 课讲过「多动画逗号分隔」让一个元素同时跑两套戏。这节展开三个实战技巧: 多动画并行、transform-origin 旋转中心、 prefers-reduced-motion 关动画。
c10-mr-scale 的 duration 从 2.4s 改成 0.6s 看「喘不上气」的拥挤感旋转(1.6s)+ 变色(2.4s)+ 缩放(2.4s)· 互不干扰
无障碍动画礼仪:用户系统设置了「减少动态效果」时,应该关动画。
transform-origin: 50% 50%),
想让指针绕一端转就写 transform-origin: 0 100%(左下角);
想让钟摆绕顶部转写 top center。这个值写在元素上,不写在 @keyframes 里。六、滚动驱动动画:scroll-timeline 与 view-timeline
这是 2023 年 Chrome 115+ 才落地的「现代派」特性——让动画跟着滚动条进度走,
而不是跟着时间走。原本要 JS 监听 scroll 才能做,现在纯 CSS 就能搞定。
| 特性 | 跟着谁走 | 典型用法 |
|---|---|---|
| scroll-timeline | 滚动容器的滚动进度(0% → 100%) | 页面顶部进度条、滚动驱动的全局特效 |
| view-timeline | 元素自身在视口里的可见性 | 滚到视口才淡入、图片 parallax 视差 |
| animation-timeline | 把上面两种绑到 animation 上 | — |
| animation-range | 指定时间线哪一段生效(entry / cover / exit) | — |
view-timeline 演示 1:从视口外滚入时淡入上移——向下滚动下方小窗试试:
entry(元素进入视口)、
cover(元素覆盖视口)、exit(元素离开视口),
后面跟百分比指定起止点。最常用:entry 0% cover 30%——元素进入视口的 0%~30% 这段距离里跑完整动画。七、复合动画实战:loading + 进度条 + 悬停反馈
综合本课所有招式做一页三件套 demo——loading 转圈(无限循环)+ 进度条(一次性动画)+ 按钮 hover 反馈, 三种典型场景一次看全。
scale 改成 1.2 看反馈过头;改进度条 delay 到 0s 看立即启动八、本章小结
- animation 八属性里 fill-mode 最常踩坑:不写就弹回基态,演完留位必须写
forwards或both - 缓动函数从内置五件套升级到 cubic-bezier 自定义曲线(用 cubic-bezier.com 拖控制点)和 steps(n) 阶梯(逐帧动画)
- CSS 动画会派发
animationstart / animationend / animationiteration三个事件,JS 用 addEventListener 监听做链式行为 - 多动画并行用逗号分隔;同属性后者覆盖前者,想让 transform 叠加必须把旋转/缩放合并写到一个 keyframe 里
- 无障碍礼仪:
@media (prefers-reduced-motion: reduce)关动画,尊重系统偏好 animation-timeline: view()+animation-range实现滚动驱动动画,但仅 Chrome 115+,记得写 fallback
cubic-bezier(0.34, 1.56, 0.64, 1) 让 hover 反馈「弹一下」;
③在 CSS 顶部加 @media (prefers-reduced-motion: reduce) 关掉所有动画,做一次无障碍重构;
④用 steps(8) 做一个走马灯式的逐帧精灵图动画(找一张 8 帧序列图自己拼)。
最后写一个完整的「卡片入场:scroll 进入视口淡入 + hover 抬升 + reduced-motion 关动画」综合 demo。