CSS 动画与过渡
CSS 动画和过渡让网页元素能够平滑地从一个状态变化到另一个状态,为用户界面增添生机和反馈。恰当的动画可以提升用户体验,引导用户注意力,但过度使用则会分散注意力、影响性能。这一章将介绍如何合理地使用 CSS 动画和过渡。
CSS 过渡(Transition)
过渡是最简单的动画形式,它让 CSS 属性的变化在一段时间内平滑进行,而不是立即生效。
基本语法
.element {
transition: property duration timing-function delay;
}
transition-property 过渡属性
指定哪些 CSS 属性参与过渡:
/* 单个属性 */
.box {
transition-property: width;
}
/* 多个属性 */
.box {
transition-property: width, height, opacity;
}
/* 所有属性 */
.box {
transition-property: all;
}
不是所有 CSS 属性都能过渡。可过渡的属性通常是数值类型的,如:
- 尺寸:
width、height、margin、padding - 颜色:
color、background-color、border-color - 透明度:
opacity - 变换:
transform - 阴影:
box-shadow、text-shadow
不可过渡的属性包括 display、visibility(只能离散变化)、position 等。
transition-duration 过渡时长
指定过渡持续的时间:
.fast { transition-duration: 0.2s; }
.normal { transition-duration: 0.3s; }
.slow { transition-duration: 0.5s; }
.multiple { transition-duration: 0.3s, 0.5s; } /* 多个属性不同时长 */
通常 0.2s 到 0.5s 的时长最适合用户界面动画,既能感知到变化又不会太慢。
transition-timing-function 时间函数
控制过渡过程中速度的变化:
.linear { transition-timing-function: linear; } /* 匀速 */
.ease { transition-timing-function: ease; } /* 默认:慢-快-慢 */
.ease-in { transition-timing-function: ease-in; } /* 慢开始 */
.ease-out { transition-timing-function: ease-out; } /* 慢结束 */
.ease-in-out { transition-timing-function: ease-in-out; } /* 慢开始和结束 */
/* 自定义贝塞尔曲线 */
.custom { transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1); }
/* 步进函数 */
.steps { transition-timing-function: steps(4, end); }
ease 是最常用的时间函数,自然流畅。ease-out 适合元素进入视野的动画,ease-in 适合元素离开视野的动画。
transition-delay 过渡延迟
指定过渡开始前的等待时间:
.immediate { transition-delay: 0s; }
.delayed { transition-delay: 0.5s; }
.staggered { transition-delay: 0s, 0.1s, 0.2s; } /* 错开动画 */
简写语法
.box {
/* 完整简写 */
transition: width 0.3s ease 0s;
/* 省略延迟 */
transition: width 0.3s ease;
/* 省略时间函数(使用默认 ease) */
transition: width 0.3s;
/* 多个属性 */
transition: width 0.3s, height 0.5s, opacity 0.2s;
}
常见过渡效果
按钮悬停效果:
.button {
background-color: #3498db;
color: white;
transition: background-color 0.3s, transform 0.2s;
}
.button:hover {
background-color: #2980b9;
transform: translateY(-2px);
}
链接下划线动画:
.link {
position: relative;
color: #333;
text-decoration: none;
}
.link::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 2px;
background: #3498db;
transition: width 0.3s;
}
.link:hover::after {
width: 100%;
}
卡片悬停效果:
.card {
transition: transform 0.3s, box-shadow 0.3s;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
}
展开/收起效果:
.expandable {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
.expandable.open {
max-height: 500px;
}
CSS 动画(Animation)
动画比过渡更强大,可以定义多个关键帧,实现更复杂的动画序列,还可以自动播放、循环播放。
@keyframes 关键帧
使用 @keyframes 定义动画序列:
/* 从...到... */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/* 百分比关键帧 */
@keyframes bounce {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-20px);
}
}
/* 多个关键帧 */
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.1);
opacity: 0.8;
}
100% {
transform: scale(1);
opacity: 1;
}
}
from 等价于 0%,to 等价于 100%。如果不指定 0% 或 100%,浏览器会使用元素的初始状态或最终状态。
animation 属性
animation-name:指定要使用的关键帧名称
.element {
animation-name: fadeIn;
}
animation-duration:动画持续时间
.element {
animation-duration: 1s;
}
animation-timing-function:时间函数
.element {
animation-timing-function: ease-in-out;
}
animation-delay:动画延迟
.element {
animation-delay: 0.5s;
}
animation-iteration-count:动画播放次数
.once { animation-iteration-count: 1; } /* 播放一次 */
.loop { animation-iteration-count: infinite; } /* 无限循环 */
.custom { animation-iteration-count: 3; } /* 播放三次 */
animation-direction:动画播放方向
.normal { animation-direction: normal; } /* 正向播放 */
.reverse { animation-direction: reverse; } /* 反向播放 */
.alternate { animation-direction: alternate; } /* 正向再反向交替 */
.alternate-reverse { animation-direction: alternate-reverse; }
animation-fill-mode:动画执行前后的样式
.none { animation-fill-mode: none; } /* 默认:动画前后恢复初始状态 */
.forwards { animation-fill-mode: forwards; } /* 保持最后一帧状态 */
.backwards { animation-fill-mode: backwards; } /* 动画前应用第一帧状态 */
.both { animation-fill-mode: both; } /* 同时应用 forwards 和 backwards */
animation-play-state:动画播放状态
.running { animation-play-state: running; } /* 播放 */
.paused { animation-play-state: paused; } /* 暂停 */
简写语法
.element {
animation: name duration timing-function delay iteration-count direction fill-mode;
}
/* 示例 */
.box {
animation: fadeIn 0.5s ease-out 0.2s 1 forwards;
}
/* 无限循环动画 */
.spinner {
animation: spin 1s linear infinite;
}
常见动画效果
淡入:
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-in {
animation: fadeIn 0.5s ease-out;
}
滑入:
@keyframes slideIn {
from {
transform: translateX(-100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
.slide-in {
animation: slideIn 0.5s ease-out;
}
弹跳:
@keyframes bounce {
0%, 20%, 50%, 80%, 100% {
transform: translateY(0);
}
40% {
transform: translateY(-30px);
}
60% {
transform: translateY(-15px);
}
}
.bounce {
animation: bounce 1s;
}
旋转加载:
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
width: 40px;
height: 40px;
border: 3px solid #f3f3f3;
border-top: 3px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
脉冲:
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.pulse {
animation: pulse 2s infinite;
}
抖动:
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
20%, 40%, 60%, 80% { transform: translateX(5px); }
}
.shake {
animation: shake 0.5s;
}
性能优化
使用 transform 和 opacity
transform 和 opacity 的动画由 GPU 加速,不会触发重排(reflow),性能最好:
/* 推荐 */
.good {
transition: transform 0.3s, opacity 0.3s;
}
.good:hover {
transform: translateX(10px);
opacity: 0.8;
}
/* 避免 */
.bad {
transition: left 0.3s, top 0.3s, width 0.3s;
}
.bad:hover {
left: 10px;
top: 10px;
width: 200px;
}
will-change 提示
will-change 提示浏览器某个属性即将变化,让浏览器提前优化:
.will-animate {
will-change: transform, opacity;
}
但不要滥用,只在需要时使用,动画结束后移除:
/* 动画前添加 */
.element.animating {
will-change: transform;
}
/* 动画后移除 */
.element:not(.animating) {
will-change: auto;
}
减少动画偏好
尊重用户的系统设置,减少不必要的动画:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
content-visibility
对于不在视口内的动画元素,可以使用 content-visibility: auto 跳过渲染:
.offscreen-animation {
content-visibility: auto;
contain-intrinsic-size: 500px;
}
过渡与动画的选择
使用过渡的场景:
- 状态切换(悬停、聚焦、激活)
- 简单的起始和结束状态
- 用户触发的交互反馈
使用动画的场景:
- 复杂的多帧动画序列
- 自动播放的动画
- 循环动画
- 需要精确控制每一帧的场景
小结
这一章我们学习了:
- CSS 过渡的四个属性:property、duration、timing-function、delay
- 常见过渡效果的实现
- @keyframes 关键帧动画的定义
- animation 的各个属性
- 常见动画效果的实现
- 动画性能优化的方法
动画应该增强用户体验,而不是分散注意力。记住几个关键点:
- 使用
transform和opacity实现高性能动画 - 动画时长通常在 0.2s 到 0.5s 之间
- 使用
ease-out或ease-in-out时间函数 - 尊重用户的减少动画偏好
- 不要为了动画而动画,每个动画都应该有目的
恭喜你完成了 HTML/CSS 教程的学习!你已经掌握了网页开发的核心技术。继续练习,多动手写代码,你会发现 HTML 和 CSS 的世界远比想象中更广阔。