CSS过渡与动画是现代Web开发中不可或缺的技术,它们为用户界面增添了生动性和交互性。 本文将全面介绍CSS过渡(transition)和动画(animation)的基本概念、语法、属性以及实际应用场景。 无论你是初学者还是有经验的开发者,都能从本文中获得关于创建流畅、吸引人用户体验的实用知识。
CSS过渡(Transition)基础
CSS过渡允许你在一定时间内平滑地改变属性值,而不是瞬间变化。这是创建微妙动画效果最简单的方式。
/* 基本过渡语法 */
.element {
transition: property duration timing-function delay;
}
/* 过渡属性分解 */
.element {
transition-property: all; /* 指定要过渡的属性 */
transition-duration: 0.3s; /* 过渡持续时间 */
transition-timing-function: ease; /* 过渡速度曲线 */
transition-delay: 0s; /* 过渡开始前的延迟 */
}
/* 实际应用示例 */
.button {
background-color: #2563eb;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
transition: background-color 0.3s ease, transform 0.2s ease-out;
}
.button:hover {
background-color: #1d4ed8;
transform: translateY(-2px);
}
.element {
transition: property duration timing-function delay;
}
/* 过渡属性分解 */
.element {
transition-property: all; /* 指定要过渡的属性 */
transition-duration: 0.3s; /* 过渡持续时间 */
transition-timing-function: ease; /* 过渡速度曲线 */
transition-delay: 0s; /* 过渡开始前的延迟 */
}
/* 实际应用示例 */
.button {
background-color: #2563eb;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
transition: background-color 0.3s ease, transform 0.2s ease-out;
}
.button:hover {
background-color: #1d4ed8;
transform: translateY(-2px);
}
悬停查看过渡效果:
悬停我
这个示例展示了颜色、尺寸、形状和旋转的同时过渡效果。
可设置过渡的CSS属性:
- 尺寸相关:width, height, padding, margin, font-size
- 颜色相关:color, background-color, border-color
- 位置相关:top, right, bottom, left
- 变换相关:transform, opacity, visibility
- 布局相关:flex, grid 相关属性(部分浏览器支持有限)
过渡计时函数(Timing Functions)
过渡计时函数决定了动画过程中值的变化速度,直接影响动画的"感觉"和流畅度。
/* 预定义的计时函数 */
.element {
transition-timing-function: ease; /* 默认,慢快慢 */
}
.element {
transition-timing-function: linear; /* 匀速 */
}
.element {
transition-timing-function: ease-in; /* 慢开始 */
}
.element {
transition-timing-function: ease-out; /* 慢结束 */
}
.element {
transition-timing-function: ease-in-out; /* 慢开始和结束 */
}
/* 自定义贝塞尔曲线 */
.element {
transition-timing-function: cubic-bezier(0.17, 0.67, 0.83, 0.67);
}
/* 步进函数 */
.element {
transition-timing-function: steps(4, end);
}
.element {
transition-timing-function: ease; /* 默认,慢快慢 */
}
.element {
transition-timing-function: linear; /* 匀速 */
}
.element {
transition-timing-function: ease-in; /* 慢开始 */
}
.element {
transition-timing-function: ease-out; /* 慢结束 */
}
.element {
transition-timing-function: ease-in-out; /* 慢开始和结束 */
}
/* 自定义贝塞尔曲线 */
.element {
transition-timing-function: cubic-bezier(0.17, 0.67, 0.83, 0.67);
}
/* 步进函数 */
.element {
transition-timing-function: steps(4, end);
}
不同计时函数对比:
linear
ease
ease-in
ease-out
ease-in-out
注意观察每个方块运动速度的变化模式。
选择合适计时函数的技巧:
- ease:最适合大多数UI元素的默认选择
- ease-in:适用于离开屏幕或消失的元素
- ease-out:适用于进入屏幕或出现的元素
- linear:适用于颜色或透明度变化,机械运动
- 自定义曲线:创建独特品牌个性或特殊效果
CSS动画(Animation)基础
CSS动画比过渡更强大,允许创建复杂的多阶段动画,无需用户交互即可自动播放。
/* 定义关键帧动画 */
@keyframes slide-in {
0% {
transform: translateX(-100%);
opacity: 0;
}
70% {
transform: translateX(10%);
}
100% {
transform: translateX(0);
opacity: 1;
}
}
/* 应用动画 */
.element {
animation-name: slide-in;
animation-duration: 1s;
animation-timing-function: ease-out;
animation-delay: 0.5s;
animation-iteration-count: infinite; /* 或数字 */
animation-direction: alternate; /* normal, reverse, alternate, alternate-reverse */
animation-fill-mode: both; /* none, forwards, backwards, both */
animation-play-state: running; /* running 或 paused */
}
/* 简写形式 */
.element {
animation: slide-in 1s ease-out 0.5s infinite alternate both;
}
@keyframes slide-in {
0% {
transform: translateX(-100%);
opacity: 0;
}
70% {
transform: translateX(10%);
}
100% {
transform: translateX(0);
opacity: 1;
}
}
/* 应用动画 */
.element {
animation-name: slide-in;
animation-duration: 1s;
animation-timing-function: ease-out;
animation-delay: 0.5s;
animation-iteration-count: infinite; /* 或数字 */
animation-direction: alternate; /* normal, reverse, alternate, alternate-reverse */
animation-fill-mode: both; /* none, forwards, backwards, both */
animation-play-state: running; /* running 或 paused */
}
/* 简写形式 */
.element {
animation: slide-in 1s ease-out 0.5s infinite alternate both;
}
CSS动画示例:
这个方块使用了无限循环的脉动动画效果。
动画属性详解:
- animation-name:指定要应用的@keyframes动画名称
- animation-duration:动画完成一个周期所需时间
- animation-timing-function:动画速度曲线(同过渡)
- animation-delay:动画开始前的延迟时间
- animation-iteration-count:动画播放次数(数字或infinite)
- animation-direction:动画播放方向(正常、反向、交替等)
- animation-fill-mode:动画执行前后如何应用样式
- animation-play-state:允许暂停和恢复动画
变换(Transform)与动画结合
CSS变换属性可以改变元素的形状、位置和大小,与动画结合可以创建出令人印象深刻的视觉效果。
/* 2D变换 */
.element {
transform: translate(100px, 50px); /* 移动 */
transform: rotate(45deg); /* 旋转 *//* 缩放 */
transform: scale(1.5); /* 等比例缩放 */
transform: scaleX(1.5); /* 水平缩放 */
transform: scaleY(1.5); /* 垂直缩放 */
transform: skew(30deg, 20deg); /* 倾斜 */
}
/* 变换原点 */
.element {
transform-origin: center center; /* 默认 */
transform-origin: left top; /* 左上角 */
transform-origin: 100px 200px; /* 具体坐标 */
}
/* 多重变换 */
.element {
transform: translateX(100px) rotate(45deg) scale(1.2);
}
/* 3D变换 */
.parent {
perspective: 1000px; /* 3D透视 */
}
.element {
transform: rotateX(45deg) rotateY(30deg);
transform-style: preserve-3d; /* 保持3D空间 */
}
.element {
transform: translate(100px, 50px); /* 移动 */
transform: rotate(45deg); /* 旋转 *//* 缩放 */
transform: scale(1.5); /* 等比例缩放 */
transform: scaleX(1.5); /* 水平缩放 */
transform: scaleY(1.5); /* 垂直缩放 */
transform: skew(30deg, 20deg); /* 倾斜 */
}
/* 变换原点 */
.element {
transform-origin: center center; /* 默认 */
transform-origin: left top; /* 左上角 */
transform-origin: 100px 200px; /* 具体坐标 */
}
/* 多重变换 */
.element {
transform: translateX(100px) rotate(45deg) scale(1.2);
}
/* 3D变换 */
.parent {
perspective: 1000px; /* 3D透视 */
}
.element {
transform: rotateX(45deg) rotateY(30deg);
transform-style: preserve-3d; /* 保持3D空间 */
}
变换效果示例:
悬停查看变换
这个示例结合了平移、旋转和倾斜变换。
变换与动画结合的最佳实践:
- 使用
transform和opacity属性制作动画,性能最佳 - 避免动画期间改变布局属性(width、height、margin等),会导致重排
- 使用
will-change属性提示浏览器哪些属性将变化,优化性能 - 考虑使用
translate3d()开启GPU加速,但不要过度使用 - 对于复杂动画,考虑使用CSS动画而不是JavaScript以获得更好性能
实际应用案例
下面是一些在实际项目中应用CSS过渡和动画的常见场景。
加载动画
/* 旋转加载器 */
.loader {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 点状加载动画 */
.dot-flashing {
position: relative;
width: 10px;
height: 10px;
border-radius: 5px;
background-color: #2563eb;
color: #2563eb;
animation: dotFlashing 1s infinite linear alternate;
animation-delay: 0.5s;
}
.dot-flashing::before, .dot-flashing::after {
content: '';
display: inline-block;
position: absolute;
top: 0;
width: 10px;
height: 10px;
border-radius: 5px;
background-color: #2563eb;
color: #2563eb;
}
.dot-flashing::before {
left: -15px;
animation: dotFlashing 1s infinite alternate;
animation-delay: 0s;
}
.dot-flashing::after {
left: 15px;
animation: dotFlashing 1s infinite alternate;
animation-delay: 1s;
}
@keyframes dotFlashing {
0% { background-color: #2563eb; }
50%, 100% { background-color: #dbeafe; }
}
.loader {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 点状加载动画 */
.dot-flashing {
position: relative;
width: 10px;
height: 10px;
border-radius: 5px;
background-color: #2563eb;
color: #2563eb;
animation: dotFlashing 1s infinite linear alternate;
animation-delay: 0.5s;
}
.dot-flashing::before, .dot-flashing::after {
content: '';
display: inline-block;
position: absolute;
top: 0;
width: 10px;
height: 10px;
border-radius: 5px;
background-color: #2563eb;
color: #2563eb;
}
.dot-flashing::before {
left: -15px;
animation: dotFlashing 1s infinite alternate;
animation-delay: 0s;
}
.dot-flashing::after {
left: 15px;
animation: dotFlashing 1s infinite alternate;
animation-delay: 1s;
}
@keyframes dotFlashing {
0% { background-color: #2563eb; }
50%, 100% { background-color: #dbeafe; }
}
加载动画示例:
左侧是旋转加载器,右侧是点状加载动画。
交互反馈动画
/* 按钮点击涟漪效果 */
.ripple-button {
position: relative;
overflow: hidden;
background-color: #2563eb;
color: white;
border: none;
padding: 12px 24px;
border-radius: 4px;
cursor: pointer;
}
.ripple-button .ripple {
position: absolute;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.7);
transform: scale(0);
animation: ripple 0.6s linear;
}
@keyframes ripple {
to {
transform: scale(4);
opacity: 0;
}
}
/* 卡片悬停效果 */
.card {
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: all 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.15);
}
.ripple-button {
position: relative;
overflow: hidden;
background-color: #2563eb;
color: white;
border: none;
padding: 12px 24px;
border-radius: 4px;
cursor: pointer;
}
.ripple-button .ripple {
position: absolute;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.7);
transform: scale(0);
animation: ripple 0.6s linear;
}
@keyframes ripple {
to {
transform: scale(4);
opacity: 0;
}
}
/* 卡片悬停效果 */
.card {
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: all 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.15);
}
交互反馈示例:
悬停卡片
将鼠标悬停在此卡片上查看效果
性能优化与最佳实践
性能考虑
- 优先使用
transform和opacity属性制作动画,它们不会触发布局或绘制 - 避免动画期间改变盒模型属性(width、height、padding等),会导致性能下降
- 使用
will-change属性小心地提示浏览器哪些属性将变化 - 尽量减少同时运行的动画数量,特别是在低性能设备上
- 适当使用
animation-play-state: paused暂停不可见元素的动画
可访问性考虑
/* 尊重用户偏好:减少动画 */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* 或者提供替代的简化动画 */
@media (prefers-reduced-motion: reduce) {
.animated-element {
animation: fade-in 0.5s ease-out;
}
}
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* 或者提供替代的简化动画 */
@media (prefers-reduced-motion: reduce) {
.animated-element {
animation: fade-in 0.5s ease-out;
}
}
调试技巧
- 使用浏览器开发者工具中的Animations面板调试CSS动画
- 使用
animation-play-state: paused在特定时间点检查动画状态 - 逐步增加动画复杂度,先实现基本效果再添加细节
- 在不同设备和浏览器上测试动画性能和外观
- 考虑使用CSS动画库(如Animate.css)作为起点