:active无法实现波纹效果,因其仅瞬时触发、不支持伪元素定位及transform/opacity组合过渡;真实波纹需JS创建临时元素或结合::after伪元素与动态坐标计算。

点击波纹效果为什么不能直接用 :active 实现
因为 :active 仅在手指按下的瞬间触发,松开就消失,无法撑开一个渐变扩散的圆形波纹;而且它不支持伪元素动态定位,更没法做 transform: scale() + opacity 的组合过渡。真实波纹必须由 JS 创建临时元素或用伪元素 + 动态计算实现。
用 ::after 伪元素 + JS 计算位置的核心步骤
波纹本质是:在点击坐标生成一个绝对定位的圆形 ::after,初始 scale(0) + opacity: 0.3,然后 transition 到 scale(3) + opacity: 0。关键在于让伪元素中心对准点击点 —— 这必须靠 JS 把 left 和 top 写进元素的 style 里(伪元素无法通过 CSS 变量传坐标)。
- 给卡片加
position: relative,确保伪元素能相对于它定位 - 监听
touchstart(移动端优先)和mousedown(兼容桌面),避免click延迟 - 用
event.touches[0]或event.clientX/clientY减去卡片getBoundingClientRect()得到相对坐标 - 把计算出的
left和top写入元素的style.setProperty('--ripple-x', ...),再在 CSS 中用left: calc(var(--ripple-x) - 50%)居中
transition 要设在哪?哪些属性必须一起过渡
波纹动画只依赖两个属性:transform(控制缩放)和 opacity(控制淡出)。它们必须写在同一个 transition 声明里,否则会出现缩放完成但透明度卡住、或反之的撕裂感。不能只写 transition: all .3s —— 这会把 left/top 也纳入过渡,导致波纹偏移轨迹异常。
- 推荐写法:
transition: transform .3s cubic-bezier(0.25, 0.46, 0.45, 0.94), opacity .3s cubic-bezier(0.25, 0.46, 0.45, 0.94) - 伪元素必须设
pointer-events: none,否则会拦截后续点击 - 动画结束后需 JS 移除波纹元素或重置状态,否则重复点击会堆积多个
::after(CSS 伪元素本身不可删,得靠 class 控制显隐)
真机上波纹不触发或延迟的常见原因
iOS Safari 和部分安卓 WebView 对 touchstart 的处理较保守,比如页面有 meta viewport 缺失、或容器设置了 touch-action: none,都会阻止原生点击反馈,连带影响波纹触发。另外,如果卡片内容区域有 user-select: none 但没配 -webkit-tap-highlight-color: transparent,iOS 下可能先闪一下蓝灰高亮,再播波纹,视觉冲突。
- 必加 meta:
- 卡片根元素加:
-webkit-tap-highlight-color: transparent - 避免在父容器设
touch-action: none,如需禁用拖拽,改用touch-action: manipulation - Android Chrome 有时对
transform: scale()在伪元素上渲染不稳,可加will-change: transform强制 GPU 加速
波纹半径和持续时间要根据卡片尺寸动态调整,固定写死 scale(3) 在小按钮上会溢出,在大卡片上又显得太弱 —— 最好用 JS 算最大直径(比如取卡片宽高的 1.5 倍),再反推 scale 值。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











