8.1 动画与过渡概述

8.1.1 动画与过渡的区别

过渡(Transitions): - 在两个状态之间平滑变化 - 需要触发条件(如 hover、focus) - 简单的属性变化动画

动画(Animations): - 可以定义复杂的关键帧序列 - 可以自动播放或循环 - 支持多个阶段的变化

8.1.2 Tailwind CSS 动画系统

Tailwind CSS 提供了丰富的动画和过渡工具类:

  • 过渡属性transition-*
  • 过渡时长duration-*
  • 过渡时机ease-*
  • 过渡延迟delay-*
  • 预设动画animate-*
  • 变换效果transformscale-*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 动画性能最佳实践

  1. 使用 transform 和 opacity:这些属性不会触发重排
  2. 避免动画布局属性:如 width、height、margin 等
  3. 使用 will-change:提前告知浏览器哪些属性会变化
  4. 合理使用动画时长:过长的动画会影响用户体验
  5. 减少同时运行的动画:避免性能问题
/* 性能优化示例 */
.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 的动画与过渡效果:

核心要点

  1. 过渡基础:掌握 transition 相关工具类的使用
  2. 变换效果:学会使用 transform 创建各种变换动画
  3. 预设动画:了解 Tailwind 内置动画和自定义动画
  4. 交互动画:实现悬停、焦点、点击等交互反馈
  5. 页面动画:创建页面加载和滚动触发动画
  6. 性能优化:遵循动画性能最佳实践

最佳实践

  • 优先使用 transform 和 opacity 属性
  • 保持动画简洁和流畅
  • 注意动画的可访问性
  • 合理控制动画时长和复杂度
  • 测试动画在不同设备上的性能

下一步

在下一章中,我们将学习自定义配置,了解如何扩展和定制 Tailwind CSS。

8.11 练习题

  1. 按钮动画练习:创建一套具有不同悬停效果的按钮组件
  2. 卡片动画练习:设计一个带有加载状态和交互动画的卡片组件
  3. 页面过渡练习:实现一个具有滚动触发动画的着陆页

练习提示

  • 从简单的过渡效果开始
  • 注意动画的流畅性和性能
  • 考虑用户体验和可访问性
  • 测试动画在不同设备上的表现