TailwindCSS 动画和过渡如何实现?
TailwindCSS 做动画主要分两类:一种是用 animate-* 直接套关键帧动画,比如加载、提示、状态闪烁;另一种是用 transition-* 处理状态变化,比如 hover、focus、active 时的颜色、位移、透明度变化。前者适合“自己一直动”的效果,后者适合“用户触发后平滑变化”的效果。
内置动画怎么用
TailwindCSS 默认提供了几个常用动画,日常 UI 里够用一大半。
html<!-- 旋转:常用于 loading 图标 --> <div class="animate-spin rounded-full h-8 w-8 border-2 border-blue-500 border-t-transparent"></div> <!-- 弹跳:常用于引导或轻提示 --> <div class="animate-bounce">向下看</div> <!-- 脉冲:常用于骨架屏或占位状态 --> <div class="animate-pulse h-4 w-40 rounded bg-gray-200"></div> <!-- ping:常用于通知点、在线状态 --> <span class="relative flex h-3 w-3"> <span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-400 opacity-75"></span> <span class="relative inline-flex h-3 w-3 rounded-full bg-green-500"></span> </span>
animate-spin 是持续旋转,animate-bounce 是上下弹动,animate-pulse 是透明度脉冲,animate-ping 是向外扩散。不要把 ping 理解成摇摆,它更像雷达波纹。
过渡效果怎么写
过渡靠三类工具类配合:过渡属性、持续时间、缓动方式。常见写法是先指定变化属性,再加 duration-* 和 ease-*。
html<button class="bg-blue-500 px-4 py-2 text-white transition-colors duration-200 ease-out hover:bg-blue-600"> 颜色过渡 </button> <div class="transition-transform duration-300 ease-in-out hover:scale-105"> 缩放过渡 </div> <div class="transition-opacity duration-200 hover:opacity-70"> 透明度过渡 </div>
常用过渡类可以这样选:transition-colors 适合颜色变化,transition-opacity 适合淡入淡出,transition-transform 适合缩放、旋转、位移,transition-shadow 适合卡片阴影变化,transition-all 只适合快速试效果,正式代码别滥用。
按钮、输入框这类即时反馈通常用 duration-150 或 duration-200;卡片 hover、弹层淡入可以用 duration-300;再慢就容易让用户觉得页面拖沓。
html<button class="transition-colors delay-75 duration-150 ease-out hover:bg-blue-500"> 带延迟的按钮 </button> <div class="transition-transform duration-[450ms] ease-[cubic-bezier(.22,1,.36,1)] hover:-translate-y-1"> 自定义时间和贝塞尔曲线 </div>
自定义动画:Tailwind v3 写法
Tailwind CSS v3 通常在 tailwind.config.js 里扩展 keyframes 和 animation。
jsmodule.exports = { theme: { extend: { keyframes: { 'fade-in': { '0%': { opacity: '0' }, '100%': { opacity: '1' }, }, 'slide-up': { '0%': { opacity: '0', transform: 'translateY(12px)' }, '100%': { opacity: '1', transform: 'translateY(0)' }, }, wiggle: { '0%, 100%': { transform: 'rotate(-3deg)' }, '50%': { transform: 'rotate(3deg)' }, }, }, animation: { 'fade-in': 'fade-in 300ms ease-out both', 'slide-up': 'slide-up 400ms ease-out both', wiggle: 'wiggle 1s ease-in-out infinite', }, }, }, };
使用时和内置动画一样:
html<div class="animate-fade-in">淡入内容</div> <div class="animate-slide-up">上滑进入</div> <button class="animate-wiggle">有提示的按钮</button>
自定义动画:Tailwind v4 的 @theme 写法
Tailwind CSS v4 更偏 CSS-first,可以在 CSS 里通过 @theme 定义动画变量和关键帧。
css@import "tailwindcss"; @theme { --animate-fade-in: fade-in 300ms ease-out both; --animate-slide-up: slide-up 400ms ease-out both; @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } @keyframes slide-up { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } } }
定义后可以直接写:
html<div class="animate-fade-in">淡入</div> <div class="animate-slide-up">上滑</div>
如果项目已经升级到 v4,优先用 @theme 管动画;还在 v3,就继续放在 tailwind.config.js 里。
任意动画值怎么写
一次性的动画,不一定要进配置。Tailwind 支持任意值语法,空格用下划线代替。
html<div class="animate-[bounce_1s_ease-in-out_infinite]">自定义 bounce 参数</div> <div class="animate-[fade-in_400ms_ease-out_both]">一次性淡入动画</div> <div class="transition-[height] duration-300 ease-out">只过渡 height</div>
这种写法适合临时效果、原型页、只出现一次的特殊动画。如果团队里很多地方都在复用同一个动画,还是放进主题配置更清楚。
常见场景示例
加载动画要轻,不要抢注意力。图标旋转、骨架屏脉冲、三个点弹跳都比较常见。
html<div class="flex items-center gap-3"> <div class="h-5 w-5 animate-spin rounded-full border-2 border-gray-300 border-t-blue-500"></div> <span class="text-sm text-gray-600">加载中...</span> </div> <div class="space-y-3 animate-pulse"> <div class="h-4 w-2/3 rounded bg-gray-200"></div> <div class="h-4 w-full rounded bg-gray-200"></div> </div>
hover 最好只动一点点。按钮放大 5%、卡片上移 4px、阴影变深,已经足够让用户知道“这里能点”。
html<button class="rounded bg-blue-500 px-4 py-2 text-white transition-transform duration-150 ease-out hover:scale-105 active:scale-95"> 保存 </button> <div class="rounded-xl bg-white p-6 shadow transition-[transform,box-shadow] duration-300 ease-out hover:-translate-y-1 hover:shadow-lg"> <h2 class="font-semibold">卡片标题</h2> </div>
页面或弹层进入时,常用淡入加轻微位移。幅度不要太大,否则会像 PPT 动画。
html<section class="animate-slide-up"> <h2 class="text-xl font-semibold">页面内容</h2> </section> <div class="animate-fade-in rounded-lg bg-white p-6 shadow-lg"> 弹层内容 </div>
性能上要注意什么
动画性能先看你动了什么属性。优先动 transform 和 opacity,它们通常更容易被浏览器合成层处理,不容易频繁触发布局计算。
html<div class="transition-transform duration-300 hover:-translate-y-1 hover:scale-105">更流畅</div> <div class="transition-opacity duration-200 hover:opacity-70">淡入淡出</div>
will-change 不是越多越好。它是在提前告诉浏览器“这个元素马上要动”,用在少量关键动画上有帮助;如果给一堆列表项长期加 will-change-transform,反而可能占用更多内存。
transition-all 也不要长期滥用。正式组件里优先写 transition-colors、transition-transform、transition-opacity,确实需要多个属性时再用 transition-[transform,box-shadow] 这类更明确的写法。
如何照顾减少动画的用户
有些用户在系统里开启了“减少动态效果”,Tailwind 可以用 motion-safe: 和 motion-reduce: 处理。
html<div class="motion-safe:animate-bounce motion-reduce:animate-none"> 尊重系统动画偏好 </div> <div class="transition-transform duration-300 motion-reduce:transition-none motion-safe:hover:scale-105"> 减少动态效果时不做缩放过渡 </div>
持续循环、闪烁、快速位移这类动画尤其应该加上降级处理。
实际使用时怎么选
如果是加载、通知点、骨架屏,先看内置的 animate-spin、animate-ping、animate-pulse、animate-bounce 能不能解决。只是 hover、focus、active 的状态变化,用 transition-colors、transition-transform、transition-opacity 就好。
需要复用的品牌动画,v3 放到 tailwind.config.js,v4 放到 @theme。只用一次的特殊效果,可以用 animate-[...] 或任意过渡值。性能上少动布局属性,多用 transform 和 opacity;可访问性上记得给明显动画配 motion-safe 和 motion-reduce。这样写出来的动效不花哨,但稳定、顺滑,也更适合真实项目维护。