从过渡到动画:CSS 动效完整指南

200 阅读10分钟

在网页开发中,流畅的动效能显著提升用户体验。CSS 提供了两种核心动效方案:过渡(transitions) 和 动画(animations)。本文先完整梳理过渡的核心用法(含实操案例),再延伸补充动画的进阶能力,帮你系统掌握 CSS 动效。

一、CSS 过渡:让属性变化 “丝滑起来”

过渡(transitions)的核心特点是 被动触发—— 必须等待某个 CSS 属性(如颜色、位置、尺寸)发生变化(比如鼠标 hover、元素 focus),才会将变化过程以平滑方式呈现。若没有过渡,属性变化会瞬间完成,观感生硬。

1.1 过渡的核心逻辑:从 “瞬移” 到 “丝滑”

我们以最常见的 “按钮交互” 为例,一步步优化动效,理解过渡的作用。

第一步:基础 hover 效果(无过渡,生硬)

先写一个简单的按钮 hover 向上移动效果,但此时没有过渡,按钮会 “瞬移”:

.btn {
padding: 8px 20px;
border: none;
border-radius: 4px;
background-color: #fff;
color: #333;
cursor: pointer;

}

/* 鼠标 hover 时向上移动10px */

.btn:hover {

transform: translateY(-10px); 

}

效果问题:鼠标放到按钮上,元素瞬间从原位置跳到目标位置,没有中间过程,观感很不自然。 第二步:添加过渡属性(指定触发过渡的属性) 要解决 “瞬移” 问题,需用 transition-property 指定 “哪些属性变化需要过渡”。这里我们让 transform 属性的变化触发过渡:

.btn {
padding: 8px 20px;
border: none;
border-radius: 4px;
background-color: #fff;
color: #333;
cursor: pointer;

/* 关键:指定仅 transform 属性变化触发过渡 */

transition-property: transform; 
}

.btn:hover {
transform: translateY(-10px);

}

此时属性变化已有过渡,但默认过渡时间为 0s,仍感觉生硬,需进一步优化。 第三步:设置过渡时长(控制动画快慢) 用 transition-duration 定义过渡的持续时间(单位:s 秒或 ms 毫秒),通常 0.3s 是兼顾丝滑与响应速度的最佳值:

.btn {
padding: 8px 20px;
border: none;
border-radius: 4px;
background-color: #fff;
color: #333;
cursor: pointer;
transition-property: transform;

/* 关键:过渡持续0.3秒,避免瞬移感 */

transition-duration: 0.3s; 
}

.btn:hover {
transform: translateY(-10px);
}

此时按钮移动已出现平滑过程,但速度曲线仍可优化。 第四步:调整过渡速度曲线(控制动效 “节奏”)

transition-timing-function 定义过渡的速度变化规律,不同值对应不同的动效节奏,我们先看最常用的 ease:

.btn {
padding: 8px 20px;
border: none;
border-radius: 4px;
background-color: #fff;
color: #333;
cursor: pointer;
transition-property: transform;
transition-duration: 0.3s;

/* 关键:速度曲线“慢→快→慢”,接近现实运动规律 */

transition-timing-function: ease; 
}

.btn:hover {
transform: translateY(-10px);
}

补充:前端动画中过渡曲线的其他家族成员 除了默认的 ease,还有 4 种常用曲线,适用场景不同:

  1. 基础缓动函数
  • linear:匀速过渡,速度恒定不变(等同于 cubic-bezier (0,0,1,1)) 场景:加载进度条、时间显示、旋转动画(如加载图标),需机械感的场景
  • ease:默认值,慢→快→慢的平滑过渡(cubic-bezier (0.25,0.1,0.25,1)) 场景:大多数 UI 元素的自然过渡,如按钮悬停效果、页面切换
  1. 方向性缓动函数
  • ease-in:慢速开始,逐渐加速(cubic-bezier (0.42,0,1,1)) 场景:元素 "出现" 效果(如弹窗展开、淡入),模拟物体从静止加速
  • ease-out:快速开始,逐渐减速(cubic-bezier (0,0,0.58,1)) 场景:元素 "消失" 效果(如弹窗关闭、淡出),物体停止前的缓冲
  • ease-in-out:两端慢,中间快的对称过渡(cubic-bezier (0.42,0,0.58,1)) 场景:页面间过渡 (300-500ms)、卡片滑动,最自然的动画效果

第五步:过渡延迟(控制动效 “启动时机”) transition-delay 用于设置 “属性变化后,延迟多久开始过渡”,单位同样是 s 或 ms。但需注意:非特殊需求(如序列动效),建议设为 0s(默认),否则会让用户感觉 “交互延迟”:

