CSS 过渡与关键帧:动画的两种写法
transition 管「从 A 到 B」,animation 管「一段编排」。选对写法,代码少一半。
CSS 动画只有两条路:transition(过渡)和 animation(关键帧)。新手最容易犯的错是用 transition 硬凑多段动画,或拿 animation 做简单的悬停反馈。判断标准一句话:状态之间的渐变用 transition,自带时间轴的编排用 animation。
transition:状态之间的桥
transition 只描述「属性从当前值到目标值怎么变」,它自己不定义动画内容。触发方式:类名切换、:hover、媒体查询变化、JS 改样式。
.card { transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 200ms ease; }
.card:hover { transform: translateY(-4px); box-shadow: 0 12px 24px rgba(0,0,0,0.12); }三个要点:
- 过渡的属性列表要显式列出,别偷懒写 all——意外的属性变化也会跟着动
- 触发源和样式写在一起(.card:hover),回退时自动反向播放
- 时长 150 到 300ms,微反馈 150ms,入场 250ms 左右,超过 500ms 像卡死
animation:自带剧本
animation 用 @keyframes 定义关键帧,浏览器自动补间。适合多段动画、循环动画、以及不依赖交互的入场动画。
@keyframes fade-up {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
.reveal { animation: fade-up 400ms cubic-bezier(0.22, 1, 0.36, 1) both; }- both 让动画开始前就停在 from 状态(避免闪烁),结束后停在 to 状态
- 循环动画加 infinite,但循环必须有「值得看」的内容,纯装饰循环是干扰
- 关键帧只写变化的属性,别在里面重置无关样式
交错入场:stagger 的两种实现
列表逐项出现,transition 和 animation 各有写法。
transition 版(依赖 JS 或延迟类名):
.item { opacity: 0; transform: translateY(12px); transition: all 300ms ease; }
.item.in { opacity: 1; transform: none; }JS 逐个加 .in,间隔 60ms。好处是可以用 IntersectionObserver 做「滚到才出现」。
animation 版(纯 CSS,借助变量):
.item { animation: fade-up 400ms ease both; animation-delay: calc(var(--i) * 60ms); }HTML 里给每项写 style="--i:0"、"--i:1"……零 JS,但一进页面就播,不管看不看得到。
性能红线:只动 transform 和 opacity
浏览器合成器只对这两个属性的动画走 GPU 加速。width、height、top、left 的动画会触发重排重绘,帧率直接崩。检查方法:Chrome DevTools 的 Performance 面板录一遍,看有没有大片的紫色(渲染)区块。
will-change 是双刃剑:只加给「正在」动画的元素,动画结束移除。全局加 will-change 会制造大量合成层,内存暴涨。
可访问性兜底
系统开了「减弱动态效果」的用户应看到即时到位的版本,FORMA 导出的动效已内置对应处理,自定义动画时保留它。
怎么选
- 悬停反馈、开关、展开折叠:transition
- 首屏入场、徽标呼吸、加载骨架:animation
- 列表交错:能纯 CSS 就 animation + 变量;要滚动触发就 transition + IntersectionObserver
- 复杂编排(多段、往返、循环):animation,多组 keyframes 串
记住分工:transition 管「交互的反馈」,animation 管「页面的表演」。两者都会写,动画的 90% 场景就覆盖了。
评论 · 0 条
还没有评论,来抢沙发。
评论经人工审核后公开;请勿提交密码、密钥等敏感信息。