目录
- 引言:为什么使用 CSS 动画?
- 第一部分:CSS 过渡 - 基础入门
- 什么是过渡?
transition属性详解- 实战案例:按钮悬停效果
- 实战案例:卡片悬停效果
- 第二部分:CSS 关键帧动画 - 进阶核心
- 什么是关键帧动画?
@keyframes规则animation属性详解- 实战案例:加载动画
- 实战案例:文字打字机效果
- 实战案例:无限循环的滚动背景
- 第三部分:高级技巧与最佳实践
- 性能优化:
transform和opacity的优势 - 动画状态控制:
animation-play-state - 动画事件:
animationstart,animationend - 响应式动画与
prefers-reduced-motion
- 性能优化:
- 第四部分:综合案例:创建一个动态产品展示卡片
- 总结与资源推荐
引言:为什么使用 CSS 动画?
在 CSS3 出现之前,网页动画主要依赖于 JavaScript 或 Flash,它们通常更复杂、性能开销更大,且不易维护。

CSS 动画带来了革命性的变化:
- 简单易用:直接在 CSS 中定义,无需编写复杂的 JavaScript 逻辑。
- 性能卓越:现代浏览器对 CSS 动画进行了深度优化,可以利用 GPU 加速,使其运行流畅。
- 声明式:你只需描述动画的“起始”和“结束”状态(或几个关键状态),浏览器会自动计算中间过程。
- 节省资源:将动画逻辑从 JavaScript 中解放出来,减少了主线程的负担。
CSS 动画主要分为两大类:过渡 和 关键帧动画。
第一部分:CSS 过渡 - 基础入门
什么是过渡?
过渡是一种状态变化的动画,当元素的 CSS 属性值发生变化时(通过 hover 伪类或 JavaScript 改变样式),过渡可以让这个变化过程在一段时间内平滑地完成,而不是瞬间跳变。
transition 属性详解
transition 是一个简写属性,通常包含四个子属性:

