Bootstrap 5 按钮默认不支持 ripple,需手动实现:通过 position: relative + ::after 伪元素模拟水波纹,JS 计算点击坐标并动态设置 left/top,配合 scale 和 opacity 动画,使用 pointerdown 防延迟与连点,兼顾移动端与不同尺寸按钮。

Bootstrap 5 按钮默认不支持 ripple,需手动实现
Bootstrap 5 官方移除了 ripple 效果(它在 Bootstrap 4 的部分主题或 MDBootstrap 中存在),原生 btn 类完全依赖纯 CSS hover/focus 状态,没有水波纹逻辑。想加涟漪,必须自己写 ::after 伪元素 + 动画 + JS 触发坐标计算。
用 position: relative + ::after 伪元素模拟涟漪
核心是让按钮可定位,再动态插入一个圆形遮罩层并缩放淡出。关键点不是“加动画”,而是“让圆心落在点击位置”——这必须靠 JS 获取 clientX/clientY 相对于按钮左上角的偏移。
- 按钮需设
position: relative,否则::after无法相对于它定位 -
::after必须设content: ""、position: absolute、border-radius: 50% - 初始
width/height设为0,opacity设为0.3左右,background推荐用currentColor或固定色值(如#000) - 动画用
transform: scale(2)+opacity: 0,时长建议600ms,缓动用cubic-bezier(0.4, 0, 0.2, 1)更自然
JS 必须监听 click 并计算点击坐标
只靠 CSS 无法响应点击位置,:active 伪类只能全区域触发,做不到中心定位。必须用 JS:
- 给所有带
data-ripple的按钮绑定click事件(避免污染全局btn) - 用
event.clientX - button.getBoundingClientRect().left算 X 偏移,同理算 Y - 把这两个值设为
::after的left和top(注意单位是px) - 插入后,等动画结束自动移除该
::after元素(否则残留 DOM 节点影响性能)
示例片段:
立即学习“前端免费学习笔记(深入)”;
button.addEventListener('click', (e) => {
const rect = button.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const ripple = document.createElement('span');
ripple.style.left = `${x}px`;
ripple.style.top = `${y}px`;
ripple.classList.add('ripple');
button.appendChild(ripple);
setTimeout(() => ripple.remove(), 600);
});兼容性与性能容易被忽略的点
移动端点击有 300ms 延迟,默认会触发 click 两次(touchstart + click),导致涟漪叠加快速闪烁。解决方案不是禁用 touchstart,而是用 pointerdown 替代 click,并加防抖:
-
pointerdown在触控和鼠标下都可靠,且无延迟 - 用
setTimeout+ 标志位防止快速连点生成多个涟漪 - 动画用
transform和opacity,避免触发重排(re-layout) - 如果按钮含图标(如
<i class="bi bi-plus"></i>),确保ripple层级高于图标(z-index: 1)
真正麻烦的是:不同尺寸按钮(btn-sm / btn-lg)需要统一涟漪最大半径,否则小按钮上涟漪溢出。建议在 JS 中按 Math.max(button.width, button.height) * 1.5 动态设 max-width/max-height。


















