不能直接用 :active 触发波纹动画,因为 Tailwind 默认不生成 active: 变体类(v2.x 需手动启用,v3.x 即使启用也难对齐动画节奏);更关键的是,:active 状态只在按下瞬间存在(通常毫秒级),而波纹动画需 200ms 以上才能被感知,导致动画未播完即中断或错位。

为什么不能直接用 :active 触发波纹动画
因为 Tailwind 默认不生成 active: 变体类(v2.x 需手动启用,v3.x 即使启用也难对齐动画节奏);更关键的是,:active 状态只在按下瞬间存在(通常 active:animate-ripple,编译后压根没这条 CSS 规则——它被 PurgeCSS 删了,或者根本没注册进构建流程。
必须自己定义 @keyframes ripple 并注册进配置
Tailwind 不内置波纹动画,得手写关键帧并显式注册。漏掉任一环,animate-ripple 就不会生效:
-
tailwind.config.js的theme.extend.keyframes里加:{ 'ripple': 'ripple 250ms ease-out' } -
theme.extend.animation里加:{ 'ripple': 'ripple 250ms ease-out' } - keyframes 名称必须完全一致(含连字符、大小写),百分比写成
'0%'和'100%',不能写from/to - 动画时长建议设为
250ms,太短用户感知不到,太长拖慢交互节奏
用 JavaScript 动态创建波纹节点最可靠
纯 CSS 伪类做不到“从点击点中心扩散 + 渐隐”,必须 JS 计算坐标、插入 DOM、控制生命周期:
- 按钮容器必须加
relative和overflow-hidden,否则波纹溢出边界 - 监听
mousedown(不是click),iOS 上click有 300ms 延迟,波纹会滞后 - 移动端还要监听
touchstart,取touches[0].clientX/Y,不能只用clientX - 波纹元素要加
pointer-events-none,避免遮挡后续点击 - 动画结束必须手动
remove()节点,否则高频点击会导致内存泄漏
阴影和过渡必须和波纹节奏对齐
别混用 active:shadow-sm 这类瞬时工具类——它只闪一下(约 100ms),而波纹播 250ms,视觉上会先缩再扩,明显割裂:
- 删掉所有
active:shadow-*类 - 改用
transition-shadow+focus:shadow-lg或自定义data-ripple="true"状态控制阴影变化 - 如果按钮本身有
hover:shadow-md,确保它的过渡时长和波纹一致(比如都设为250ms) - 波纹尺寸建议动态设为
Math.max(btn.offsetWidth, btn.offsetHeight) * 2,固定200px在小按钮上会溢出,在大按钮上又太小
实际中最容易被忽略的,是波纹节点的 pointer-events-none 和动画结束后的 remove() —— 前者导致按钮点不动,后者积累 DOM 节点,页面卡顿。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











