CSS动画
目录
一、核心概念与语法
1. @keyframes 关键帧
2. animation 属性
二、动画调速函数(animation-timing-function)
1. 预设值
2. 贝塞尔曲线
3. 步进函数(steps())
三、动画控制与交互
1. 暂停与恢复
2. JavaScript 控制
3.逐帧动画与精灵图
四、性能优化
五、实际应用示例
1. 淡入淡出效果
2. 旋转加载图标
3. 弹跳效果
六、兼容性与前缀
示例:走马灯
示例:全民出游季
CSS 动画允许通过定义关键帧(
@keyframes
)和动画属性(animation
)实现复杂的动态效果,相比transition
更灵活,支持多阶段控制和循环播放。
一、核心概念与语法
在 CSS 中,以 @
开头的语法称为 At-Rules(规则声明),用于定义 CSS 的元数据、条件逻辑、外部资源引入等高级功能。
1. @keyframes
关键帧
-
作用:定义动画的中间状态。
-
语法:
@keyframes 动画名称 {from { /* 初始状态 */ }to { /* 结束状态 */ }/* 或使用百分比 */0% { ... }50% { ... }100% { ... } }
-
示例:
@keyframes fadeIn {from { opacity: 0; }to { opacity: 1; } }@keyframes slideAndRotate {0% { transform: translateX(0) rotate(0); }50% { transform: translateX(200px) rotate(180deg); }100% { transform: translateX(0) rotate(360deg); } }
2. animation
属性
-
作用:将关键帧动画应用到元素。
-
子属性:
属性 作用 常用值 animation-name
指定关键帧名称 fadeIn
,slideAndRotate
animation-duration
动画持续时间 2s
,500ms
animation-timing-function
速度曲线 ease
(默认),linear
,ease-in-out
,cubic-bezier(0.4, 0, 0.2, 1)
animation-delay
动画延迟时间 1s
,0.5s
animation-iteration-count
播放次数 1
(默认),infinite
,3
animation-direction
播放方向 normal
(默认正向),reverse
(反向),alternate
(正反交替)animation-fill-mode
动画结束后的样式保留 none
(默认),forwards
(保持最后一帧),backwards
(应用第一帧)animation-play-state
控制播放状态 running
(默认),paused
(暂停) -
简写语法:
.element {animation: name duration timing-function delay iteration-count direction fill-mode play-state; }
示例:
.box {animation: fadeIn 2s ease-in-out 1s infinite alternate forwards; }
二、动画调速函数(animation-timing-function
)
1. 预设值
-
ease
:默认缓入缓出(先加速后减速)。 -
linear
:匀速。 -
ease-in
:缓入(逐渐加速)。 -
ease-out
:缓出(逐渐减速)。 -
ease-in-out
:缓入缓出。
2. 贝塞尔曲线
-
使用
cubic-bezier(x1, y1, x2, y2)
自定义速度曲线。
.box {animation-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55);
}
3. 步进函数(steps()
)
-
将动画拆分为固定步数播放,适合帧动画。
.box {animation-timing-function: steps(5, jump-start); /* 分 5 步跳跃播放 */ }
三、动画控制与交互
1. 暂停与恢复
-
通过
animation-play-state
控制:.box:hover {animation-play-state: paused; /* 悬停时暂停动画 */ }
2. JavaScript 控制
-
动态添加/移除动画类:
const box = document.querySelector('.box'); box.classList.add('fadeIn'); // 触发动画 box.style.animation = 'none'; // 停止动画
3.逐帧动画与精灵图
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>test</title><link rel="stylesheet" href="./iconfont/iconfont.css"><style>.box {margin: 100px auto;width: 1000px;}.people {width: 140px;height: 140px;background-image: url(./res/run.png);animation: run 1s steps(12) infinite,move 4s linear infinite;}@keyframes run {from {background-position: 0 0;}to {background-position: -1680px 0;}}@keyframes move {0% {transform: translate(0) scaleX(1);}50% {transform: translate(800px) scaleX(1);}50.1% {transform: translate(800px) scaleX(-1);}100% {transform: translate(0) scaleX(-1);}}</style>
</head>
<body><div class="box"><div class="people"></div></div></body>
</html>
四、性能优化
-
优先使用
transform
和opacity
-
这些属性由 GPU 加速,避免触发重排(如
width
、margin
)。
-
-
减少动画数量
-
同时运行过多动画可能导致页面卡顿。
-
-
使用
will-change
提示浏览器.box {will-change: transform, opacity; /* 提前告知浏览器可能变化的属性 */ }
五、实际应用示例
1. 淡入淡出效果
@keyframes fadeInOut {0%, 100% { opacity: 0; }50% { opacity: 1; }
}.element {animation: fadeInOut 3s ease-in-out infinite;
}
2. 旋转加载图标
@keyframes spin {from { transform: rotate(0deg); }to { transform: rotate(360deg); }
}.loader {animation: spin 1s linear infinite;
}
3. 弹跳效果
@keyframes bounce {0%, 100% { transform: translateY(0); }50% { transform: translateY(-30px); }
}.button {animation: bounce 1s ease-in-out infinite;
}
六、兼容性与前缀
-
现代浏览器:无需前缀(Chrome 43+、Firefox 16+、Safari 9+)。
-
旧版浏览器:需添加
-webkit-
前缀:@-webkit-keyframes fadeIn { ... } .box {-webkit-animation: fadeIn 2s; }
示例:走马灯
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>test</title><link rel="stylesheet" href="./iconfont/iconfont.css"><style>* {margin: 0;padding: 0;box-sizing: border-box;}li {list-style: none;}a {text-decoration: none;color: #fff;}.box {margin: 100px auto;width: 300px;height: 50px;overflow: hidden;}.box ul {display: flex;animation: move 7s linear infinite;}.box:hover ul {animation-play-state: paused;}@keyframes move {from {transform: translateX(0);}to {transform: translateX(-700px);}}.box img {width: 100px;}</style>
</head>
<body><div class="box"><ul><li><img src="./res/1.jpg" alt=""></li><li><img src="./res/2.jpg" alt=""></li><li><img src="./res/3.jpg" alt=""></li><li><img src="./res/4.jpg" alt=""></li><li><img src="./res/5.jpg" alt=""></li><li><img src="./res/6.jpg" alt=""></li><li><img src="./res/7.jpg" alt=""></li><!-- 填补显示区域的空白 --><li><img src="./res/1.jpg" alt=""></li><li><img src="./res/2.jpg" alt=""></li><li><img src="./res/3.jpg" alt=""></li></ul></div></body>
</html>
示例:全民出游季
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>test</title><link rel="stylesheet" href="./iconfont/iconfont.css"><style>* {margin: 0;padding: 0;box-sizing: border-box;}li {list-style: none;}a {text-decoration: none;color: #fff;}html {height: 100%; }body {height: 100%;background: url(./res/images/f1_1.jpg) no-repeat center 0 / cover; }.cover {width: 100%;height: 100%; position: relative;}.cover div {position: absolute;}.title {top: 50%;left: 50%;transform: translate(-50%,-50%);animation: show 1s;}@keyframes show {0% {transform: translate(-50%,-50%) scale(1);}20% {transform: translate(-50%,-50%) scale(0.3);}50% {transform: translate(-50%,-50%) scale(1.7);}80% {transform: translate(-50%,-50%) scale(0.8);}100% {transform: translate(-50%,-50%) scale(1);}}.label {bottom: 10%;left: 50%;transform: translate(-50%);}.label ul {display: flex;justify-content: space-between;}.label ul img {width: 100px;margin: 0 85px;animation: bounce .8s ease-in infinite alternate;}.label ul li:nth-child(2) img {animation: bounce .8s 0.3s ease-in infinite alternate;}.label ul li:nth-child(3) img {animation: bounce .8s 0.6s ease-in infinite alternate;}.label ul li:nth-child(4) img {animation: bounce .8s 0.9s ease-in infinite alternate;}@keyframes bounce {from {transform: translateY(0);}to {transform: translateY(30px);}}.cloud {position: relative;left: 50%;}.cloud img:nth-child(1) {top: 20px;margin-left: -200px;}.cloud img:nth-child(2) {top: 100px;margin-left: 400px;}.cloud img:nth-child(3) {top: 180px;margin-left: -500px;}.cloud img {position: absolute;animation: move 2s linear infinite alternate;}@keyframes move {to {transform: translate(-50px);}}.lu {top: 15%;left: 60%;}.san {top: 15%;left: 25%;animation: float 1.5s linear infinite alternate;}@keyframes float {to {transform: translateY(50px);}}</style>
</head>
<body><div class="cover"><div class="cloud"><img src="./res/images/yun1.png" alt=""><img src="./res/images/yun2.png" alt=""><img src="./res/images/yun3.png" alt=""></div> <div class="lu"><img src="./res/images/lu.png" alt=""></div> <div class="san"><img src="./res/images/san.png" alt=""></div><div class="label"><ul><li><img src="./res/images/1.png" alt=""></li><li><img src="./res/images/2.png" alt=""></li><li><img src="./res/images/3.png" alt=""></li><li><img src="./res/images/4.png" alt=""></li></ul></div><div class="title"><img src="./res/images/font1.png" alt=""></div></div></body>
</html>