10动画高级

第 07 课把动画基础打好了:animation 简写、@keyframes 分镜、缓动、循环方向。 这一课往上走一阶——让动画「长出耳朵」(监听开始/结束事件)、 缓动曲线自己画(贝塞尔 & 阶梯函数)、 让动画跟着滚动条走(滚动驱动 + view-timeline)、 再把加载旋转、进度条、悬停反馈串成实战。学会这一课,动画就能「按你的指挥棒表演」。

约 18 分钟 7 个动手实验 滚动驱动 + 动画事件

一、回顾 + 进阶地图

07 课我们掌握了一张牌:@keyframes 分镜表 + animation 简写绑定, 浏览器自动播放。基础够用了,但要做出产品级的动效,还需要四把进阶钥匙。

动画进阶四个方向:把「自动播放」升级成「可编排」
方向解决什么本课出现位置
animation 八属性细分fill-mode 让动画停在末态、首帧就位第二节
缓动函数深度cubic-bezier 画曲线、steps 走阶梯第三节
动画事件JS 监听开始 / 结束 / 迭代,串联行为第四节
滚动驱动scroll-timeline / view-timeline 跟滚动走第六节
学习路线:第二节先补 fill-mode(07 课点到为止,这课展开)→ 第三节画曲线 → 第四节学会用 JS 钩 → 第五节综合多动画 → 第六节玩滚动驱动 → 第七节三件套实战。看不懂的先跳下一节,回头再嚼。

二、animation 属性的细分:fill-mode 三态

07 课列了 animation 八个子属性:name / duration / timing-function / delay / iteration-count / direction / fill-mode / play-state。 本节只展开 fill-mode——它最容易让人踩坑: 不写它,动画演完立刻弹回基态。

animation-fill-mode 四种值:动画「首尾」两个时刻定格在哪
值延迟期间定格演完定格典型场景
none(默认)显示基态弹回基态循环动画(无所谓定格)
forwards显示基态停在末帧入场动画演完就位
backwards应用首帧弹回基态有 delay 时藏首帧出场
both应用首帧停在末帧既要 delay 藏身,又要结尾就位

三只方块各跑同一动画 + 1.6s 延迟,但 fill-mode 不同——看「等待期」与「结束后」的姿态:

fill-mode 三态对照:把 1.6s 改成 4s 看等待期与结束后的定格差别——左侧(none)会弹回初始位置
踩坑现场:动画演完「一闪而过回到原位」—— 99% 是忘了 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 为负产生回弹)

steps(n) 把动画切成 n 个离散步阶——适合「逐帧精灵图」或打字机效果:

逐帧跳动:steps(8) 把一段 0→100% 的位移切成 8 个等距停顿——点数字看「瞬移」效果
调曲线不用瞎试——打开 cubic-bezier.com 拖两个控制点看实时曲线, 调满意了复制四参数到代码里。y 值允许为负(冲过头)或大于 1(停留更久), 这正是回弹、阻尼效果的来源。

四、动画事件:让 JS 听到 CSS 的脚步声

CSS 动画不只是「看」——它在开始 / 结束 / 每次迭代时会派发 DOM 事件, JS 可以监听它们去做别的事:

动画三大事件:JS 监听 CSS 动画的生命周期
事件触发时机常见用途
animationstart动画开演瞬间(含 delay 期开始)打点统计、初始化下一帧
animationend动画全部跑完(含 forwards 后定格)链式启动下一个动画、隐藏元素
animationiteration每轮迭代之间(infinite 时反复触发)轮询打点、节奏灯

标准监听写法(JS):

事件对象的两个关键字段:

沙箱提示:本课示例需要 JS 监听事件, 静态 HTML 沙箱禁 JS,故只能用静态对照 + 代码块说明。 想跑完整效果,复制 JS 代码到自己的项目里、给元素绑个动画即可触发。

五、@keyframes 高级技巧:多动画并行 + 无障碍

07 课讲过「多动画逗号分隔」让一个元素同时跑两套戏。这节展开三个实战技巧: 多动画并行、transform-origin 旋转中心、 prefers-reduced-motion 关动画。

一个徽章三套戏同时演——把 c10-mr-scale 的 duration 从 2.4s 改成 0.6s 看「喘不上气」的拥挤感

无障碍动画礼仪:用户系统设置了「减少动态效果」时,应该关动画。

rotate 默认绕中心转(transform-origin: 50% 50%), 想让指针绕一端转就写 transform-origin: 0 100%(左下角); 想让钟摆绕顶部转写 top center。这个值写在元素上,不写在 @keyframes 里。

六、滚动驱动动画:scroll-timeline 与 view-timeline

这是 2023 年 Chrome 115+ 才落地的「现代派」特性——让动画跟着滚动条进度走, 而不是跟着时间走。原本要 JS 监听 scroll 才能做,现在纯 CSS 就能搞定。

scroll-timeline vs view-timeline:跟着谁走
特性跟着谁走典型用法
scroll-timeline滚动容器的滚动进度(0% → 100%)页面顶部进度条、滚动驱动的全局特效
view-timeline元素自身在视口里的可见性滚到视口才淡入、图片 parallax 视差
animation-timeline把上面两种绑到 animation 上—
animation-range指定时间线哪一段生效(entry / cover / exit)—
兼容性硬伤:scroll-timeline / view-timeline 目前 仅 Chrome 115+ 与 Edge 同内核版本 支持,Firefox、Safari 暂未落地。 不支持的浏览器元素会保持 fallback 状态(不会出错,只是不动)。 生产环境请做好视觉降级:给元素写「默认完整可见」的样式,动画从隐藏走到可见。

view-timeline 演示 1:从视口外滚入时淡入上移——向下滚动下方小窗试试:

滚动下方小窗里的元素,渐入 + 上移——Chrome 115+ 才看得到;其它浏览器看到的是 fallback(直接显示)
range 关键字三选一:entry(元素进入视口)、 cover(元素覆盖视口)、exit(元素离开视口), 后面跟百分比指定起止点。最常用:entry 0% cover 30%——元素进入视口的 0%~30% 这段距离里跑完整动画。

七、复合动画实战:loading + 进度条 + 悬停反馈

综合本课所有招式做一页三件套 demo——loading 转圈(无限循环)+ 进度条(一次性动画)+ 按钮 hover 反馈, 三种典型场景一次看全。

三件套同台——把按钮的 scale 改成 1.2 看反馈过头;改进度条 delay 到 0s 看立即启动
三件套背后的「招式组合」:无限循环用 infinite + linear(匀速感); 一次性用 forwards / both(停在末态);hover 反馈用 transition + cubic-bezier。 一道完整的「产品级动效」往往是这三招拼出来的。

八、本章小结

  • 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
动手练习:①把第 07 课「loading 旋转」改造成滚动驱动——元素进入视口才开演; ②给一个按钮加 cubic-bezier(0.34, 1.56, 0.64, 1) 让 hover 反馈「弹一下」; ③在 CSS 顶部加 @media (prefers-reduced-motion: reduce) 关掉所有动画,做一次无障碍重构; ④用 steps(8) 做一个走马灯式的逐帧精灵图动画(找一张 8 帧序列图自己拼)。 最后写一个完整的「卡片入场:scroll 进入视口淡入 + hover 抬升 + reduced-motion 关动画」综合 demo。