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>
▶ 试一试

也可以使用 fromto 关键字(等价于 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 内存。

为了获得流畅的动画,尽量使用以下属性:

✅ 性能好的属性:

⚠️ 性能一般的属性:

❌ 尽量避免动画的属性:


❓ 常见问题

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>
逻辑代码 42 行(超过 40 行限制,仅展示)
💡 实现原理: 使用 @keyframes 定义滑动动画,通过 translateX 控制轮播位置。每张幻灯片停留3秒,过渡0.3秒,循环播放。

📖 小节

📝 作业

  1. 创建一个"弹跳球"动画——球从空中掉落,触底反弹,逐渐减弱(使用 keyframes 的多阶段定义)。
  2. 制作一个"旋转加载器"——一个圆环不断旋转(提示:border + border-top-color + border-radius + animation)。
  3. 创建一个"渐入滑入"的页面:页面加载时,标题从上方滑入,段落从下方滑入,图片从左方滑入(使用不同的动画)。
  4. 制作一个"呼吸灯"按钮——按钮亮暗循环变化。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