CSS: 动画 @keyframes
过渡(transition)只能处理"从状态 A 到状态 B"的简单变化。而通过 @keyframes(关键帧动画),你可以定义更复杂的多阶段动画——元素可以经过多个中间状态,甚至无限循环。
动画属性速查表
| 属性 | 常用值 | 作用 |
|---|---|---|
@keyframes |
动画名称 { 0% {...} 100% {...} } |
定义关键帧动画序列 |
animation-name |
fadeIn, slideLeft |
引用的 @keyframes 名称 |
animation-duration |
2s, 500ms |
动画完成一次的时间 |
animation-timing-function |
ease, linear, ease-in-out |
动画速度曲线 |
animation-delay |
0.5s, -1s(提前开始) |
动画开始前的延迟 |
animation-iteration-count |
1, 3, infinite |
动画播放次数 |
animation-direction |
normal, reverse, alternate, alternate-reverse |
动画方向 |
animation-fill-mode |
none, forwards, backwards, both |
动画结束后样式保持 |
animation-play-state |
running, paused |
动画播放/暂停状态 |
animation |
fadeIn 2s ease 0.5s infinite |
简写属性 |
1. @keyframes 定义动画
基本语法:
▶ 示例
HTML
<style>
@keyframes anim-keyframes{
0% {
/* 起始状态 */
transform: translateX(0);
opacity: 1;
}
50% {
/* 中间状态 */
transform: translateX(100px);
opacity: 0.5;
}
100% {
/* 结束状态 */
transform: translateX(0);
opacity: 1;
}
}
.anim-demo {
width: 100px; height: 100px;
background: linear-gradient(135deg, #3498db, #2ecc71);
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
color: white; font-size: 14px;
animation: anim-keyframes 2s infinite;
margin: 20px 0;
}
</style>
<div class="anim-demo">自定义关键帧动画</div>
也可以使用 from 和 to 关键字(等价于 0% 和 100%):
▶ 示例
HTML
<style>
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.anim-demo-fadeIn {
width: 100px; height: 100px;
background: linear-gradient(135deg, #3498db, #2ecc71);
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
color: white; font-size: 14px;
animation: fadeIn 2s infinite;
margin: 20px 0;
}
</style>
<div class="anim-demo-fadeIn">Anim demo fadein</div>
(1) 多阶段动画
▶ 示例
HTML
<style>
@keyframes bounce {
0% { transform: translateY(0); }
30% { transform: translateY(-50px); }
50% { transform: translateY(-25px); }
70% { transform: translateY(-50px); }
100% { transform: translateY(0); }
}
.anim-demo-bounce {
width: 100px; height: 100px;
background: linear-gradient(135deg, #3498db, #2ecc71);
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
color: white; font-size: 14px;
animation: bounce 2s infinite;
margin: 20px 0;
}
</style>
<div class="anim-demo-bounce">Anim demo bounce</div>
2. animation 属性
⚠️ animation 兼容性: 大部分现代浏览器已全面支持 CSS 动画,但
@keyframes 中的某些属性(如 auto 值)在某些浏览器上有兼容问题。复杂动画建议用 infinite 循环时加 alternate 让动画来回播放,比直接重复更自然。
定义好动画后,用 animation 属性应用到元素上:
(1) animation-name(动画名称)
▶ 示例
HTML
<style>
.box {
animation-name: fadeIn; /* 对应 @keyframes 的名称 */
}
.anim-demo-的名称 {
width: 100px; height: 100px;
background: linear-gradient(135deg, #3498db, #2ecc71);
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
color: white; font-size: 14px;
animation: 的名称 2s infinite;
margin: 20px 0;
}
</style>
<div class="anim-demo-的名称">Anim demo 的名称</div>
(2) animation-duration(持续时间)
▶ 示例
HTML
<style>
.box {
animation-duration: 2s; /* 播放一次要2秒 */
}
</style>
<div class="box">这是一个盒子元素,用于展示盒模型相关样式效果</div>
(3) animation-timing-function(速度曲线)
▶ 示例
HTML
<style>
.box {
animation-timing-function: ease; /* 默认 */
animation-timing-function: linear; /* 匀速 */
animation-timing-function: ease-in-out;
/* 动画曲线 */
}
</style>
<div class="box">这是一个盒子元素,用于展示盒模型相关样式效果</div>
(4) animation-delay(延迟时间)
▶ 示例
HTML
<style>
.box {
animation-delay: 1s; /* 1秒后才开始播放 */
}
</style>
<div class="box">这是一个盒子元素,用于展示盒模型相关样式效果</div>
(5) animation-iteration-count(播放次数)
▶ 示例
HTML
<style>
.box {
animation-iteration-count: 3; /* 播放3次 */
animation-iteration-count: infinite; /* 无限循环 */
}
</style>
<div class="box">这是一个盒子元素,用于展示盒模型相关样式效果</div>
(6) animation-direction(方向)
▶ 示例
HTML
<style>
.box {
animation-direction: normal; /* 正常方向(默认) */
animation-direction: reverse; /* 反向播放 */
animation-direction: alternate; /* 先正向再反向 */
animation-direction: alternate-reverse; /* 先反向再正向 */
}
</style>
<div class="box">这是一个盒子元素,用于展示盒模型相关样式效果</div>
(7) animation-fill-mode(填充模式)
控制动画开始前和结束后元素的样式:
▶ 示例
HTML
<style>
.box {
animation-fill-mode: none; /* 默认,动画结束后恢复到初始状态 */
animation-fill-mode: forwards; /* 动画结束后保持最后状态 */
animation-fill-mode: backwards;/* 动画开始前应用第一帧样式 */
animation-fill-mode: both; /* 同时应用 forwards 和 backwards */
}
</style>
<div class="box">这是一个盒子元素,用于展示盒模型相关样式效果</div>
(8) animation-play-state(播放状态)
▶ 示例
HTML
<style>
.box {
animation-play-state: running; /* 播放中 */
}
.box:hover {
animation-play-state: paused; /* 悬停时暂停 */
}
</style>
<div class="box">这是一个盒子元素,用于展示盒模型相关样式效果</div>
<div class="box">这是一个盒子元素,用于展示盒模型相关样式效果</div>
(9) animation 简写
▶ 示例
HTML
<style>
.box {
animation: bounce 1s ease-in-out 0.5s infinite alternate;
/* 动画 */
/* name duration timing-function delay count direction */
}
</style>
<div class="box">这是一个盒子元素,用于展示盒模型相关样式效果</div>
<span class="demo-bounce">弹跳动画</span>
<span class="demo-infinite">无限循环</span>
3. 综合示例
(1) 心跳动画
▶ 示例
HTML
<style>
@keyframes heartbeat {
0% { transform: scale(1); }
25% { transform: scale(1.2); }
50% { transform: scale(1); }
75% { transform: scale(1.2); }
100% { transform: scale(1); }
}
.heart {
display: inline-block;
font-size: 3rem;
animation: heartbeat 1s infinite;
}
.anim-demo-heartbeat {
width: 100px; height: 100px;
background: linear-gradient(135deg, #3498db, #2ecc71);
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
color: white; font-size: 14px;
animation: heartbeat 2s infinite;
margin: 20px 0;
}
</style>
<div class="anim-demo-heartbeat">Anim demo heartbeat</div>
(2) 加载旋转动画
▶ 示例
HTML
<style>
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #eee;
border-top-color: #3498db;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
.anim-demo-spin {
width: 100px; height: 100px;
background: linear-gradient(135deg, #3498db, #2ecc71);
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
color: white; font-size: 14px;
animation: spin 2s infinite;
margin: 20px 0;
}
</style>
<div class="anim-demo-spin">Anim demo spin</div>
(3) 淡入滑入动画
▶ 示例
HTML
<style>
@keyframes slideInUp {
from {
transform: translateY(30px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.animate-in {
animation: slideInUp 0.5s ease-out forwards;
/* 动画 */
}
.anim-demo-slideInUp {
width: 100px; height: 100px;
background: linear-gradient(135deg, #3498db, #2ecc71);
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
color: white; font-size: 14px;
animation: slideInUp 2s infinite;
margin: 20px 0;
}
</style>
<div class="anim-demo-slideInUp">Anim demo slideinup</div>
(4) 逐帧动画
▶ 示例
HTML
<style>
@keyframes typing {
from { width: 0; }
to { width: 100%; }
}
.typing-text {
overflow: hidden;
/* 溢出处理 */
white-space: nowrap;
animation: typing 3s steps(20) forwards;
}
.anim-demo-typing {
width: 100px; height: 100px;
background: linear-gradient(135deg, #3498db, #2ecc71);
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
color: white; font-size: 14px;
animation: typing 2s infinite;
margin: 20px 0;
}
</style>
<div class="anim-demo-typing">Anim demo typing</div>
4. 动画性能优化
🔥 性能警告: 动画不要做太多。同时播放二三十个元素的动画会导致页面卡顿。用
will-change 属性提前告知浏览器哪些元素会有动画,但别滥用——设了 will-change 的元素会占用额外的 GPU 内存。
为了获得流畅的动画,尽量使用以下属性:
✅ 性能好的属性:
transform(位移、缩放、旋转)opacity
⚠️ 性能一般的属性:
color、background-color
❌ 尽量避免动画的属性:
width、height、margin、padding(会引起重排)box-shadow(计算开销大)
❓ 常见问题
Q @keyframes 和 transition 有什么区别?
A transition 只能处理"从状态 A 到状态 B"的简单变化,而 @keyframes 可以定义多个关键帧(0%、50%、100%),实现更复杂的多阶段动画。简单悬浮效果用 transition,复杂动效用 @keyframes。
Q animation 的 infinite 循环会让页面卡顿吗?
A 合理使用不会。但不要同时让太多元素做动画(建议不超过 20 个)。可以用 will-change 提前告诉浏览器哪些元素会变化,帮助 GPU 加速。如果页面掉帧,减少动画元素数量或缩短动画时长。
Q 动画结束后元素会跳回原位怎么办?
A 设置
animation-fill-mode: forwards,动画结束后会保持在最后一帧的状态。默认值是 none,动画播放完就回到起始位置。5. 实战案例:纯CSS轮播图
这个案例展示了如何用纯CSS实现一个简单的图片轮播效果,无需JavaScript:
▶ 示例
HTML
📖 仅展示
<style>
.carousel {
width: 300px;
height: 200px;
overflow: hidden;
position: relative;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.carousel-inner {
display: flex;
width: 300%;
height: 100%;
animation: slide 9s infinite;
}
.carousel-item {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 24px;
font-weight: bold;
}
.item-1 { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
.item-2 { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); }
.item-3 { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); }
@keyframes slide {
0%, 30% { transform: translateX(0); }
33%, 63% { transform: translateX(-33.33%); }
66%, 96% { transform: translateX(-66.66%); }
100% { transform: translateX(0); }
}
</style>
<div class="carousel">
<div class="carousel-inner">
<div class="carousel-item item-1">幻灯片 1</div>
<div class="carousel-item item-2">幻灯片 2</div>
<div class="carousel-item item-3">幻灯片 3</div>
</div>
</div>
💡 实现原理: 使用
@keyframes 定义滑动动画,通过 translateX 控制轮播位置。每张幻灯片停留3秒,过渡0.3秒,循环播放。
📖 小节
@keyframes动画比transition更强大,可以定义多阶段的动画序列- 通过
animation属性的各个子属性,你可以控制动画的播放次数、方向、延迟、填充模式等 - 建议在动画中优先使用
transform和opacity以获得最佳性能 - 对于无限循环的动画(如加载旋转),记得用
infinite
📝 作业
- 创建一个"弹跳球"动画——球从空中掉落,触底反弹,逐渐减弱(使用 keyframes 的多阶段定义)。
- 制作一个"旋转加载器"——一个圆环不断旋转(提示:border + border-top-color + border-radius + animation)。
- 创建一个"渐入滑入"的页面:页面加载时,标题从上方滑入,段落从下方滑入,图片从左方滑入(使用不同的动画)。
- 制作一个"呼吸灯"按钮——按钮亮暗循环变化。