.btn {
transition-property: transform;
transition-duration: 0.3s;
transition-timing-function: ease;
transition-delay: 0s; /* 无延迟,交互更即时 */
}

1.2 过渡简写:简化代码 上述 4 个过渡属性(property、duration、timing-function、delay)可合并为 transition 简写,顺序规则如下: /* 完整写法 */

transition: [property] [duration] [timing-function] [delay]; /* 示例:省略默认值(ease 和 0s)/ .btn { / 等价于:transform 0.3s ease 0s */ transition: transform 0.3s; }

⚠️ 注意:简写中第一个时间值永远是 duration(时长),第二个时间值才是 delay(延迟),不要颠倒。

1.3 多属性过渡:一次控制多个变化 若想让按钮 hover 时同时实现 “向上移动 + 背景色变化 + 文字色变化”,需指定多个过渡属性,用英文逗号分隔: 第一步:定义多属性变化

.btn:hover {
transform: translateY(-10px); /* 位置变化 */
background-color: var(--clr-accent); /* 背景色变化(CSS变量,便于统一管理)*/
color: var(--clr-light); /* 文字色变化 */
}

/* 提前定义CSS变量(通常放 :root 中)*/

:root {
--clr-accent: #2563eb; /* 强调色(蓝色)*/
--clr-light: #ffffff; /* 浅色(白色)*/
}

第二步:多属性过渡实现 有两种方式实现多属性过渡:

  1. 指定具体属性:明确列出需要过渡的属性,适合属性数量少的场景:
.btn {
/* 三个属性均过渡0.3秒,速度曲线ease */
transition: transform 0.3s, background-color 0.3s, color 0.3s;
}
  1. 用 all 简化:当所有属性的过渡规则(时长、曲线)一致时,用 all 代表 “所有属性变化都触发过渡”:
.btn {​

/* 等价于上述多属性写法,代码更简洁 */transition: all 0.3s;​

}​

1.4 过渡优化:避坑与最佳实践​

  1. 优先过渡 transform 和 opacity:这两个属性不会触发浏览器 “重排(reflow)” 和 “重绘(repaint)”,仅触发 “合成(composite)”,性能更优,动效更流畅;避免过渡 width、height、margin 等会引发重排的属性。​
  1. 谨慎使用 all:若元素有多个属性变化,但仅部分需要过渡,用 all 会导致不必要的过渡(如 border 变化),建议指定具体属性。​
  1. 控制过渡时长:交互类动效(hover、点击)建议 0.2-0.3s,过长会让用户觉得 “慢”,过短则不够丝滑。​

二、CSS 动画:突破过渡限制,实现主动复杂动效​

过渡虽好,但有明显局限:被动触发(依赖属性变化)、仅支持 “从 A 到 B” 两阶段变化。若想实现 “主动循环动效”(如加载动画)、“多阶段复杂运动”(如元素先旋转再跳跃),就需要 CSS 动画(animations)。​

2.1 动画核心:@keyframes 关键帧​

动画的灵魂是 @keyframes(关键帧)—— 它能定义动画的 “多个关键节点状态”,浏览器会自动补全中间过程,实现主动运动。​

  • @keyframes:相当于动画的 “剧本”,定义元素在不同时间点的状态;​
  • animation 属性:相当于 “导演”,控制动画的执行规则(时长、循环次数等)。​

2.2 动画基础实操:主动跳动的按钮​

延续过渡的按钮案例,这次让按钮不依赖 hover,主动循环跳动,同时实现颜色变化:​

第一步:定义关键帧(剧本)​

用 0%(开始)、50%(中间)、100%(结束)定义关键节点,也可用 from 代替 0%,to 代替 100%:​

/* 关键帧名称:bounce(跳动)*/@keyframes bounce {​
0% {​
transform: translateY(0);​
background-color: #fff;​
color: #333;​
}​
50% {​
transform: translateY(-15px); /* 中间位置:向上15px */background-color: var(--clr-accent);​
color: var(--clr-light);​
}​
100% {​
transform: translateY(0); /* 回到初始位置 */background-color: #fff;​
color: #333;​
}​
}​

第二步:应用动画(执行剧本)​

通过 animation 属性给按钮绑定关键帧,控制动画规则:​

.btn {​

padding: 8px 20px;​

border: none;​

border-radius: 4px;​

cursor: pointer;​

/* 动画简写:名称 时长 速度曲线 循环次数 */animation: bounce 1.5s ease infinite;​

}​

