Chapter 06

动画与过渡

transition 过渡、内置 animate- 动画、自定义 @keyframes,以及无障碍动画设计

1. Transition 过渡

过渡(transition)让属性值的变化从突变变成平滑动画。Tailwind 提供了一套完整的过渡工具类。

<!-- transition: 过渡所有可动画属性 -->
<div class="transition hover:scale-105">悬浮放大</div>

<!-- 指定过渡属性 -->
<button class="transition-colors duration-200 bg-cyan-500 hover:bg-cyan-600">
  只过渡颜色
</button>

<div class="transition-transform duration-300 hover:-translate-y-2">
  只过渡位移(卡片上浮效果)
</div>

<div class="transition-opacity duration-500 hover:opacity-70">
  只过渡透明度
</div>

<!-- duration: 过渡时长 -->
<!-- 75 / 100 / 150 / 200 / 300 / 500 / 700 / 1000 ms -->
<div class="transition duration-700">700ms 缓慢过渡</div>

<!-- ease: 缓动函数 -->
<div class="transition ease-in-out">进出都有缓动</div>
<div class="transition ease-spring">弹簧缓动(v4 新增)</div>

<!-- delay: 延迟 -->
<div class="transition delay-150">延迟 150ms 后开始过渡</div>

2. 内置 animate- 动画

Tailwind 内置了 4 个常用动画类,适用于加载状态、提示、通知等场景:

类名效果典型用途
animate-spin360° 持续旋转loading 转圈图标
animate-ping从中心向外扩散+透明通知红点、实时状态
animate-pulse透明度 1→0.5 循环骨架屏占位
animate-bounce上下弹跳向下滚动提示箭头
<!-- animate-spin:loading 旋转图标 -->
<svg class="animate-spin h-5 w-5 text-cyan-500" viewBox="0 0 24 24">
  <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
  <path class="opacity-75" fill="currentColor"
    d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/>
</svg>

<!-- animate-ping:实时状态绿点 -->
<span class="relative flex h-3 w-3">
  <span class="animate-ping absolute inline-flex h-full w-full
                   rounded-full bg-green-400 opacity-75"></span>
  <span class="relative inline-flex rounded-full h-3 w-3 bg-green-500"></span>
</span>

<!-- animate-bounce:向下箭头 -->
<div class="animate-bounce text-center text-gray-400">
  ↓ 向下滚动
</div>

3. 骨架屏(Skeleton)实战

animate-pulse 是构建骨架屏的核心动画——给占位元素添加灰色背景 + 脉冲动画,模拟内容加载中的状态。

<!-- 文章卡片骨架屏 -->
<div class="bg-white rounded-xl p-6 space-y-4 max-w-sm">
  <!-- 头像 + 用户名行 -->
  <div class="flex items-center gap-3">
    <div class="animate-pulse w-10 h-10 rounded-full bg-gray-200"></div>
    <div class="flex-1 space-y-2">
      <div class="animate-pulse h-3 bg-gray-200 rounded w-3/4"></div>
      <div class="animate-pulse h-2 bg-gray-200 rounded w-1/2"></div>
    </div>
  </div>

  <!-- 封面图 -->
  <div class="animate-pulse h-40 bg-gray-200 rounded-lg"></div>

  <!-- 标题 -->
  <div class="space-y-2">
    <div class="animate-pulse h-4 bg-gray-200 rounded w-full"></div>
    <div class="animate-pulse h-4 bg-gray-200 rounded w-5/6"></div>
    <div class="animate-pulse h-4 bg-gray-200 rounded w-4/6"></div>
  </div>

  <!-- 底部按钮 -->
  <div class="animate-pulse h-9 bg-gray-200 rounded-lg"></div>
</div>

4. 自定义动画 @keyframes

v4 中在 @theme 里扩展动画,完全基于原生 CSS:

/* style.css */
@import "tailwindcss";

@theme {
  /* 定义关键帧动画 */
  --animate-wiggle: wiggle 0.5s ease-in-out infinite;
  --animate-slide-in: slide-in 0.3s ease-out;
  --animate-fade-up: fade-up 0.4s ease-out;
}

@keyframes wiggle {
  0%, 100% { transform: rotate(-3deg); }
  50% { transform: rotate(3deg); }
}

@keyframes slide-in {
  from { transform: translateX(-100%); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

@keyframes fade-up {
  from { transform: translateY(16px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
<!-- 使用自定义动画类 -->
<div class="animate-wiggle">摇摆动画</div>
<div class="animate-slide-in">从左滑入</div>
<div class="animate-fade-up">向上淡入</div>

5. motion-safe / motion-reduce 无障碍

部分用户(如有前庭障碍)对动画敏感,可能配置操作系统开启"减少动态效果"(Reduce Motion)。Tailwind 提供两个对应的变体前缀:

<!-- motion-safe: 只在用户未开启 Reduce Motion 时生效 -->
<div class="motion-safe:animate-bounce">
  尊重用户偏好的弹跳动画
</div>

<!-- motion-reduce: 只在用户开启 Reduce Motion 时生效(提供简化版)-->
<div class="
  transition-transform duration-500
  hover:-translate-y-2
  motion-reduce:transition-none
  motion-reduce:hover:translate-y-0
">
  开启减少动效时取消过渡
</div>

最佳实践:凡是纯装饰性动画,都加上 motion-safe: 前缀;核心交互反馈动画保留(用户需要知道操作已生效),但用 motion-reduce: 提供简化版(如 0ms 过渡而非消除)。这是无障碍(a11y)设计的重要组成部分。