Bootstrap 5 按钮真涟漪必须用 JS 动态定位 + CSS transform/opacity 动画实现,因 :active 生命周期短、无法读取点击坐标、伪元素不能动态设 left/top;需 position: relative + overflow: hidden + ::after 圆形元素 + 动画清理。

Bootstrap 5 按钮默认没有涟漪动画,:active 只能触发瞬时样式变化,无法实现从点击点扩散的圆形水波纹。真涟漪必须靠 JS 动态定位 + CSS transform: scale() + opacity 动画组合完成。
为什么纯 CSS :active::after 做不出真涟漪
你看到的“纯 CSS 涟漪”几乎全是固定中心、固定大小的缩放动画,本质是模拟:
-
:active生命周期太短(毫秒级),撑不起完整动画过程 - 无法读取
clientX/clientY,涟漪起点永远在左上角或中心,不响应真实点击位置 - 伪元素不能动态设置
left/top—— CSS 里写死的值对所有点击都一样 - 用
%单位设left/top会导致永远居中,彻底失去定位能力
必须加的 HTML 和 CSS 基础结构
按钮本身要为涟漪提供定位上下文:
- 给按钮加
position: relative和overflow: hidden(防止涟漪溢出) - 涟漪伪元素用
::after,content: ""+position: absolute+border-radius: 50% - 动画只允许用
transform和opacity—— 改width/height会触发重排,卡顿且不准 - 涟漪初始状态设
transform: scale(0)、opacity: 0,过渡用transition: transform 0.45s ease-out, opacity 0.45s ease-out
JS 动态定位的关键计算逻辑
坐标计算错一点,涟漪就偏移;没清理节点,连点后会堆积残留:
立即学习“前端免费学习笔记(深入)”;
- 监听
click(PC)和touchstart(移动端,避免 300ms 延迟),且passive: false - 用
getBoundingClientRect()获取按钮视口坐标,再减去event.clientX - rect.left得到相对 X 坐标 - 不要用
offsetX/offsetY—— Firefox 不支持,Safari 行为不一致 - 涟漪直径建议设为
Math.max(rect.width, rect.height) * 1.4,保证全覆盖又不夸张 - 动画结束必须监听
animationend或transitionend,然后移除涟漪类或删除 DOM 节点
移动端适配和性能陷阱
真机上涟漪卡顿、边缘锯齿、甚至不触发,往往不是代码写错,而是渲染层没优化:
- 移动端必须用
touchstart,取touches[0].pageX而非clientX - iOS Safari 对
transform动画优化差,涟漪元素要加will-change: transform(仅动画期间设,结束后移除) - 父容器有
transform(如scale(0.9)或translateZ(0))会创建新定位上下文,导致getBoundingClientRect()失真 —— 此时涟漪应挂到该父级下,并重新算坐标 - 快速连点时,多个涟漪可能叠加,需节流或用
requestAnimationFrame控制插入时机
最难的不是写出动画,而是让每个涟漪都精准锚定在毫秒级的点击位置,同时不干扰后续交互、不堆积 DOM、不卡顿。坐标计算、定位上下文、动画清理这三点,漏一个就失效。


















