CSS3 动画与过渡
从静态到生动——让界面拥有生命力与回响
理解变换、过渡、关键帧,打造丝滑的现代网页交互瞬变太廉价
你给按钮加了 :hover,鼠标移上去颜色"啪"地一下跳变——感觉卡顿、廉价,像 1990 年代的网页。怎么让它丝滑?
瞬变(廉价感)
.btn { background: #007bff; }
.btn:hover { background: #0056b3; }
/* 颜色瞬间跳变,像闪了一下 */
过渡(高级感)
.btn {
background: #007bff;
transition: background-color 0.3s ease;
}
/* 300ms 内平滑渐变,活了 */
这一章就解决这类问题。掌握 transform、transition、animation 三件套,你的界面会从"能用"变成"想用"。
元素形变
Transform 的 2D/3D 形变四个基本操作:位移、缩放、旋转、倾斜
/* 位移 — 最常用,不影响文档流 */
transform: translate(50px, -20px);
transform: translateX(100%);
/* 缩放 */
transform: scale(1.5); /* 放大 1.5 倍 */
transform: scale(0.8, 1.2); /* 宽缩高放 */
/* 旋转 */
transform: rotate(45deg);
/* 倾斜 */
transform: skew(10deg, 5deg);
组合用法:四个值可以组合使用,
transform: translate(-50%, -50%) rotate(45deg) scale(1.2) ——从左到右依次执行。
形变实战
Transform 最常用的三种微交互:居中、上浮、旋转——威力在于 hover 与状态切换
卡片居中(地球上最经典的 CSS 问题)
position: absolute; top: 50%; left: 50%;
transform: translate(-50%, -50%);
按钮/图标 hover 微交互
.btn:hover { transform: translateY(-2px); }
.card:hover { transform: scale(1.02); }
.icon:hover { transform: rotate(180deg); }
黄金原则:用 transform 替代 left/top/margin 做动画——前者走 GPU 加速,后者触发页面重排,性能差 10 倍。
变换的锚点
transform-origin 控制变换的"支点"——同一个 rotate,锚点不同,效果天差地别
/* 默认绕中心旋转 */
.icon { transform: rotate(45deg); }
/* 等价于显式写出 */
.icon { transform-origin: 50% 50%; transform: rotate(45deg); }
/* 绕左上角旋转 → 像翻页 */
.page { transform-origin: left center; transform: rotateY(-30deg); }
/* 绕底部中心放大 → 像从地面升起 */
.menu { transform-origin: bottom center; transform: scaleY(1.3); }
| 取值 | 效果 |
|---|---|
center center(默认) | 绕中心点变换 |
left top | 绕左上角 |
right bottom | 绕右下角 |
50% 0 | 绕顶部中点 |
过渡入门
Transition 让变化有温度——状态跳变是冰冷的,过渡让操作有了"回响"
无过渡(突変)
.btn { background: #007bff; }
.btn:hover { background: #0056b3; }
/* 颜色瞬间跳变 → 用户感觉"卡"了一下 */
有过渡(丝滑)
.btn {
background: #007bff;
transition: background-color 0.3s ease;
}
/* 颜色在 300ms 内匀速渐变 → 高级感 */
四个子属性
transition 控制着"怎么变、变多快、何时开始"
| 属性 | 作用 | 常用值 |
|---|---|---|
transition-property | 哪个属性要过渡 | all / background-color / transform |
transition-duration | 过渡持续多久 | 0.2s / 0.3s / 1s |
transition-timing-function | 速度曲线 | ease / linear / ease-in-out / cubic-bezier() |
transition-delay | 延迟多久后开始 | 0s / 0.5s |
/* 简写顺序:property duration timing-function delay */
transition: all 0.3s ease 0s;
缓动曲线
timing-function 决定运动的"情绪"——同样的时间,加速 vs 减速,情感完全不同
/* 预定义关键词 */
transition: transform 0.3s ease; /* 默认:先快后慢 */
transition: transform 0.3s linear; /* 匀速:机械感 */
transition: transform 0.3s ease-in; /* 慢入:退出、消失 */
transition: transform 0.3s ease-out; /* 慢出:进入、出现 */
transition: transform 0.3s ease-in-out; /* 慢入慢出:卡片 */
/* 自定义贝塞尔曲线 */
transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55); /* 回弹 */
| 曲线 | 适用场景 |
|---|---|
ease-out | 元素进入视图、弹窗弹出 |
ease-in | 元素离开视图、弹窗关闭 |
ease-in-out | 位置切换、状态切换 |
| 回弹贝塞尔 | 按钮按下、通知提醒、惊喜元素 |
调试工具:cubic-bezier.com — 可视化拖拽曲线,复制粘贴即用。
可动画属性
哪些属性能做过渡,哪些不能——牢记这张表,做动画不走弯路
| ✅ 可动画(性能好,首选) | ⚠ 可动画但性能差 | ❌ 不可动画 |
|---|---|---|
transform(translate/scale/rotate) | width / height | display |
opacity | margin / padding | font-family |
color / background-color | top / left | position |
box-shadow | float | |
border-radius、filter |
注意:为什么不用
display none→block? 因为 display 不是连续值。替代方案:opacity + visibility 组合。
按钮与卡片
实战:打造一套丝滑的 hover 效果合集,直接用在你的个人主页上
/* 主按钮:上浮 + 阴影 */
.btn-primary {
background: #D06519; color: #fff; border: none;
padding: 12px 28px; border-radius: 8px;
transition: all 0.3s ease;
}
.btn-primary:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px rgba(208, 101, 25, 0.4);
}
/* 卡片:浮起 */
.card {
transition: transform 0.35s ease, box-shadow 0.35s ease;
}
.card:hover {
transform: translateY(-6px);
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.12);
}
/* 链接:下划线滑出 */
.link { position: relative; }
.link::after {
content: ''; position: absolute;
bottom: -2px; left: 0; width: 0; height: 2px;
background: #D06519; transition: width 0.3s ease;
}
.link:hover::after { width: 100%; }
过渡的局限
Transition 只能两端过渡——CSS Animation 是多阶段剧本,@keyframes 是导演的指令
Transition 局限性
/* 只能做 A → B 状态跳变 */
transition: transform 0.3s ease;
/* 无法实现:A → B → C 复杂路径 */
/* 无法自动播放(依赖伪类触发) */
/* 无法暂停、反转、循环 */
Animation 解决方案
/* 定义多阶段动画 */
@keyframes slideIn {
0% { transform: translateX(-100%); opacity: 0; }
50% { transform: translateX(20px); }
100% { transform: translateX(0); opacity: 1; }
}
.element { animation: slideIn 0.6s ease-out; }
六个子属性
掌握 animation 这 6 个子属性,就能定义复杂动画的"导演指令集"
.bounce-ball {
animation-name: bounce;
animation-duration: 1s;
animation-timing-function: ease-in-out;
animation-delay: 0s;
animation-iteration-count: infinite; /* 数字或 infinite */
animation-direction: alternate; /* normal/alternate/reverse */
animation-fill-mode: forwards; /* 动画结束后停留在哪 */
}
/* 简写顺序 */
animation: bounce 1s ease-in-out 0s infinite alternate forwards;
| 属性 | 作用 | 常用值 |
|---|---|---|
animation-name | 引用的 @keyframes 名称 | 自定义名 |
animation-duration | 一次完整动画的时间 | 0.3s / 1s / 2s |
animation-timing-function | 速度曲线 | ease / cubic-bezier() |
animation-iteration-count | 播放次数 | 1 / 3 / infinite |
animation-direction | 播放方向 | normal / alternate |
animation-fill-mode | 动画前后的状态 | forwards / none |
旋转加载器
实战:纯 CSS 实现 loading——一个 div + 一圈边框 + keyframes = 完整动画
<div class="loader"></div>
.loader {
width: 40px; height: 40px;
border: 4px solid #e5e7eb;
border-top-color: #D06519; /* 顶部高亮 */
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
原理:四个边框三个透明,顶部着色 → 旋转时就像在转动。修改 border 颜色和 width 可以做出各种变体。
渐显入场动画
实战:用 animation-delay 创造错落有致的列表入场效果
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card {
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0; /* 初始不可见,动效完成后 forwards 保留 */
}
/* 5 张卡片错落出现 */
.card:nth-child(1) { animation-delay: 0s; }
.card:nth-child(2) { animation-delay: 0.1s; }
.card:nth-child(3) { animation-delay: 0.2s; }
/* ... 依次加 0.1s → 瀑布般的入场效果 */
GPU 加速
will-change 是 GPU 加速的最后钥匙——告诉浏览器"这个元素即将动画",浏览器提前分配资源
/* 告诉浏览器:这个元素即将做 transform 变化 */
.card {
will-change: transform; /* 提前分配 GPU */
transition: transform 0.3s ease;
}
/* ❌ 滥用 will-change → 内存暴涨,性能更差 */
* { will-change: transform; } /* 千万别这样做! */
/* ✅ 只在即将动画的元素上使用 */
.box:hover { will-change: transform; }
.box:not(:hover) { will-change: auto; }
注意:滥用 will-change 的后果:浏览器为每个声明的元素分配 GPU 显存,内存暴涨 + 卡顿。原则:只对'即将发生动画'的元素声明,动画结束后清除。
体谅不动画
prefers-reduced-motion——为不想看动画的用户(前庭功能障碍、癫痫)提供无动画体验
/* 为所有人添加动画 */
.card {
animation: fadeInUp 0.5s ease-out forwards;
}
/* 尊重'减少动画'系统设置 */
@media (prefers-reduced-motion: reduce) {
.card {
animation: none; /* 关闭动画 */
opacity: 1; /* 确保内容立即可见 */
transform: none;
}
}
为什么重要:根据 WHO 估计,全球约 15% 的人口有不同程度的前庭功能障碍。闪烁/旋转/快速平移可能触发眩晕甚至癫痫。一个专业的开发者会为这些用户提供无动画的替代体验。
动画三件套到手
transform
translate/scale/rotate + GPU 加速
transition
四大属性 + 缓动曲线 + 性能
animation + @keyframes
多阶段剧本 + 实战案例
will-change
何时用、何时不用
prefers-reduced-motion
让网页对所有人都友好
知识学会了,下一章你将学习如何借助 AI 的力量,对网页进行精准的渐进式设计和生成。