CSS 动画:transition 与 @keyframes
CSS 动画是前端开发中最常用的交互手段之一。它能让页面元素动起来,提升用户体验。CSS 提供了两种主要的动画实现方式:transition 和 @keyframes。理解它们的区别和使用场景,是掌握 CSS 动画的第一步。
transition:简单的状态过渡
transition 适用于两个状态之间的平滑过渡。当你改变元素的某个属性值时,transition 会让这个变化在指定时间内完成,而不是瞬间跳变。
核心属性
transition 是四个属性的简写形式:
| 属性 | 作用 |
|---|---|
transition-property |
指定要动画的CSS属性 |
transition-duration |
动画持续的时间 |
transition-timing-function |
动画的速度曲线 |
transition-delay |
动画开始前的延迟时间 |
基本用法
.box {
width: 100px;
height: 100px;
background: #3498db;
transition: all 0.3s ease;
}
.box:hover {
width: 150px;
background: #e74c3c;
}
这段代码的含义是:当鼠标悬停在 .box 上时,宽度和背景色会在 0.3 秒内平滑过渡。ease 是默认的速度曲线,表示开始和结束时较慢,中间较快。
单独设置每个属性
.box {
transition-property: width, background-color;
transition-duration: 0.5s, 0.3s;
transition-timing-function: ease-in-out, linear;
transition-delay: 0s, 0.2s;
}
这里宽度变化需要 0.5 秒,背景色变化需要 0.3 秒 且延迟 0.2 秒 开始。分别设置可以让不同属性的动画节奏更精细。
常见速度曲线
| 关键字 | 效果 |
|---|---|
ease |
默认,慢-快-慢 |
linear |
匀速运动 |
ease-in |
慢慢开始,突然结束 |
ease-out |
突然开始,慢慢结束 |
ease-in-out |
慢-快-慢(比 ease 更明显) |
你也可以使用 cubic-bezier() 自定义速度曲线:
.box {
transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
这个贝塞尔曲线会产生"回弹"效果,元素到达目标位置后会轻微超出再弹回。
@keyframes:复杂的动画序列
transition 只能处理两个状态之间的变化,而 @keyframes 可以定义多个关键帧,实现复杂的动画序列。比如淡入淡出、无限循环、复杂变形等效果。
基本语法
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.element {
animation: fadeIn 1s ease-in-out;
}
@keyframes 后跟动画名称(大括号内是动画定义),from 表示起始状态(等同于 0%),to 表示结束状态(等同于 100%)。
使用百分比定义多阶段动画
@keyframes bounce {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-20px);
}
70% {
transform: translateY(-10px);
}
100% {
transform: translateY(0);
}
}
这个弹跳动画包含四个关键帧:起跳、最高点、回落、落地。百分比表示动画进行到某个阶段时应该处于的状态。
动画属性详解
animation 是多个属性的简写:
| 属性 | 默认值 | 说明 |
|---|---|---|
animation-name |
none | 动画名称 |
animation-duration |
0s | 动画时长 |
animation-timing-function |
ease | 速度曲线 |
animation-delay |
0s | 延迟时间 |
animation-iteration-count |
1 | 播放次数(infinite 表示无限) |
animation-direction |
normal | 播放方向 |
animation-fill-mode |
none | 动画前后的状态保持 |
animation-play-state |
running | 播放或暂停 |
实用示例
无限旋转加载动画:
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.loading {
animation: spin 1.5s linear infinite;
}
linear 保证旋转速度均匀,infinite 让动画一直循环。
悬停时播放的脉冲效果:
@keyframes pulse {
0% {
transform: scale(1);
box-shadow: 0 0 0 0 rgba(52, 152, 219, 0.7);
}
70% {
transform: scale(1.1);
box-shadow: 0 0 0 15px rgba(52, 152, 219, 0);
}
100% {
transform: scale(1);
box-shadow: 0 0 0 0 rgba(52, 152, 219, 0);
}
}
.button:hover {
animation: pulse 1s infinite;
}
控制动画方向
animation-direction 有四个可选值:
| 值 | 效果 |
|---|---|
normal |
正向播放,每次都从 0% 到 100% |
reverse |
反向播放,从 100% 到 0% |
alternate |
奇数次正向,偶数次反向(适合呼吸效果) |
alternate-reverse |
奇数次反向,偶数次正向 |
.breathing {
animation: breathe 3s ease-in-out infinite alternate;
}
transition 与 @keyframes 的核心区别
| 特性 | transition | @keyframes |
|---|---|---|
| 触发方式 | 状态变化(hover、class切换等) | 加载即开始或手动控制 |
| 关键帧数量 | 两个(起始、结束) | 任意数量(0% 到 100%) |
| 循环控制 | 不支持 | 支持 infinite 无限循环 |
| 复杂动画 | 无法实现 | 可以实现复杂序列 |
| 性能开销 | 较小 | 相对较大 |
选择建议:
- 简单的状态过渡(如按钮悬停、颜色变化)用
transition - 复杂的动画序列(如加载动画、复杂特效)用
@keyframes
性能优化技巧
CSS 动画的性能主要取决于动画属性的选择。浏览器的合成层处理动画的效率最高,而触发布局重排的属性开销很大。
推荐动画属性
以下属性由合成器处理,性能最佳:
transform(位移、缩放、旋转、倾斜)opacity(透明度)filter(滤镜,部分浏览器)
避免动画的属性
以下属性会触发布局重排,性能较差:
width、heightmargin、paddingtop、left、right、bottomborder-width
will-change 优化
对于复杂动画,可以提前通知浏览器进行优化:
.box {
will-change: transform;
}
但不要滥用,只在确实需要时才添加,否则会导致内存占用过高。
实用代码片段库
淡入效果
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fade-in {
animation: fadeIn 0.5s ease-out forwards;
}
forwards 会保持动画结束时的状态。
打字机效果
@keyframes type {
from {
width: 0;
}
to {
width: 100%;
}
}
.typewriter {
overflow: hidden;
white-space: nowrap;
border-right: 2px solid #333;
animation: type 2s steps(30) forwards;
}
steps(30) 让动画按 30 步完成,产生逐字显示的效果。
卡片悬停 3D 翻转
.card {
perspective: 1000px;
}
.card-inner {
transition: transform 0.6s;
transform-style: preserve-3d;
}
.card:hover .card-inner {
transform: rotateY(180deg);
}
.card-front,
.card-back {
backface-visibility: hidden;
}
.card-back {
transform: rotateY(180deg);
}
perspective 设置透视效果,preserve-3d 保持 3D 空间,backface-visibility 隐藏背面。
常见问题解决
动画不执行? 检查是否设置了 animation-duration,默认值为 0s 会导致动画不播放。
动画结束后恢复原状? 使用 animation-fill-mode: forwards 保持结束状态,或 both 保持起始和结束状态。
transition 不生效? 确保触发状态的选择器 specificity 高于默认状态,比如使用 :hover 而不是添加新 class。
动画卡顿? 尽量只动画 transform 和 opacity 属性,避免触发布局重排的属性。
总结
transition 是处理两个状态之间平滑过渡的最佳选择,语法简单,性能优秀。keyframes 则适合创建复杂的动画序列,支持多阶段控制、无限循环和精确的状态管理。实际开发中,根据动画的复杂程度选择合适的方式,并注意性能优化,就能做出流畅的页面动效。

暂无评论,快来抢沙发吧!