7.1 CSS 动效基础
CSS 动效是前端交互反馈与视觉体验的核心实现方式,基于浏览器合成线程原生渲染,具备 GPU 加速能力,性能远优于 JavaScript 动画。CSS 动效体系分为过渡动画与关键帧动画两大核心类型,配合原生动画事件实现动画生命周期的回调控制,能够覆盖状态反馈、入场出场、循环装饰等绝大多数动效场景,是构建流畅交互体验的基础。
7.1.1 transition 过渡动画
一、核心原理
过渡动画是状态驱动的补间动画,针对元素的两个状态(默认态与 hover 态、类名切换态等),在状态变化时自动计算中间帧,实现属性的平滑过渡。
它是最简单的 CSS 动效形式,适合交互触发的状态变化反馈。
二、核心属性
transition是简写属性,包含四个子属性,按顺序为:属性名、时长、缓动函数、延迟时间。
属性 | 说明 | 取值示例 |
transition-property | 指定应用过渡的 CSS 属性,all表示所有可过渡属性 | all、opacity、transform |
transition-duration | 过渡持续时间,单位秒(s)或毫秒(ms) | 0.3s、300ms |
transition-timing-function | 过渡缓动曲线,控制动画的速度变化 | ease、linear、ease-in-out、cubic-bezier(0.4, 0, 0.2, 1) |
transition-delay | 过渡延迟触发时间,单位秒或毫秒 | 0s、100ms |
三、缓动函数详解
缓动函数决定动画的运动感,是动效自然度的核心:
- linear:匀速线性运动,适合匀速旋转、位移动画
- ease:默认值,慢-快-慢,自然的运动感,通用场景
- ease-in:慢入快出,加速运动,适合元素出场、下落动画
- ease-out:快入慢出,减速运动,适合元素入场、停止动画
- ease-in-out:慢入慢出,两端平缓,适合悬停切换、来回过渡
- cubic-bezier(x1,y1,x2,y2):自定义贝塞尔曲线,精准控制运动曲线
四、基础示例
/* 按钮悬停过渡:所有属性 0.3 秒缓动过渡 */ .btn { background: #1677ff; transform: scale(1); transition: all 0.3s ease; } .btn:hover { background: #4096ff; transform: scale(1.05); }五、特点与边界
- 优势:实现简单,声明式配置,性能优异,状态切换时自动反向过渡
- 局限:仅支持两个状态之间的过渡,无法控制中间帧;无法主动播放,必须依赖状态触发;部分属性不可过渡(如display、float)
- 最佳实践:优先使用transform和opacity实现动效,触发 GPU 合成,避免重排重绘,性能最优;避免使用all,指定具体属性减少性能开销
7.1.2 animation 关键帧动画
一、核心原理
关键帧动画通过@keyframes规则定义动画过程中的多个关键帧状态,浏览器自动补全中间帧,支持多阶段、循环、反向等复杂动画效果,无需状态触发即可独立播放,是复杂 CSS 动效的标准实现方式。
二、核心属性
animation是简写属性,包含 8 个子属性,完整控制动画的全生命周期。
属性 | 说明 | 取值示例 |
animation-name | 绑定的 @keyframes 关键帧名称 | fadeIn |
animation-duration | 单次动画持续时间 | 1s |
animation-timing-function | 单帧间的缓动函数 | ease-out |
animation-delay | 动画延迟播放时间 | 0.2s |
animation-iteration-count | 动画播放次数 | 1、infinite(无限循环) |
animation-direction | 动画播放方向 | normal(正向)、reverse(反向)、alternate(交替往返) |
animation-fill-mode | 动画填充模式,控制动画前后的状态 | none、forwards(停在结束帧)、backwards(提前应用起始帧)、both |
animation-play-state | 动画播放状态 | running(运行)、paused(暂停) |
三、@keyframes 定义方式
支持两种关键帧定义方式:
- from / to:两帧动画,等价于 0% 和 100%
- 百分比:多帧动画,定义任意百分比位置的状态
/* 淡入上移动画 */ @keyframes fadeInUp { 0% { opacity: 0; transform: translateY(20px); } 100% { opacity: 1; transform: translateY(0); } } /* 呼吸动画:无限循环交替 */ @keyframes breathe { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } /* 应用动画 */ .fade-in { animation: fadeInUp 0.5s ease-out forwards; } .breathe { animation: breathe 2s ease-in-out infinite alternate; }四、与 transition 的核心对比
对比维度 | transition 过渡 | animation 关键帧 |
状态数量 | 仅两个状态(起始-结束) | 支持任意多个关键帧状态 |
触发方式 | 依赖状态变化触发,无法主动播放 | 可自动播放,也可通过类名控制 |
循环能力 | 不支持循环,仅往返过渡 | 支持任意次数循环、无限循环 |
中间控制 | 无法控制中间过程 | 可精准控制每一帧的状态 |
事件回调 | 单次过渡对应一次事件 | 支持帧迭代、结束等多种事件 |
适用场景 | 交互状态反馈、悬停切换 | 复杂动画、入场出场、循环装饰、加载动效 |
五、fill-mode 重点说明
animation-fill-mode是最容易被忽略的核心属性,决定动画播放前后元素的状态:
- none:默认值,动画开始前和结束后都保持元素原有样式
- forwards:动画结束后,保持最后一帧的状态,是入场动画最常用的配置
- backwards:动画延迟期间,提前应用第一帧的状态,避免动画开始前的跳变
- both:同时应用 forwards 和 backwards 的效果
7.1.3 动画事件:transitionend、animationend
CSS 动画原生提供生命周期事件,用于监听动画的开始、结束、迭代等节点,实现动画与业务逻辑的联动,是链式动画、状态切换、入场出场流程控制的核心。
一、transitionend 事件
触发时机
过渡动画完成时触发,每个过渡属性会独立触发一次。如果同时过渡多个属性,会触发多次事件。
核心属性
- event.propertyName:完成过渡的属性名,用于区分不同属性的过渡
- event.elapsedTime:过渡持续的时间,单位秒
基础示例
const box = document.querySelector('.box'); box.addEventListener('transitionend', (e) => { // 只处理 opacity 过渡完成的逻辑 if (e.propertyName === 'opacity') { console.log('透明度过渡完成'); // 过渡结束后移除元素 if (box.style.opacity === '0') { box.remove(); } } });注意事项
- 过渡中途被中断(如状态再次变化、元素隐藏),不会触发 transitionend 事件。
- 过渡时长为 0 时不会触发事件。
- 多个属性过渡会触发多次,需通过 propertyName 过滤目标事件。
二、animation 相关事件
关键帧动画提供三个生命周期事件,覆盖完整动画流程:
事件名 | 触发时机 | 核心说明 |
animationstart | 动画开始播放时触发 | 延迟时间结束、动画正式启动时触发 |
animationiteration | 动画每完成一次迭代时触发 | 循环动画每次循环结束触发,仅 iteration-count > 1 时有效 |
animationend | 动画全部播放完成时触发 | 所有迭代完成后触发,无限循环不会触发 |
基础示例:入场动画结束后执行业务逻辑
const modal = document.querySelector('.modal'); modal.addEventListener('animationend', () => { console.log('弹窗入场动画完成'); // 动画结束后聚焦输入框 modal.querySelector('input').focus(); });三、典型应用场景
- 离场动画结束后移除 DOM 元素,避免元素残留
- 链式动画:前一个动画结束后触发下一个动画,实现序列动效
- 动画完成回调:入场动画结束后初始化业务逻辑、聚焦交互
- 状态同步:动画结束后更新业务状态,避免动画未完成就执行操作