transition、animation、keyframes——三种动效武器,让网页从静止变生动,又不喧宾夺主。
静态页面看久了会"死",加一点动效立刻就活。但动效是个危险品:用得好是点睛之笔,用过头就是花式打扰。CSS 提供了三件武器——transition、animation、transform,掌握它们的分工,就能做出"刚好够"的动效。
这篇我们一件件讲清楚:transition 处理状态切换、animation 做复杂循环、transform 负责变形位移,最后聊性能和分寸感。学完你不会做出炫技的动画,但能让页面在每个交互节点上都"跟手"。
transition 是最常用的动效工具。它管的是"从一个状态到另一个状态的过渡"——比如鼠标悬停时颜色变深、按钮按下时缩放。你只需要声明"哪个属性、用多久、什么曲线",浏览器会自动补上中间帧。
.btn {
background: #4A7C3A;
transition: background 0.3s ease, transform 0.3s ease;
}
.btn:hover {
background: #3a6b2c;
transform: translateY(-2px); /* 悬停轻微上浮 */
}
transition 的关键不在时长,而在缓动曲线。ease 是默认值,开头慢中间快结尾慢,适合大多数交互。但如果你想要更有"个性"的动效,就要用 cubic-bezier 自己调曲线。
/* 自定义贝塞尔曲线:先快后慢,有"落定感" */
.card {
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.card:hover {
transform: scale(1.03);
}
上面这个 cubic-bezier 的第二个值超过 1,会产生"回弹"效果——元素冲过目标位置再弹回来,比平铺直叙的 ease 有灵气得多。这个技巧在做卡片悬停、按钮点击时特别好用。
transition 只能在两个状态间过渡,要做"持续运转"或"多步骤"的动画,就得用 animation 配合 keyframes。keyframes 定义关键帧,animation 负责调度——播放几次、往复还是单向、暂停还是运行。
/* 定义关键帧:从透明淡入并上移 */
@keyframes fadeUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 应用动画:进入页面时淡入上浮 */
.reveal {
animation: fadeUp 0.6s ease both;
}
animation 的几个常用属性值得记一下:iteration-count 控制播放次数(infinite 是无限循环),alternate 让动画往复来回(奇数次正向、偶数次反向),animation-fill-mode 决定动画结束前后保持哪一帧。
/* 加载指示器:无限旋转 */
@keyframes spin {
to { transform: rotate(360deg); }
}
.loader {
animation: spin 1s linear infinite;
}
/* 呼吸效果:往复缩放 */
@keyframes breathe {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.dot {
animation: breathe 2s ease-in-out infinite alternate;
}
transform 是动效的"肌肉",几乎所有位移、缩放、旋转都靠它。它最大的优点是不触发重排——元素变形时不影响周围布局,浏览器只需在合成层上重新绘制,性能远好于改 top、left、width。
/* 位移:从原位置偏移,不影响布局 */
.float-up {
transform: translateY(-10px);
}
/* 缩放:以中心为原点放大 */
.zoom-in {
transform: scale(1.1);
}
/* 旋转:顺时针转 90 度 */
.turn {
transform: rotate(90deg);
}
/* 组合:位移 + 缩放一起用 */
.card:hover {
transform: translateY(-4px) scale(1.02);
}
多个 transform 可以连写,按顺序执行。组合时注意顺序——先旋转再平移,和先平移再旋转,效果完全不同。一般遵循"先缩放旋转、再位移"的顺序,符合直觉。
动效一多就容易卡,尤其在低端机上。卡顿的根源通常是触发了重排或重绘。重排是元素位置变了,浏览器要重新计算整个布局;重绘是外观变了,要重新绘制像素。两者都耗性能,重排更甚。
所以动画要尽量只动两个属性:transform 和 opacity。它们在合成层处理,不触发布局计算。相反,改 top、left、width、height、margin 都会引发重排,能避就避。
/* 差:改 top 触发重排,滚动时会卡 */
.bad {
position: absolute;
top: 0;
transition: top 0.3s;
}
.bad.scroll { top: 20px; }
/* 好:用 transform 位移,只动合成层 */
.good {
transform: translateY(0);
transition: transform 0.3s;
}
.good.scroll { transform: translateY(20px); }
遇到复杂动画还可以用 will-change 提前告知浏览器"这个元素要变了",让它提前创建合成层。但别滥用,每个 will-change 都占内存,铺满全站反而拖慢。
/* 仅对确实会动的元素声明 */
.carousel-track {
will-change: transform;
}
技术讲完了,最后回到分寸感。动效存在的意义是"引导注意力"和"提供反馈",不是炫技。几条原则值得刻在脑子里:
/* 照顾不喜欢动效的用户 */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
三件武器讲完了。transition 管过渡、animation 管循环、transform 管变形,再配上性能意识和对"度"的把握,你就能做出既生动又不打扰的页面。这是基础教程的最后一课,接下来可以回到教程列表,挑感兴趣的方向继续深入。