动画属性详解(含简写)​

animation 包含多个细分属性,简写顺序如下(默认值可省略):​

/* 完整写法 */​

animation: [name] [duration] [timing-function] [delay] [iteration-count] [direction] [fill-mode] [play-state];​

/* 各属性作用说明 */​

属性名​作用​常用值​
animation-name​绑定关键帧名称(必选)​自定义关键帧名(如 bounce)​
animation-duration​动画时长(必选,默认 0s 无动画)​1.5s、500ms​
animation-timing-function​速度曲线(同过渡)​ease(默认)、linear​
animation-delay​延迟启动时间​0s(默认)、0.5s​
animation-iteration-count​循环次数​infinite(无限循环)、3(3 次)​
animation-direction​播放方向​normal(正向)、alternate(来回)​
animation-fill-mode​动画结束后保持的状态​forwards(保持最后一帧)​
animation-play-state​控制播放 / 暂停​running(播放)、paused(暂停)​

2.3 动画实战扩展:3 个高频场景​

场景 1:加载旋转图标(匀速循环)​

用 border 实现圆环加载动画,核心是 “匀速旋转”:​

/* 关键帧:旋转360度 */@keyframes spin {​

0% { transform: rotate(0deg); }​

100% { transform: rotate(360deg); }​

}​

​

.loader {​

width: 40px;​

height: 40px;​

border: 4px solid #eee;​

border-top-color: var(--clr-accent); /* 顶部高亮,形成圆环缺口感 */border-radius: 50%;​

/* 匀速旋转+无限循环 */animation: spin 1s linear infinite;​

}​

场景 2:呼吸效果(hover 暂停)​

按钮平时缓慢 “呼吸”(缩放 + 透明度变化),鼠标 hover 时暂停:​

@keyframes breathe {​

0% { transform: scale(1); opacity: 0.9; }​

50% { transform: scale(1.05); opacity: 1; }​

100% { transform: scale(1); opacity: 0.9; }​

}​

​

.btn {​

animation: breathe 3s ease infinite;​

transition: all 0.3s; /* 保留hover过渡,增强交互 */​

}​

​

/* hover 时暂停动画,并放大变色 */.btn:hover {​

animation-play-state: paused;​

transform: scale(1.1);​

background-color: var(--clr-accent);​

color: var(--clr-light);​

}​

场景 3:数字滚动(动画结束保持状态)​

实现 “0→100%” 的数字滚动,动画结束后保持 100%:​

/* 用CSS计数器实现数字变化 */​

@keyframes countUp {​

0% { counter-reset: num 0; } /* 初始值0 */100% { counter-reset: num 100; } /* 结束值100 */​

}​

​

.number {​

font-size: 24px;​

counter-reset: num 0;​

/* forwards:动画结束后保持最后一帧(num=100)*/animation: countUp 1.5s forwards;​

}​

​

/* 显示计数器数值 */.number::after {​

content: counter(num) "%";​

}​

三、过渡 vs 动画:怎么选?​

很多时候两者可以配合使用,核心区别在于 “触发方式” 和 “复杂度”,用表格快速区分:​

维度​过渡(transitions)​动画(animations)​
触发方式​被动(依赖属性变化:hover/active 等)​主动(定义后自动执行,无需交互)​
运动阶段​仅支持 “从 A 到 B” 两阶段​支持多阶段(0%/50%/100% 等任意节点)​
循环能力​不支持循环(触发一次执行一次)​支持无限循环(infinite)​
适用场景​简单交互(hover 变色、点击放大)​复杂动效(加载动画、呼吸、多状态)​
代码复杂度​简单(1-2 行简写)​稍复杂(需定义关键帧)​

选择建议:​

  • 简单交互用过渡(如按钮 hover、输入框焦点样式);​
  • 主动 / 循环 / 多阶段动效用动画(如加载图标、数字滚动);​
  • 复杂交互两者结合(如 “呼吸动画 + hover 暂停 + 过渡变色”)。​

四、总结:CSS 动效优化 checklist​

  1. 性能优先:优先用 transform 和 opacity 做动效,避免重排属性;​
  1. 时长合理:交互动效 0.2-0.3s,循环动效 1-3s;​
  1. 规则清晰:过渡简写不颠倒时间顺序,动画关键帧节点明确;​
  1. 用户友好:避免过度动效(如频繁闪烁),确保动效服务于交互逻辑。​

掌握过渡与动画,就能覆盖 90% 以上的网页动效场景。赶紧把案例复制到代码里调试,调整参数感受不同动效的差异,实践才是最快的掌握方式!​