第29篇:CSS动画
学习目标
- 掌握
@keyframes关键帧的定义方式 - 理解
animation所有子属性的含义和用法 - 能够编写常见的 UI 动画:加载、提示、微交互
- 了解 CSS 动画与 JavaScript 动画的选择场景
核心知识点
1. @keyframes — 定义关键帧
关键帧动画由一系列"时间点"的样式状态组成,浏览器自动补间过渡。
/* 基本语法 */@keyframesfadeIn{from{opacity:0;}/* 0% */to{opacity:1;}/* 100% */}/* 多关键帧 */@keyframesbounce{0%{transform:translateY(0);}40%{transform:translateY(-30px);}60%{transform:translateY(-15px);}100%{transform:translateY(0);}}关键帧百分比:
0%或from— 动画开始100%或to— 动画结束- 中间任意百分比 — 自定义时间点
2. animation 属性大全
| 属性 | 含义 | 常用值 |
|---|---|---|
animation-name | 引用 @keyframes | fadeIn、bounce |
animation-duration | 动画时长 | 0.5s、2s |
animation-timing-function | 速度曲线 | ease、linear、ease-in-out |
animation-delay | 延迟开始 | 1s、-0.5s(负值表示已进行一半) |
animation-iteration-count | 播放次数 | 1、3、infinite |
animation-direction | 播放方向 | normal、reverse、alternate |
animation-fill-mode | 动画前后状态 | none、forwards、backwards、both |
animation-play-state | 播放/暂停 | running、paused |
简写语法
.element{animation:bounce 1s ease-in-out 0.5s infinite alternate;/* name duration timing-function delay iteration-count direction */}animation-fill-mode 详解
/* 动画结束后保持最后一帧 */.box{animation:slideIn 0.5s forwards;}/* 动画开始前应用第一帧(解决延迟期间的空白) */.box{animation:fadeIn 1s 2s backwards;}/* 同时应用 forwards 和 backwards */.box{animation:slideIn 0.5s both;}| 值 | 开始前 | 结束后 |
|---|---|---|
none | 默认样式 | 默认样式 |
forwards | 默认样式 | 最后一帧 |
backwards | 第一帧 | 默认样式 |
both | 第一帧 | 最后一帧 |
animation-direction
animation-direction:normal;/* 正向播放 */animation-direction:reverse;/* 反向播放 */animation-direction:alternate;/* 正→反→正→反... */animation-direction:alternate-reverse;/* 反→正→反→正... */3. 实战:常见动画模式
淡入
@keyframesfadeIn{from{opacity:0;transform:translateY(20px);}to{opacity:1;transform:translateY(0);}}.card{animation:fadeIn 0.5s ease-out;}脉冲(心跳效果)
@keyframespulse{0%, 100%{transform:scale(1);}50%{transform:scale(1.1);}}.heart{animation:pulse 1s ease-in-out infinite;}旋转加载
@keyframesspin{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}.spinner{width:40px;height:40px;border:3px solid #e5e7eb;border-top-color:#4a90d9;border-radius:50%;animation:spin 0.8s linear infinite;}抖动(错误提示)
@keyframesshake{0%, 100%{transform:translateX(0);}20%{transform:translateX(-10px);}40%{transform:translateX(10px);}60%{transform:translateX(-5px);}80%{transform:translateX(5px);}}.input-error{animation:shake 0.4s ease-in-out;}呼吸灯
@keyframesbreathe{0%, 100%{opacity:0.4;transform:scale(0.9);}50%{opacity:1;transform:scale(1.1);}}.dot{animation:breathe 2s ease-in-out infinite;}4. 多动画组合
一个元素可以同时应用多个动画:
.element{animation:fadeIn 0.5s ease-out,slideUp 0.5s ease-out 0.2s both;}5. 用 JS 控制动画
// 暂停/播放constel=document.querySelector('.spinner');el.style.animationPlayState='paused';el.style.animationPlayState='running';// 动态添加动画类document.querySelector('.btn').addEventListener('click',()=>{el.classList.add('animate-spin');// 动画结束后移除类el.addEventListener('animationend',()=>{el.classList.remove('animate-spin');},{once:true});});6. 动画性能优化
优先使用这些属性(触发 GPU 合成,不引起重排):
transform(位移、旋转、缩放)opacity
避免动画化这些属性(触发重排,性能差):
width、height、top、left、margin、paddingborder-width
will-change 提示
.animated-element{will-change:transform,opacity;}不要滥用
will-change,动画结束后应移除,否则占用 GPU 内存。
减少动画(prefers-reduced-motion)
@media(prefers-reduced-motion:reduce){*, *::before, *::after{animation-duration:0.01ms!important;animation-iteration-count:1!important;transition-duration:0.01ms!important;}}7. transition vs animation 对比
| 特性 | transition | animation |
|---|---|---|
| 触发方式 | 需要状态变化(如 hover) | 自动播放,可循环 |
| 复杂度 | 两个状态之间的过渡 | 多关键帧,任意状态数 |
| 循环 | 不能 | 可以 infinite |
| 方向 | A → B | A → B → C → D |
| 适用 | 悬停、切换等交互反馈 | 加载、装饰性动画 |
动手练习
练习1:打字机效果
实现文字逐个显示的打字机动画。提示:用steps()时间函数配合宽度动画。
@keyframestyping{from{width:0;}to{width:100%;}}.typing{overflow:hidden;white-space:nowrap;animation:typing 3ssteps(20)forwards;}练习2:交错淡入
一组卡片依次淡入,每张延迟 0.1s。提示:用:nth-child(n)设置不同animation-delay。
练习3:环形加载器
用纯 CSS 创建一个三个圆点依次放大缩小的加载动画。
常见误区 ⚠️
| 误区 | 正确做法 |
|---|---|
| 动画化 width/height/top/left | 用 transform 和 opacity,性能高 10 倍 |
| 忘记 forwards 导致动画跳回初始状态 | 需要保持结束状态时加animation-fill-mode: forwards |
| 无限循环动画滥用 will-change | 仅在必要时使用,结束后移除 |
| 忽略 prefers-reduced-motion | 必须做无障碍降级 |
| animation-delay 用正数实现交错 | 用负数更高效:-0.1s表示从 10% 开始 |
速查卡片 📋
/* 定义 */@keyframesname{0%{...}50%{...}100%{...}}/* 应用 */animation:name 1s ease 0s 1 normal forwards;animation:name duration timing-function delay iteration-count direction fill-mode;/* 常用组合 */animation:fadeIn 0.5s ease-out forwards;animation:spin 0.8s linear infinite;animation:pulse 1.5s ease-in-out infinite alternate;animation:bounce 0.5s ease-in-out 3;/* 性能 */will-change:transform,opacity;/* 提示浏览器优化 *//* 无障碍 */@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important;}}扩展阅读
- MDN: CSS 动画
- MDN: @keyframes
- Animate.css(常用动画库)
- CSS Tricks: Animation