8.1 动画与过渡概述
8.1.1 动画与过渡的区别
过渡(Transitions): - 在两个状态之间平滑变化 - 需要触发条件(如 hover、focus) - 简单的属性变化动画
动画(Animations): - 可以定义复杂的关键帧序列 - 可以自动播放或循环 - 支持多个阶段的变化
8.1.2 Tailwind CSS 动画系统
Tailwind CSS 提供了丰富的动画和过渡工具类:
- 过渡属性:
transition-*
- 过渡时长:
duration-*
- 过渡时机:
ease-*
- 过渡延迟:
delay-*
- 预设动画:
animate-*
- 变换效果:
transform
、scale-*
、rotate-*
、translate-*
8.2 过渡效果基础
8.2.1 基础过渡
<!-- 基础过渡效果 -->
<button class="bg-blue-500 text-white px-4 py-2 rounded transition-colors duration-300 hover:bg-blue-600">
悬停变色
</button>
<!-- 多属性过渡 -->
<button class="bg-green-500 text-white px-4 py-2 rounded transition-all duration-300 hover:bg-green-600 hover:scale-105 hover:shadow-lg">
多效果过渡
</button>
<!-- 自定义过渡属性 -->
<div class="w-32 h-32 bg-red-500 transition-transform duration-500 hover:rotate-45">
旋转方块
</div>
8.2.2 过渡属性类型
<!-- 颜色过渡 -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="bg-blue-500 text-white p-4 rounded transition-colors duration-300 hover:bg-blue-700">
背景色过渡
</div>
<div class="text-blue-500 p-4 rounded border transition-colors duration-300 hover:text-blue-700">
文字色过渡
</div>
<div class="p-4 rounded border-2 border-blue-500 transition-colors duration-300 hover:border-blue-700">
边框色过渡
</div>
<div class="p-4 rounded bg-blue-100 transition-colors duration-300 hover:bg-blue-200">
组合色过渡
</div>
</div>
<!-- 尺寸过渡 -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-8">
<div class="w-16 h-16 bg-green-500 rounded transition-all duration-300 hover:w-20 hover:h-20">
尺寸变化
</div>
<div class="w-16 h-16 bg-green-500 rounded transition-transform duration-300 hover:scale-125">
缩放变化
</div>
<div class="w-16 h-16 bg-green-500 rounded transition-transform duration-300 hover:scale-x-150">
水平缩放
</div>
<div class="w-16 h-16 bg-green-500 rounded transition-transform duration-300 hover:scale-y-150">
垂直缩放
</div>
</div>
<!-- 位置过渡 -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-8">
<div class="w-16 h-16 bg-purple-500 rounded transition-transform duration-300 hover:translate-x-4">
水平移动
</div>
<div class="w-16 h-16 bg-purple-500 rounded transition-transform duration-300 hover:translate-y-4">
垂直移动
</div>
<div class="w-16 h-16 bg-purple-500 rounded transition-transform duration-300 hover:translate-x-4 hover:translate-y-4">
对角移动
</div>
<div class="w-16 h-16 bg-purple-500 rounded transition-transform duration-300 hover:-translate-y-2">
向上移动
</div>
</div>
8.2.3 过渡时长和时机
<!-- 不同时长的过渡 -->
<div class="space-y-4">
<button class="bg-blue-500 text-white px-4 py-2 rounded transition-colors duration-75 hover:bg-blue-600">
75ms 过渡
</button>
<button class="bg-blue-500 text-white px-4 py-2 rounded transition-colors duration-150 hover:bg-blue-600">
150ms 过渡
</button>
<button class="bg-blue-500 text-white px-4 py-2 rounded transition-colors duration-300 hover:bg-blue-600">
300ms 过渡
</button>
<button class="bg-blue-500 text-white px-4 py-2 rounded transition-colors duration-500 hover:bg-blue-600">
500ms 过渡
</button>
<button class="bg-blue-500 text-white px-4 py-2 rounded transition-colors duration-700 hover:bg-blue-600">
700ms 过渡
</button>
<button class="bg-blue-500 text-white px-4 py-2 rounded transition-colors duration-1000 hover:bg-blue-600">
1000ms 过渡
</button>
</div>
<!-- 不同时机函数的过渡 -->
<div class="space-y-4 mt-8">
<button class="bg-green-500 text-white px-4 py-2 rounded transition-all duration-300 ease-linear hover:scale-110">
线性过渡 (ease-linear)
</button>
<button class="bg-green-500 text-white px-4 py-2 rounded transition-all duration-300 ease-in hover:scale-110">
缓入过渡 (ease-in)
</button>
<button class="bg-green-500 text-white px-4 py-2 rounded transition-all duration-300 ease-out hover:scale-110">
缓出过渡 (ease-out)
</button>
<button class="bg-green-500 text-white px-4 py-2 rounded transition-all duration-300 ease-in-out hover:scale-110">
缓入缓出过渡 (ease-in-out)
</button>
</div>
<!-- 过渡延迟 -->
<div class="space-y-4 mt-8">
<button class="bg-red-500 text-white px-4 py-2 rounded transition-colors duration-300 hover:bg-red-600">
无延迟
</button>
<button class="bg-red-500 text-white px-4 py-2 rounded transition-colors duration-300 delay-75 hover:bg-red-600">
75ms 延迟
</button>
<button class="bg-red-500 text-white px-4 py-2 rounded transition-colors duration-300 delay-150 hover:bg-red-600">
150ms 延迟
</button>
<button class="bg-red-500 text-white px-4 py-2 rounded transition-colors duration-300 delay-300 hover:bg-red-600">
300ms 延迟
</button>
</div>
8.3 变换效果
8.3.1 旋转变换
<!-- 旋转效果 -->
<div class="grid grid-cols-3 md:grid-cols-6 gap-4">
<div class="w-16 h-16 bg-blue-500 rounded transition-transform duration-300 hover:rotate-12 flex items-center justify-center text-white font-bold">
12°
</div>
<div class="w-16 h-16 bg-blue-500 rounded transition-transform duration-300 hover:rotate-45 flex items-center justify-center text-white font-bold">
45°
</div>
<div class="w-16 h-16 bg-blue-500 rounded transition-transform duration-300 hover:rotate-90 flex items-center justify-center text-white font-bold">
90°
</div>
<div class="w-16 h-16 bg-blue-500 rounded transition-transform duration-300 hover:rotate-180 flex items-center justify-center text-white font-bold">
180°
</div>
<div class="w-16 h-16 bg-blue-500 rounded transition-transform duration-300 hover:-rotate-45 flex items-center justify-center text-white font-bold">
-45°
</div>
<div class="w-16 h-16 bg-blue-500 rounded transition-transform duration-500 hover:rotate-360 flex items-center justify-center text-white font-bold">
360°
</div>
</div>
8.3.2 缩放变换
<!-- 缩放效果 -->
<div class="grid grid-cols-3 md:grid-cols-6 gap-4 mt-8">
<div class="w-16 h-16 bg-green-500 rounded transition-transform duration-300 hover:scale-50 flex items-center justify-center text-white font-bold">
0.5x
</div>
<div class="w-16 h-16 bg-green-500 rounded transition-transform duration-300 hover:scale-75 flex items-center justify-center text-white font-bold">
0.75x
</div>
<div class="w-16 h-16 bg-green-500 rounded transition-transform duration-300 hover:scale-90 flex items-center justify-center text-white font-bold">
0.9x
</div>
<div class="w-16 h-16 bg-green-500 rounded transition-transform duration-300 hover:scale-110 flex items-center justify-center text-white font-bold">
1.1x
</div>
<div class="w-16 h-16 bg-green-500 rounded transition-transform duration-300 hover:scale-125 flex items-center justify-center text-white font-bold">
1.25x
</div>
<div class="w-16 h-16 bg-green-500 rounded transition-transform duration-300 hover:scale-150 flex items-center justify-center text-white font-bold">
1.5x
</div>
</div>
<!-- 方向性缩放 -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-8">
<div class="w-16 h-16 bg-purple-500 rounded transition-transform duration-300 hover:scale-x-150 flex items-center justify-center text-white font-bold">
X轴
</div>
<div class="w-16 h-16 bg-purple-500 rounded transition-transform duration-300 hover:scale-y-150 flex items-center justify-center text-white font-bold">
Y轴
</div>
<div class="w-16 h-16 bg-purple-500 rounded transition-transform duration-300 hover:scale-x-50 flex items-center justify-center text-white font-bold">
压缩X
</div>
<div class="w-16 h-16 bg-purple-500 rounded transition-transform duration-300 hover:scale-y-50 flex items-center justify-center text-white font-bold">
压缩Y
</div>
</div>
8.3.3 平移变换
<!-- 平移效果 -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-8 mt-8">
<div class="relative">
<div class="w-16 h-16 bg-red-500 rounded transition-transform duration-300 hover:translate-x-8 flex items-center justify-center text-white font-bold">
→
</div>
</div>
<div class="relative">
<div class="w-16 h-16 bg-red-500 rounded transition-transform duration-300 hover:-translate-x-8 flex items-center justify-center text-white font-bold">
←
</div>
</div>
<div class="relative">
<div class="w-16 h-16 bg-red-500 rounded transition-transform duration-300 hover:-translate-y-8 flex items-center justify-center text-white font-bold">
↑
</div>
</div>
<div class="relative">
<div class="w-16 h-16 bg-red-500 rounded transition-transform duration-300 hover:translate-y-8 flex items-center justify-center text-white font-bold">
↓
</div>
</div>
</div>
<!-- 组合平移 -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-8 mt-8">
<div class="relative">
<div class="w-16 h-16 bg-yellow-500 rounded transition-transform duration-300 hover:translate-x-4 hover:-translate-y-4 flex items-center justify-center text-white font-bold">
↗
</div>
</div>
<div class="relative">
<div class="w-16 h-16 bg-yellow-500 rounded transition-transform duration-300 hover:-translate-x-4 hover:-translate-y-4 flex items-center justify-center text-white font-bold">
↖
</div>
</div>
<div class="relative">
<div class="w-16 h-16 bg-yellow-500 rounded transition-transform duration-300 hover:translate-x-4 hover:translate-y-4 flex items-center justify-center text-white font-bold">
↘
</div>
</div>
<div class="relative">
<div class="w-16 h-16 bg-yellow-500 rounded transition-transform duration-300 hover:-translate-x-4 hover:translate-y-4 flex items-center justify-center text-white font-bold">
↙
</div>
</div>
</div>
8.3.4 倾斜变换
<!-- 倾斜效果 -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-8">
<div class="w-16 h-16 bg-indigo-500 rounded transition-transform duration-300 hover:skew-x-12 flex items-center justify-center text-white font-bold">
X倾斜
</div>
<div class="w-16 h-16 bg-indigo-500 rounded transition-transform duration-300 hover:skew-y-12 flex items-center justify-center text-white font-bold">
Y倾斜
</div>
<div class="w-16 h-16 bg-indigo-500 rounded transition-transform duration-300 hover:-skew-x-12 flex items-center justify-center text-white font-bold">
-X倾斜
</div>
<div class="w-16 h-16 bg-indigo-500 rounded transition-transform duration-300 hover:-skew-y-12 flex items-center justify-center text-white font-bold">
-Y倾斜
</div>
</div>
8.3.5 组合变换
<!-- 复杂组合变换 -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-8 mt-8">
<div class="w-16 h-16 bg-pink-500 rounded transition-transform duration-500 hover:rotate-45 hover:scale-110 flex items-center justify-center text-white font-bold">
旋转+缩放
</div>
<div class="w-16 h-16 bg-pink-500 rounded transition-transform duration-500 hover:translate-x-4 hover:rotate-12 flex items-center justify-center text-white font-bold">
移动+旋转
</div>
<div class="w-16 h-16 bg-pink-500 rounded transition-transform duration-500 hover:scale-125 hover:skew-x-6 flex items-center justify-center text-white font-bold">
缩放+倾斜
</div>
<div class="w-16 h-16 bg-pink-500 rounded transition-transform duration-700 hover:rotate-180 hover:scale-75 hover:translate-y-4 flex items-center justify-center text-white font-bold">
全组合
</div>
</div>
8.4 预设动画
8.4.1 内置动画
<!-- Tailwind 内置动画 -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="w-16 h-16 bg-blue-500 rounded animate-spin flex items-center justify-center text-white font-bold">
旋转
</div>
<div class="w-16 h-16 bg-green-500 rounded animate-ping flex items-center justify-center text-white font-bold">
脉冲
</div>
<div class="w-16 h-16 bg-red-500 rounded animate-pulse flex items-center justify-center text-white font-bold">
呼吸
</div>
<div class="w-16 h-16 bg-purple-500 rounded animate-bounce flex items-center justify-center text-white font-bold">
弹跳
</div>
</div>
<!-- 动画控制 -->
<div class="mt-8 space-y-4">
<button class="bg-blue-500 text-white px-4 py-2 rounded hover:animate-pulse">
悬停时呼吸动画
</button>
<button class="bg-green-500 text-white px-4 py-2 rounded hover:animate-bounce">
悬停时弹跳动画
</button>
<button class="bg-red-500 text-white px-4 py-2 rounded hover:animate-spin">
悬停时旋转动画
</button>
</div>
8.4.2 自定义动画
/* 在 CSS 文件中定义自定义动画 */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInLeft {
from {
opacity: 0;
transform: translateX(-100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes zoomIn {
from {
opacity: 0;
transform: scale(0.5);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes shake {
0%, 100% {
transform: translateX(0);
}
10%, 30%, 50%, 70%, 90% {
transform: translateX(-10px);
}
20%, 40%, 60%, 80% {
transform: translateX(10px);
}
}
@keyframes heartbeat {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
}
/* 应用自定义动画 */
.animate-fadeIn {
animation: fadeIn 0.5s ease-out;
}
.animate-slideInLeft {
animation: slideInLeft 0.5s ease-out;
}
.animate-slideInRight {
animation: slideInRight 0.5s ease-out;
}
.animate-zoomIn {
animation: zoomIn 0.3s ease-out;
}
.animate-shake {
animation: shake 0.5s ease-in-out;
}
.animate-heartbeat {
animation: heartbeat 1s ease-in-out infinite;
}
<!-- 使用自定义动画 -->
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
<div class="bg-blue-500 text-white p-4 rounded animate-fadeIn">
淡入动画
</div>
<div class="bg-green-500 text-white p-4 rounded animate-slideInLeft">
左滑入动画
</div>
<div class="bg-red-500 text-white p-4 rounded animate-slideInRight">
右滑入动画
</div>
<div class="bg-purple-500 text-white p-4 rounded animate-zoomIn">
缩放入动画
</div>
<button class="bg-yellow-500 text-white p-4 rounded hover:animate-shake">
悬停摇摆
</button>
<div class="bg-pink-500 text-white p-4 rounded animate-heartbeat">
心跳动画
</div>
</div>
8.5 交互动画
8.5.1 悬停动画
<!-- 悬停效果集合 -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<!-- 按钮悬停效果 -->
<button class="bg-blue-500 text-white px-6 py-3 rounded-lg transition-all duration-300 hover:bg-blue-600 hover:shadow-lg hover:-translate-y-1">
悬停上浮
</button>
<button class="bg-green-500 text-white px-6 py-3 rounded-lg transition-all duration-300 hover:bg-green-600 hover:scale-105">
悬停放大
</button>
<button class="bg-red-500 text-white px-6 py-3 rounded-lg transition-all duration-300 hover:bg-red-600 hover:rotate-3">
悬停旋转
</button>
<button class="bg-purple-500 text-white px-6 py-3 rounded-lg transition-all duration-300 hover:bg-purple-600 hover:skew-x-3">
悬停倾斜
</button>
</div>
<!-- 卡片悬停效果 -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
<div class="bg-white rounded-lg shadow-md overflow-hidden transition-all duration-300 hover:shadow-xl hover:-translate-y-2">
<div class="h-48 bg-gradient-to-r from-blue-400 to-blue-600"></div>
<div class="p-6">
<h3 class="text-lg font-semibold mb-2">悬停上浮卡片</h3>
<p class="text-gray-600">鼠标悬停时卡片会上浮并增强阴影效果。</p>
</div>
</div>
<div class="bg-white rounded-lg shadow-md overflow-hidden transition-all duration-300 hover:shadow-xl hover:scale-105">
<div class="h-48 bg-gradient-to-r from-green-400 to-green-600"></div>
<div class="p-6">
<h3 class="text-lg font-semibold mb-2">悬停缩放卡片</h3>
<p class="text-gray-600">鼠标悬停时卡片会轻微放大。</p>
</div>
</div>
<div class="bg-white rounded-lg shadow-md overflow-hidden transition-all duration-500 hover:shadow-xl hover:rotate-1">
<div class="h-48 bg-gradient-to-r from-purple-400 to-purple-600"></div>
<div class="p-6">
<h3 class="text-lg font-semibold mb-2">悬停旋转卡片</h3>
<p class="text-gray-600">鼠标悬停时卡片会轻微旋转。</p>
</div>
</div>
</div>
8.5.2 焦点动画
<!-- 表单焦点动画 -->
<div class="max-w-md mx-auto space-y-4">
<div class="relative">
<input
type="text"
placeholder="用户名"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-300"
>
</div>
<div class="relative">
<input
type="email"
placeholder="邮箱地址"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent focus:scale-105 transition-all duration-300"
>
</div>
<div class="relative">
<textarea
placeholder="留言内容"
rows="4"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent focus:shadow-lg transition-all duration-300 resize-none"
></textarea>
</div>
</div>
8.5.3 点击动画
<!-- 点击反馈动画 -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<button class="bg-blue-500 text-white px-6 py-3 rounded-lg transition-all duration-150 active:scale-95 active:bg-blue-600">
点击缩小
</button>
<button class="bg-green-500 text-white px-6 py-3 rounded-lg transition-all duration-150 active:scale-110 active:bg-green-600">
点击放大
</button>
<button class="bg-red-500 text-white px-6 py-3 rounded-lg transition-all duration-150 active:rotate-3 active:bg-red-600">
点击旋转
</button>
<button class="bg-purple-500 text-white px-6 py-3 rounded-lg transition-all duration-150 active:translate-y-1 active:shadow-none active:bg-purple-600 shadow-lg">
点击下沉
</button>
</div>
8.6 页面加载动画
8.6.1 加载指示器
<!-- 加载指示器 -->
<div class="flex flex-col items-center space-y-8">
<!-- 旋转加载器 -->
<div class="flex items-center space-x-2">
<div class="w-8 h-8 border-4 border-blue-500 border-t-transparent rounded-full animate-spin"></div>
<span class="text-gray-600">加载中...</span>
</div>
<!-- 脉冲加载器 -->
<div class="flex items-center space-x-2">
<div class="w-3 h-3 bg-blue-500 rounded-full animate-pulse"></div>
<div class="w-3 h-3 bg-blue-500 rounded-full animate-pulse" style="animation-delay: 0.1s"></div>
<div class="w-3 h-3 bg-blue-500 rounded-full animate-pulse" style="animation-delay: 0.2s"></div>
<span class="text-gray-600 ml-4">处理中...</span>
</div>
<!-- 弹跳加载器 -->
<div class="flex items-center space-x-1">
<div class="w-2 h-2 bg-green-500 rounded-full animate-bounce"></div>
<div class="w-2 h-2 bg-green-500 rounded-full animate-bounce" style="animation-delay: 0.1s"></div>
<div class="w-2 h-2 bg-green-500 rounded-full animate-bounce" style="animation-delay: 0.2s"></div>
<span class="text-gray-600 ml-4">同步中...</span>
</div>
<!-- 进度条加载器 -->
<div class="w-64">
<div class="flex justify-between text-sm text-gray-600 mb-1">
<span>上传进度</span>
<span>75%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-blue-500 h-2 rounded-full transition-all duration-300" style="width: 75%"></div>
</div>
</div>
</div>
8.6.2 骨架屏动画
<!-- 骨架屏加载 -->
<div class="max-w-md mx-auto bg-white rounded-lg shadow-md overflow-hidden">
<div class="animate-pulse">
<!-- 图片骨架 -->
<div class="h-48 bg-gray-300"></div>
<!-- 内容骨架 -->
<div class="p-6">
<!-- 标题骨架 -->
<div class="h-4 bg-gray-300 rounded w-3/4 mb-4"></div>
<!-- 段落骨架 -->
<div class="space-y-2">
<div class="h-3 bg-gray-300 rounded"></div>
<div class="h-3 bg-gray-300 rounded w-5/6"></div>
<div class="h-3 bg-gray-300 rounded w-4/6"></div>
</div>
<!-- 按钮骨架 -->
<div class="mt-6">
<div class="h-10 bg-gray-300 rounded w-24"></div>
</div>
</div>
</div>
</div>
<!-- 列表骨架屏 -->
<div class="max-w-2xl mx-auto mt-8 space-y-4">
<div class="animate-pulse flex space-x-4">
<div class="rounded-full bg-gray-300 h-12 w-12"></div>
<div class="flex-1 space-y-2 py-1">
<div class="h-4 bg-gray-300 rounded w-3/4"></div>
<div class="h-3 bg-gray-300 rounded w-1/2"></div>
</div>
</div>
<div class="animate-pulse flex space-x-4">
<div class="rounded-full bg-gray-300 h-12 w-12"></div>
<div class="flex-1 space-y-2 py-1">
<div class="h-4 bg-gray-300 rounded w-5/6"></div>
<div class="h-3 bg-gray-300 rounded w-2/3"></div>
</div>
</div>
<div class="animate-pulse flex space-x-4">
<div class="rounded-full bg-gray-300 h-12 w-12"></div>
<div class="flex-1 space-y-2 py-1">
<div class="h-4 bg-gray-300 rounded w-4/5"></div>
<div class="h-3 bg-gray-300 rounded w-3/5"></div>
</div>
</div>
</div>
8.7 页面过渡动画
8.7.1 页面进入动画
/* 页面进入动画 */
@keyframes pageEnter {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInFromLeft {
from {
opacity: 0;
transform: translateX(-100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideInFromRight {
from {
opacity: 0;
transform: translateX(100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.page-enter {
animation: pageEnter 0.5s ease-out;
}
.slide-in-left {
animation: slideInFromLeft 0.5s ease-out;
}
.slide-in-right {
animation: slideInFromRight 0.5s ease-out;
}
<!-- 页面内容动画 -->
<div class="page-enter">
<div class="max-w-4xl mx-auto px-4 py-8">
<h1 class="text-3xl font-bold text-gray-900 mb-6">页面标题</h1>
<p class="text-gray-600 mb-8">页面内容会以淡入上滑的方式进入。</p>
<!-- 分段动画 -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div class="slide-in-left">
<h2 class="text-xl font-semibold mb-4">左侧内容</h2>
<p class="text-gray-600">这部分内容从左侧滑入。</p>
</div>
<div class="slide-in-right">
<h2 class="text-xl font-semibold mb-4">右侧内容</h2>
<p class="text-gray-600">这部分内容从右侧滑入。</p>
</div>
</div>
</div>
</div>
8.7.2 滚动触发动画
/* 滚动触发动画 */
.scroll-reveal {
opacity: 0;
transform: translateY(50px);
transition: all 0.6s ease-out;
}
.scroll-reveal.revealed {
opacity: 1;
transform: translateY(0);
}
.scroll-reveal-left {
opacity: 0;
transform: translateX(-50px);
transition: all 0.6s ease-out;
}
.scroll-reveal-left.revealed {
opacity: 1;
transform: translateX(0);
}
.scroll-reveal-right {
opacity: 0;
transform: translateX(50px);
transition: all 0.6s ease-out;
}
.scroll-reveal-right.revealed {
opacity: 1;
transform: translateX(0);
}
<!-- 滚动动画内容 -->
<div class="space-y-16 py-16">
<div class="scroll-reveal text-center">
<h2 class="text-3xl font-bold text-gray-900 mb-4">滚动触发动画</h2>
<p class="text-gray-600">当元素进入视口时触发动画效果。</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div class="scroll-reveal-left">
<div class="bg-blue-500 text-white p-8 rounded-lg">
<h3 class="text-xl font-semibold mb-4">从左侧进入</h3>
<p>这个卡片会从左侧滑入视口。</p>
</div>
</div>
<div class="scroll-reveal-right">
<div class="bg-green-500 text-white p-8 rounded-lg">
<h3 class="text-xl font-semibold mb-4">从右侧进入</h3>
<p>这个卡片会从右侧滑入视口。</p>
</div>
</div>
</div>
<div class="scroll-reveal">
<div class="bg-purple-500 text-white p-8 rounded-lg text-center">
<h3 class="text-xl font-semibold mb-4">从下方进入</h3>
<p>这个卡片会从下方滑入视口。</p>
</div>
</div>
</div>
<script>
// 滚动动画 JavaScript
function revealOnScroll() {
const reveals = document.querySelectorAll('.scroll-reveal, .scroll-reveal-left, .scroll-reveal-right');
reveals.forEach(reveal => {
const windowHeight = window.innerHeight;
const elementTop = reveal.getBoundingClientRect().top;
const elementVisible = 150;
if (elementTop < windowHeight - elementVisible) {
reveal.classList.add('revealed');
}
});
}
window.addEventListener('scroll', revealOnScroll);
</script>
8.8 实践案例:动画组件库
8.8.1 动画按钮组件
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动画组件库</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* 自定义动画 */
@keyframes wiggle {
0%, 100% { transform: rotate(-3deg); }
50% { transform: rotate(3deg); }
}
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
}
@keyframes glow {
0%, 100% { box-shadow: 0 0 5px rgba(59, 130, 246, 0.5); }
50% { box-shadow: 0 0 20px rgba(59, 130, 246, 0.8), 0 0 30px rgba(59, 130, 246, 0.6); }
}
.animate-wiggle {
animation: wiggle 1s ease-in-out infinite;
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
.animate-glow {
animation: glow 2s ease-in-out infinite;
}
/* 按钮动画组件 */
.btn-animated {
@apply px-6 py-3 rounded-lg font-medium transition-all duration-300 relative overflow-hidden;
}
.btn-slide {
@apply bg-blue-500 text-white;
}
.btn-slide::before {
content: '';
@apply absolute top-0 left-0 w-0 h-full bg-blue-600 transition-all duration-300 z-0;
}
.btn-slide:hover::before {
@apply w-full;
}
.btn-slide span {
@apply relative z-10;
}
.btn-ripple {
@apply bg-green-500 text-white relative;
}
.btn-ripple::after {
content: '';
@apply absolute top-1/2 left-1/2 w-0 h-0 bg-white bg-opacity-30 rounded-full transition-all duration-300;
transform: translate(-50%, -50%);
}
.btn-ripple:hover::after {
@apply w-full h-full;
}
</style>
</head>
<body class="bg-gray-50 py-12">
<div class="max-w-6xl mx-auto px-4">
<h1 class="text-3xl font-bold text-center text-gray-900 mb-12">动画组件库</h1>
<!-- 基础动画按钮 -->
<section class="mb-12">
<h2 class="text-2xl font-semibold text-gray-900 mb-6">基础动画按钮</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<button class="bg-blue-500 text-white px-6 py-3 rounded-lg transition-all duration-300 hover:bg-blue-600 hover:scale-105 hover:shadow-lg">
悬停放大
</button>
<button class="bg-green-500 text-white px-6 py-3 rounded-lg transition-all duration-300 hover:bg-green-600 hover:-translate-y-1 hover:shadow-lg">
悬停上浮
</button>
<button class="bg-red-500 text-white px-6 py-3 rounded-lg transition-all duration-300 hover:bg-red-600 hover:rotate-3">
悬停旋转
</button>
<button class="bg-purple-500 text-white px-6 py-3 rounded-lg transition-all duration-300 hover:bg-purple-600 hover:skew-x-3">
悬停倾斜
</button>
</div>
</section>
<!-- 高级动画按钮 -->
<section class="mb-12">
<h2 class="text-2xl font-semibold text-gray-900 mb-6">高级动画按钮</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<button class="btn-animated btn-slide">
<span>滑动填充</span>
</button>
<button class="btn-animated btn-ripple">
波纹效果
</button>
<button class="bg-yellow-500 text-white px-6 py-3 rounded-lg transition-all duration-300 hover:bg-yellow-600 hover:animate-wiggle">
摆动效果
</button>
</div>
</section>
<!-- 持续动画 -->
<section class="mb-12">
<h2 class="text-2xl font-semibold text-gray-900 mb-6">持续动画</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="bg-blue-500 text-white p-4 rounded-lg text-center animate-pulse">
呼吸动画
</div>
<div class="bg-green-500 text-white p-4 rounded-lg text-center animate-bounce">
弹跳动画
</div>
<div class="bg-red-500 text-white p-4 rounded-lg text-center animate-float">
浮动动画
</div>
<div class="bg-purple-500 text-white p-4 rounded-lg text-center animate-glow">
发光动画
</div>
</div>
</section>
<!-- 加载动画 -->
<section class="mb-12">
<h2 class="text-2xl font-semibold text-gray-900 mb-6">加载动画</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<!-- 旋转加载器 -->
<div class="text-center">
<div class="w-12 h-12 border-4 border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
<p class="text-gray-600">旋转加载器</p>
</div>
<!-- 脉冲加载器 -->
<div class="text-center">
<div class="flex justify-center space-x-1 mb-4">
<div class="w-3 h-3 bg-green-500 rounded-full animate-pulse"></div>
<div class="w-3 h-3 bg-green-500 rounded-full animate-pulse" style="animation-delay: 0.1s"></div>
<div class="w-3 h-3 bg-green-500 rounded-full animate-pulse" style="animation-delay: 0.2s"></div>
</div>
<p class="text-gray-600">脉冲加载器</p>
</div>
<!-- 弹跳加载器 -->
<div class="text-center">
<div class="flex justify-center space-x-1 mb-4">
<div class="w-2 h-2 bg-red-500 rounded-full animate-bounce"></div>
<div class="w-2 h-2 bg-red-500 rounded-full animate-bounce" style="animation-delay: 0.1s"></div>
<div class="w-2 h-2 bg-red-500 rounded-full animate-bounce" style="animation-delay: 0.2s"></div>
</div>
<p class="text-gray-600">弹跳加载器</p>
</div>
</div>
</section>
<!-- 交互反馈 -->
<section class="mb-12">
<h2 class="text-2xl font-semibold text-gray-900 mb-6">交互反馈</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<!-- 成功反馈 -->
<div class="bg-green-50 border border-green-200 rounded-lg p-6 transition-all duration-300 hover:bg-green-100">
<div class="flex items-center">
<div class="w-8 h-8 bg-green-500 rounded-full flex items-center justify-center mr-3 animate-bounce">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
</div>
<div>
<h3 class="text-green-800 font-semibold">操作成功</h3>
<p class="text-green-600 text-sm">您的操作已成功完成</p>
</div>
</div>
</div>
<!-- 错误反馈 -->
<div class="bg-red-50 border border-red-200 rounded-lg p-6 transition-all duration-300 hover:bg-red-100">
<div class="flex items-center">
<div class="w-8 h-8 bg-red-500 rounded-full flex items-center justify-center mr-3 animate-pulse">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</div>
<div>
<h3 class="text-red-800 font-semibold">操作失败</h3>
<p class="text-red-600 text-sm">请检查输入并重试</p>
</div>
</div>
</div>
</div>
</section>
</div>
</body>
</html>
8.9 性能优化
8.9.1 动画性能最佳实践
- 使用 transform 和 opacity:这些属性不会触发重排
- 避免动画布局属性:如 width、height、margin 等
- 使用 will-change:提前告知浏览器哪些属性会变化
- 合理使用动画时长:过长的动画会影响用户体验
- 减少同时运行的动画:避免性能问题
/* 性能优化示例 */
.optimized-animation {
/* 使用 transform 而不是改变 left/top */
transform: translateX(0);
transition: transform 0.3s ease-out;
/* 提示浏览器这个属性会变化 */
will-change: transform;
}
.optimized-animation:hover {
transform: translateX(10px);
}
/* 避免的做法 */
.bad-animation {
left: 0;
transition: left 0.3s ease-out; /* 会触发重排 */
}
.bad-animation:hover {
left: 10px;
}
8.9.2 减少动画复杂度
<!-- 简化动画 -->
<div class="simple-hover transition-transform duration-300 hover:scale-105">
简单缩放动画
</div>
<!-- 避免复杂组合 -->
<div class="complex-hover transition-all duration-300 hover:scale-110 hover:rotate-3 hover:translate-x-2 hover:skew-x-1">
复杂组合动画(避免)
</div>
8.10 本章总结
在本章中,我们全面学习了 Tailwind CSS 的动画与过渡效果:
核心要点
- 过渡基础:掌握 transition 相关工具类的使用
- 变换效果:学会使用 transform 创建各种变换动画
- 预设动画:了解 Tailwind 内置动画和自定义动画
- 交互动画:实现悬停、焦点、点击等交互反馈
- 页面动画:创建页面加载和滚动触发动画
- 性能优化:遵循动画性能最佳实践
最佳实践
- 优先使用 transform 和 opacity 属性
- 保持动画简洁和流畅
- 注意动画的可访问性
- 合理控制动画时长和复杂度
- 测试动画在不同设备上的性能
下一步
在下一章中,我们将学习自定义配置,了解如何扩展和定制 Tailwind CSS。
8.11 练习题
- 按钮动画练习:创建一套具有不同悬停效果的按钮组件
- 卡片动画练习:设计一个带有加载状态和交互动画的卡片组件
- 页面过渡练习:实现一个具有滚动触发动画的着陆页
练习提示
- 从简单的过渡效果开始
- 注意动画的流畅性和性能
- 考虑用户体验和可访问性
- 测试动画在不同设备上的表现