.element {
/* property | duration | timing-function | delay */
transition: all 0.3s ease-in-out 0.1s;
}
-
transition-property: 指定哪个属性需要过渡效果。- 可以是具体属性名,如
width,background-color。 - 使用
all(默认)表示所有可过渡的属性都会发生变化。 - 使用
none表示没有属性过渡。
- 可以是具体属性名,如
-
transition-duration: 指定过渡效果持续的时间。- 单位是秒或毫秒,
5s或500ms。 - 如果值为
0,则表示没有过渡效果。
- 单位是秒或毫秒,
-
transition-timing-function: 指定过渡的速度曲线,即动画的节奏。ease: 默认值,慢速开始,然后变快,最后慢速结束。linear: 匀速运动。ease-in: 慢速开始。ease-out: 慢速结束。ease-in-out: 慢速开始和结束。cubic-bezier(): 自定义贝塞尔曲线,可以实现更复杂的动画节奏。steps(): 分步执行,常用于帧动画。
-
transition-delay: 指定过渡效果开始前的等待时间。
(图片来源网络,侵删)单位同样是秒或毫秒,可以为负值,表示动画立即开始,但会从动画过程的某个时间点开始。
实战案例:按钮悬停效果
这是最经典的过渡应用。
HTML:
<button class="btn-hover">悬停我</button>
CSS:
.btn-hover {
padding: 12px 24px;
font-size: 16px;
background-color: #3498db;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
/* 关键:设置默认的过渡属性 */
transition: background-color 0.3s ease, transform 0.3s ease;
}
.btn-hover:hover {
background-color: #2980b9;
transform: scale(1.05); /* 轻微放大 */
}
.btn-hover:active {
transform: scale(0.98); /* 点击时缩小 */
}
效果: 鼠标移入时,按钮背景色平滑变化,并轻微放大;鼠标移出时,效果平滑恢复,点击时也有一个反馈。
第二部分:CSS 关键帧动画 - 进阶核心
什么是关键帧动画?
关键帧动画用于实现更复杂的、不依赖于状态变化的动画,你可以定义一个动画在不同时间点的状态(关键帧),浏览器会根据这些关键帧生成完整的动画序列。
@keyframes 规则
@keyframes 用于定义动画的关键帧。
@keyframes animationName {
0% {
/* 动画开始时的样式 */
transform: translateX(0);
}
50% {
/* 动画进行到一半时的样式 */
transform: translateX(100px);
}
100% {
/* 动画结束时的样式 */
transform: translateX(0);
}
}
animationName: 给你的动画起一个名字。0%,50%,100%: 是动画的进度百分比,也叫关键帧。- 你也可以使用
from(等同于0%) 和to(等同于100%)。
animation 属性详解
animation 是一个简写属性,用于控制关键帧动画的播放。
.element {
/* name | duration | timing-function | delay | iteration-count | direction | fill-mode | play-state */
animation: slideIn 2s ease-in-out 0.5s infinite alternate;
}
-
animation-name: 指定要使用的@keyframes的名字。 -
animation-duration: 指定动画完成一次循环所需的时间。 -
animation-timing-function: 同过渡,定义动画的速度曲线。 -
animation-delay: 指定动画开始前的等待时间。 -
animation-iteration-count: 定义动画播放的次数。infinite: 无限循环。
-
animation-direction: 定义动画的播放方向。normal: 默认,从 0% 到 100% 正常播放。reverse: 从 100% 到 0% 反向播放。alternate: 动画交替播放,第一次正常,第二次反向,如此反复。alternate-reverse: 第一次反向,第二次正常,交替播放。
-
animation-fill-mode: 定义动画在执行前和执行后如何应用样式。none: 默认,动画执行前后不应用任何样式。forwards: 动画结束后,元素会保留最后一帧(100%)的样式。backwards: 动画开始前,元素会应用第一帧(0%)的样式(在delay期间生效)。both: 同时应用forwards和backwards的效果。
实战案例:加载动画
创建一个经典的旋转加载图标。
HTML:
<div class="loader"></div>
CSS:
.loader {
width: 50px;
height: 50px;
border: 5px solid #f3f3f3; /* 灰色背景 */
border-top: 5px solid #3498db; /* 蓝色顶部 */
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
效果: 一个圆形的加载图标会不停地旋转。
实战案例:文字打字机效果
模拟打字机逐字显示文字的效果。
HTML:
<p class="typewriter">Hello, CSS Animation!</p>
CSS:
.typewriter {
overflow: hidden; /* 隐藏超出部分 */
border-right: 2px solid orange; /* 光标效果 */
white-space: nowrap; /* 保持文本在一行 */
animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite;
}
/* 打字动画 */
@keyframes typing {
from { width: 0 }
to { width: 100% }
}
/* 光标闪烁动画 */
@keyframes blink-caret {
from, to { border-color: transparent }
50% { border-color: orange; }
}
效果: 文字会像打字一样逐个出现,光标会不断闪烁。
实战案例:无限循环的滚动背景
创建一个无缝滚动的背景图,常用于展示横幅或装饰。
HTML:
<div class="scrolling-background"></div>
CSS:
.scrolling-background {
width: 100%;
height: 200px;
background-image: url('your-image.jpg');
background-repeat: repeat-x; /* 水平平铺 */
animation: scroll 10s linear infinite;
}
@keyframes scroll {
0% {
background-position: 0 0;
}
100% {
background-position: 100% 0; /* 移动一个完整的背景宽度 */
}
}
效果: 背景图片会无限向左滚动。
第三部分:高级技巧与最佳实践
性能优化:transform 和 opacity 的优势
并非所有 CSS 属性都适合做动画,改变 width, height, margin, top, left 等属性会触发浏览器的重排,非常消耗性能。
应优先使用以下属性,它们可以利用 GPU 加速,触发重绘,性能更好:
transform: 用于移动、缩放、旋转、倾斜。opacity: 用于改变透明度。filter: 用于模糊、调整亮度等。
优化前:
.box {
width: 100px;
height: 100px;
background: red;
transition: width 0.5s, height 0.5s; /* 性能较差 */
}
.box:hover {
width: 150px;
height: 150px;
}
优化后:
.box {
width: 100px;
height: 100px;
background: red;
transition: transform 0.5s; /* 性能极佳 */
}
.box:hover {
transform: scale(1.5);
}
动画状态控制:animation-play-state
这个属性可以让你在动画运行时暂停或恢复它,通常与 JavaScript 配合使用。
running: 动画正在运行(默认)。paused: 动画已暂停。
CSS:
.paused-element {
animation: spin 2s linear infinite;
animation-play-state: paused; /* 默认暂停 */
}
JavaScript:
const element = document.querySelector('.paused-element');
element.addEventListener('click', () => {
// 切换播放状态
element.style.animationPlayState =
element.style.animationPlayState === 'paused' ? 'running' : 'paused';
});
动画事件
JavaScript 可以监听动画的生命周期事件。
animationstart: 动画开始时触发。animationend: 动画结束时触发。animationiteration: 每次动画循环一次时触发(仅在iteration-count大于 1 时有效)。
JavaScript 示例:
const element = document.querySelector('.loader');
element.addEventListener('animationend', () => {
alert('动画播放完成!');
});
响应式动画与 prefers-reduced-motion
这是一个重要的可访问性特性,有些用户(如前庭障碍患者)不希望看到剧烈的动画,我们可以通过媒体查询来检测用户的偏好,并相应地禁用或简化动画。
/* 默认情况下,应用动画 */
.animated-element {
animation: spin 2s linear infinite;
}
/* 如果用户在系统设置中选择了“减少动画”,则禁用动画 */
@media (prefers-reduced-motion: reduce) {
.animated-element {
animation: none; /* 或者替换为一个非常简单的动画 */
}
}
这是一个非常专业且贴心的做法,强烈推荐使用。
第四部分:综合案例:创建一个动态产品展示卡片
我们将结合过渡和关键帧动画,创建一个引人注目的产品卡片。
目标效果:
- 卡片有轻微的阴影和悬停放大效果(过渡)。
- 卡片内部有一个“热卖”标签,有闪烁动画(关键帧)。
- 卡片被加入购物车时,有一个飞入购物车的动画(关键帧 + JS)。
HTML:
<div class="product-card"> <div class="badge">热卖</div> <img src="https://via.placeholder.com/200" alt="产品图片"> <h3>超酷产品</h3> <p>¥99.00</p> <button class="add-to-cart">加入购物车</button> </div> <div class="cart-icon">🛒</div>
CSS:
/* 基础样式 */
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: #f0f0f0;
font-family: sans-serif;
}
.product-card {
width: 250px;
background: white;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
padding: 20px;
text-align: center;
position: relative;
transition: transform 0.3s ease, box-shadow 0.3s ease; /* 卡片悬停过渡 */
}
.product-card:hover {
transform: translateY(-10px) scale(1.02);
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
}
/* 热卖标签 */
.badge {
position: absolute;
top: 10px;
right: -30px;
background: #ff4757;
color: white;
padding: 5px 30px;
border-radius: 20px;
font-size: 12px;
animation: pulse 1.5s infinite; /* 关键帧动画 */
}
@keyframes pulse {
0% {
box-shadow: 0 0 0 0 rgba(255, 71, 87, 0.7);
}
70% {
box-shadow: 0 0 0 10px rgba(255, 71, 87, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(255, 71, 87, 0);
}
}
/* 购物车图标 */
.cart-icon {
position: fixed;
top: 20px;
right: 20px;
font-size: 30px;
cursor: pointer;
}
/* 飞入动画的初始状态 */
.flying-item {
position: fixed;
width: 50px;
height: 50px;
pointer-events: none;
z-index: 1000;
opacity: 0;
}
@keyframes flyToCart {
0% {
opacity: 1;
transform: translate(0, 0) scale(1);
}
100% {
opacity: 0;
transform: translate(var(--end-x), var(--end-y)) scale(0.2);
}
}
JavaScript:
document.querySelector('.add-to-cart').addEventListener('click', function(e) {
// 1. 克隆产品图片
const productCard = document.querySelector('.product-card');
const img = productCard.querySelector('img');
const flyingImg = img.cloneNode(true);
// 2. 设置克隆图片的初始位置和样式
const rect = img.getBoundingClientRect();
flyingImg.style.position = 'fixed';
flyingImg.style.left = rect.left + 'px';
flyingImg.style.top = rect.top + 'px';
flyingImg.style.width = rect.width + 'px';
flyingImg.style.height = rect.height + 'px';
flyingImg.classList.add('flying-item');
// 3. 添加到页面
document.body.appendChild(flyingImg);
// 4. 获取购物车图标的位置
const cartIcon = document.querySelector('.cart-icon');
const cartRect = cartIcon.getBoundingClientRect();
// 5. 计算动画的终点
const endX = cartRect.left - rect.left;
const endY = cartRect.top - rect.top;
flyingImg.style.setProperty('--end-x', `${endX}px`);
flyingImg.style.setProperty('--end-y', `${endY}px`);
// 6. 应用飞行动画
flyingImg.style.animation = 'flyToCart 0.8s ease-in-out forwards';
// 7. 动画结束后移除元素
flyingImg.addEventListener('animationend', () => {
flyingImg.remove();
// 可以在这里添加其他逻辑,比如更新购物车数量
alert('已添加到购物车!');
});
});
这个案例展示了如何将过渡、关键帧动画和 JavaScript 事件结合,创造出流畅且有趣的交互体验。
总结与资源推荐
- CSS 过渡:适合简单的状态变化,如
hover,语法简单,性能好。 - CSS 关键帧动画:适合复杂的、多步骤的动画,如加载、无限循环等。
- 性能是王道:优先使用
transform和opacity来创建动画。 - 可访问性很重要:使用
prefers-reduced-motion尊重用户的偏好。 - 组合使用:将 CSS 动画与 JavaScript 结合,可以实现更强大的交互控制。
资源推荐
- MDN Web Docs (权威文档):
- CSS Tricks (优秀教程博客):
- A Guide to CSS (包含大量动画文章)
- 动画工具:
- CSS Easing Animation Tool: 可视化贝塞尔曲线。
- Animista.net: 在线生成各种 CSS 动画效果。
- 灵感库:
- CodePen: 搜索 "CSS Animation" 可以找到海量的创意实例。
希望这份详尽的教程能帮助你从入门到精通 HTML5 & CSS3 动画!动手实践是最好的学习方式,祝你玩得开心!
