CSS 动画是实现页面动态效果的核心技术之一,无需依赖 JavaScript,即可完成元素的位移、旋转、缩放、透明度变化等交互效果。其核心由两部分组成:
@keyframes
关键帧定义 (规定动画 "做什么")和 动画属性(规定动画 "怎么播")。本文将从基础概念到实战案例,全面拆解 CSS 动画的核心知识点
一、核心基础:@keyframes
关键帧
@keyframes
是 CSS 动画的 "剧本",用于定义动画在不同时间点的状态(即 "关键帧")。浏览器会自动计算关键帧之间的过渡效果,实现平滑动画。
1. 语法规则
css
/* 格式:@keyframes + 动画名称 { 关键帧列表 } */
@keyframes 动画名称 {
/* 方式1:使用 from/to(对应 0%/100%,适合简单的"开始-结束"动画) */
from { /* 动画开始时的样式 */ }
to { /* 动画结束时的样式 */ }
/* 方式2:使用百分比(适合多步骤动画,0%=开始,100%=结束,中间可加任意百分比) */
0% { /* 初始状态 */ }
50% { /* 动画中间状态 */ }
100% { /* 结束状态 */ }
}
2. 关键特性
- 动画名称 :自定义(如
slide-in
、rotate-spin
),需与后续animation-name
对应。 - 关键帧百分比:可任意拆分(如 0%、20%、80%、100%),百分比顺序不影响执行(浏览器会按从小到大排序)。
- 支持的样式 :并非所有 CSS 属性都能动画,仅支持 "可插值" 属性(如
transform
、opacity
、width
、background-color
),不支持display: none
/block
、visibility
(会跳变) 。
3. 基础示例:简单位移动画
css
/* 定义关键帧:元素从左侧-100px 移到 0px */
@keyframes slideIn {
from { transform: translateX(-100px); opacity: 0; } /* 开始:左移+透明 */
to { transform: translateX(0); opacity: 1; } /* 结束:复位+不透明 */
}
/* 应用到元素 */
.box {
width: 100px;
height: 100px;
background: #4285F4;
/* 必须指定动画名称和时长(否则动画不生效) */
animation-name: slideIn; /* 关联关键帧 */
animation-duration: 1s; /* 动画总时长 */
}
二、动画核心属性:控制 "播放规则"
定义好 @keyframes
后,需通过 动画属性 控制播放逻辑(如时长、次数、延迟、速度曲线等)。CSS 提供了 8 个独立属性,以及 1 个简写属性 animation
,下面逐一拆解。
1. 8 个独立动画属性详解
属性名 | 作用 | 取值范围 | 默认值 |
---|---|---|---|
animation-name |
关联 @keyframes 定义的动画名 |
自定义名称 / none (取消动画) |
none |
animation-duration |
动画总时长 | 时间值(如 1s 、500ms ),不可为 0 |
0s (无动画) |
animation-timing-function |
动画速度曲线(缓动效果) | 预定义值 / 贝塞尔曲线 / 阶梯函数 | ease |
animation-delay |
动画延迟多久开始 | 时间值(正:延迟;负:提前开始) | 0s |
animation-iteration-count |
动画重复次数 | 数字(如 3 ) / infinite (无限循环) |
1 |
animation-direction |
动画重复时的方向 | normal /reverse /alternate /alternate-reverse |
normal |
animation-fill-mode |
动画结束 / 延迟时的元素状态 | none /forwards /backwards /both |
none |
animation-play-state |
控制动画播放 / 暂停 | running (播放) / paused (暂停) |
running |
重点属性深度解析
以下是最容易混淆或高频使用的属性,需结合示例理解:
(1)animation-timing-function
:速度曲线
控制动画在 "关键帧之间" 的过渡速度,决定动画的 "流畅感"。
取值 | 效果描述 | 适用场景 |
---|---|---|
linear |
匀速(速度不变) | 机械运动(如时钟旋转) |
ease |
默认:慢→快→慢(中间加速) | 通用交互(如按钮 hover) |
ease-in |
慢开始(加速) | 入场动画(如元素从下往上) |
ease-out |
慢结束(减速) | 退场动画(如元素消失) |
ease-in-out |
慢开始 + 慢结束(对称加速) | 平滑往复动画(如弹窗切换) |
cubic-bezier(n,n,n,n) |
自定义贝塞尔曲线(4 个参数,0~1) | 精细控制(如拟物动画) |
steps(n, [start/end]) |
阶梯动画(分 n 步完成,无过渡) | 帧动画(如精灵图、数字跳动) |
示例:阶梯动画(数字从 1 跳到 5)
css
@keyframes count {
0% { content: "1"; }
25% { content: "2"; }
50% { content: "3"; }
75% { content: "4"; }
100% { content: "5"; }
}
.count::after {
content: "1";
animation: count 2s steps(4) infinite; /* steps(4):分4步,每步0.5s */
}
(2)animation-fill-mode
:动画前后状态
控制元素在 动画延迟开始前 (animation-delay
期间)和 动画结束后 的样式状态,解决 "动画结束后元素复位" 的问题。
取值 | 延迟前状态(delay 期间) | 动画结束后状态 | 核心场景 |
---|---|---|---|
none |
元素默认样式 | 恢复元素默认样式 | 动画后无需保留状态 |
forwards |
元素默认样式 | 保持 100% 关键帧样式 | 动画后固定在结束状态(如弹窗停留) |
backwards |
保持 0% 关键帧样式 | 恢复元素默认样式 | 延迟期间显示初始状态(如提前透明) |
both |
保持 0% 关键帧样式 | 保持 100% 关键帧样式 | 延迟 + 结束都需保留状态(如入场后固定) |
示例:动画结束后不复位
css
.box {
animation: slideIn 1s forwards; /* 结束后保持 100% 状态(不透明+复位) */
}
(3)animation-direction
:动画方向
控制动画重复时的播放方向,尤其适合 "往复动画"(如左右摇摆)。
取值 | 效果描述 |
---|---|
normal |
每次都从 0%→100%(正向) |
reverse |
每次都从 100%→0%(反向) |
alternate |
奇数次正向(0%→100%),偶数次反向(100%→0%) |
alternate-reverse |
奇数次反向(100%→0%),偶数次正向(0%→100%) |
示例:左右摇摆动画
css
@keyframes swing {
0% { transform: translateX(-50px); }
100% { transform: translateX(50px); }
}
.box {
animation: swing 1s ease-in-out infinite alternate; /* 来回摇摆 */
}
2. animation
简写属性
为简化代码,可将 8 个独立属性合并为 animation
简写,顺序有严格要求(部分属性可省略):
语法顺序
css
animation: 动画名 时长 速度曲线 延迟 重复次数 方向 填充模式 播放状态;
规则说明
- 必须包含的两个属性:
animation-name
和animation-duration
(否则动画不生效)。 - 可选属性:其他 6 个属性可按顺序省略(未写则用默认值)。
- 延迟与时长的区别:先写时长,后写延迟(均为时间值,靠顺序区分)。
示例:简写对比
css
/* 分开写 */
.box {
animation-name: slideIn;
animation-duration: 1s;
animation-timing-function: ease;
animation-delay: 0.5s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
/* 简写(效果完全一致) */
.box {
animation: slideIn 1s ease 0.5s infinite alternate;
}
三、实战案例:3 个高频动画场景
理论结合实践,以下是项目中常用的动画案例,可直接复用。
案例 1:加载旋转动画(无限循环)
css
/* 关键帧:360度旋转 */
@keyframes spin {
to { transform: rotate(360deg); } /* 0% 可省略(默认元素初始状态) */
}
/* 加载图标样式 */
.loader {
width: 40px;
height: 40px;
border: 4px solid #eee;
border-top-color: #4285F4; /* 顶部边框变色,模拟旋转感 */
border-radius: 50%; /* 圆形 */
/* 动画:旋转 1s 匀速 无限循环 */
animation: spin 1s linear infinite;
}
案例 2:hover 悬浮放大 + 阴影动画
css
/* 关键帧:放大+加阴影 */
@keyframes hoverScale {
to {
transform: scale(1.05); /* 放大5% */
box-shadow: 0 4px 20px rgba(0,0,0,0.1); /* 增加阴影 */
}
}
/* 按钮样式 */
.btn {
padding: 8px 16px;
border: none;
background: #4285F4;
color: white;
border-radius: 4px;
transition: all 0.3s; /* 过渡(可选,与动画互补) */
/* 初始:动画暂停;hover时播放 */
animation: hoverScale 0.3s forwards paused;
}
/* hover 触发动画 */
.btn:hover {
animation-play-state: running; /* 播放动画 */
}
案例 3:多步骤动画(位移 + 旋转 + 变色)
css
/* 关键帧:3步动画 */
@keyframes multiStep {
0% {
transform: translateX(0) rotate(0);
background: #4285F4;
}
50% {
transform: translateX(200px) rotate(180deg);
background: #EA4335;
}
100% {
transform: translateX(400px) rotate(360deg);
background: #34A853;
}
}
.box {
width: 100px;
height: 100px;
border-radius: 8px;
/* 动画:3步动画 3s 缓动 延迟0.5s 播放1次 正向 结束后固定状态 */
animation: multiStep 3s ease 0.5s 1 normal forwards;
}
四、常见问题与解决方案
新手使用 CSS 动画时,常遇到 "动画不生效" 或 "效果异常",以下是高频问题汇总:
问题现象 | 原因分析 | 解决方案 |
---|---|---|
动画完全不播放 | 1. 未设置 animation-duration (默认 0s) 2. animation-name 与 @keyframes 名称不匹配 |
1. 必须指定 duration (如 1s ) 2. 检查名称拼写(区分大小写) |
动画结束后立即复位 | animation-fill-mode 未设置为 forwards 或 both |
添加 forwards (保持结束状态) |
transform 动画无效果 |
元素未触发 "层叠上下文",或父元素有 overflow: hidden |
1. 加 will-change: transform 或 position: relative 2. 检查父元素 overflow 设置 |
动画卡顿、掉帧 | 1. 使用了会触发重排的属性(如 width 、margin ) 2. 动画元素过多 |
1. 优先用 transform 和 opacity (浏览器优化好) 2. 加 will-change: transform 提前通知浏览器优化 |
延迟期间元素样式异常 | animation-fill-mode 未设置为 backwards 或 both |
添加 backwards (延迟时显示 0% 状态) |
五、性能优化技巧
CSS 动画虽轻量,但不合理使用会导致页面卡顿,尤其在移动端。以下是关键优化点:
- 优先使用
transform
和opacity
浏览器对这两个属性的动画会开启 "合成层" 优化,避免触发页面重排(reflow)和重绘(repaint),仅需合成(composite),性能最优。
❌ 避免动画:width
、height
、margin
、top
、left
(会触发重排)。 - 使用
will-change
提前优化
告诉浏览器 "该元素即将动画",让浏览器提前分配资源,减少动画启动时的卡顿:
css
.box {
will-change: transform, opacity; /* 提前声明要动画的属性 */
}
⚠️ 注意:不要滥用 will-change
(如给所有元素加),会占用额外内存。
3. 减少动画元素数量
同时动画的元素越多,性能压力越大,建议控制在 5 个以内(复杂场景需用 JS 节流 / 防抖)。
4. 避免过度使用 infinite
循环动画
无限循环动画会持续占用主线程,非必要时可通过 JS 控制播放 / 暂停(如滚动到视图时播放)。
六、兼容性说明
现代浏览器(Chrome、Firefox、Safari 10+、Edge)均支持标准 CSS 动画属性,无需前缀。但对于 Safari 9 及以下版本 ,需添加 -webkit-
前缀:
css
/* 关键帧前缀 */
@-webkit-keyframes slideIn {
from { -webkit-transform: translateX(-100px); }
to { -webkit-transform: translateX(0); }
}
/* 属性前缀 */
.box {
-webkit-animation-name: slideIn;
-webkit-animation-duration: 1s;
/* 简写前缀 */
-webkit-animation: slideIn 1s ease;
}
可通过 caniuse 查看最新兼容性数据。
七、前端动画库
一、通用动画库(全能型)
1. GreenSock (GSAP)
- 特点:业界公认的高性能动画库,支持 CSS、SVG、Canvas、WebGL 等几乎所有前端元素,可实现时间线控制、贝塞尔曲线、滚动触发等复杂逻辑。
- 优势:性能极强(尤其在移动端),支持动画暂停 / 重播 / 反转,API 灵活,兼容性好(IE9+)。
- 适用场景:复杂交互动画(如页面过渡、游戏动效、数据可视化动效)。
示例
js
// 基础动画:元素从左移到右并淡入
gsap.to(".box", {
x: 300,
opacity: 1,
duration: 1,
ease: "power2.out"
});
官网: greensock.com
2. Framer Motion
- 特点:React 生态最流行的动画库,基于 React 组件设计,支持声明式动画,内置手势(拖拽、缩放)和物理动效。
- 优势:与 React 无缝集成,API 简洁,支持动画组合和变体(Variants)复用。
- 适用场景:React 项目的 UI 交互(如组件切换、列表动效、手势反馈)。
示例
js
// React组件动画
import { motion } from "framer-motion";
const Box = () => (
<motion.div
initial={{ x: -100, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
transition={{ duration: 0.5 }}
/>
);
二、CSS 动画库(轻量基础)
1. Animate.css
- 特点:最经典的 CSS 类动画库,提供预设的基础动画(如淡入、滑动、旋转),直接通过添加类名使用。
- 优势:零配置、轻量(~70KB)、支持自定义(可通过工具生成子集)。
- 适用场景:快速添加简单动效(如按钮 hover、元素入场)。
示例
html
<!-- 直接添加类名 -->
<div class="animate__animated animate__bounce"> bounce动画 </div>
官网 :animate.style
2. AnimXYZ
- 特点:基于 CSS 变量的动画库,支持通过类名动态组合动画参数(如方向、距离、时长),高度可定制。
- 优势:无需写 CSS,通过 HTML 类名控制动画细节,适合快速迭代。
示例
html
<!-- 向右移动20px,持续0.5s,缓入缓出 -->
<div class="xyz-in xyz-translate-x-20 xyz-duration-500 xyz-ease-in-out"></div>
官网 :animxyz.com
三、3D / 物理仿真动画库
1. Three.js
- 特点:基于 WebGL 的 3D 动画库,可创建 3D 模型、场景、光照和相机,实现 3D 旋转、缩放、物理碰撞等效果。
- 优势:功能全面,社区活跃,支持加载 3D 模型(如 GLB、OBJ)。
- 适用场景:3D 可视化(如产品展示、数据 3D 图表、小游戏)。
官网 :threejs.org
2. Matter.js
- 特点:2D 物理引擎库,支持重力、碰撞、摩擦、关节约束等物理效果,可模拟现实世界运动。
- 优势:轻量(~100KB),API 简单,适合实现拖拽碰撞、堆叠等效果。
- 适用场景:物理交互动效(如拖拽元素碰撞、物体掉落动画)。
官网: brm.io/matter-js
四、SVG/Canvas 动画库
1. Lottie
- 特点:由 Airbnb 开发,支持将 AE(After Effects)动画导出为 JSON,通过前端解析播放,完美还原 AE 动效。
- 优势:矢量动画(无损缩放),体积小,支持交互控制(暂停、反转)。
- 适用场景:复杂矢量动画(如 LOGO 动效、引导页动画、图标动效)。
示例:
html
<script src="lottie.js"></script>
<div id="animation-container"></div>
<script>
lottie.loadAnimation({
container: document.getElementById('animation-container'),
path: 'animation.json', // AE导出的JSON
loop: true,
autoplay: true
});
</script>
官网 :lottiefiles.com
2. Vivus
- 特点:专注于 SVG 路径动画,模拟 "手绘" 效果(路径逐帧绘制)。
- 优势:轻量(~15KB),支持自定义绘制速度、延迟、方向。
- 适用场景:SVG 图标绘制动画、手写文字效果。
官网 :maxwellito.github.io/vivus
五、交互反馈动画库
1. TweenMax(GSAP 核心模块)
- 特点:GSAP 的基础模块,专注于元素补间动画,支持时间线(Timeline)控制多个动画的顺序和叠加。
- 优势:比原生 CSS 动画性能更好,尤其在复杂序列动画中。
- 适用场景:需要精确控制时序的动画(如多元素分步入场)。
2. React Spring
- 特点:基于物理弹簧模型的 React 动画库,动画效果更贴近自然(如弹性、惯性)。
- 优势:声明式 API,适合模拟真实物理动效(如弹性缩放、惯性滑动)。
示例
js
import { useSpring, animated } from 'react-spring';
const AnimatedDiv = () => {
const props = useSpring({
from: { opacity: 0 },
to: { opacity: 1 },
config: { tension: 100 } // 弹簧张力
});
return <animated.div style={props} />;
};
官网 :react-spring.dev