1. 水波纹效果的工作原理
1.1 基本原理与视觉表现
在按钮被点击时,水波纹作为一个圆形光波从点击点向外扩散,产生自然的反馈感。这种效果通常通过在按钮上方叠加一个圆形元素实现,圆圈的初始半径很小,随后通过 动画放大 与 淡出 来模拟波纹扩散。
为了让波纹能在任意点击位置出现,我们需要将波纹的起点设定为点击位置,并让伪元素在按钮内部对齐。这里可以使用 ::after 伪元素作为波纹的载体,并通过 CSS 动画 实现放大与透明度变化。
在性能方面,这种实现通常通过 transform 与 opacity 的组合来触发 GPU 加速,确保在移动端也有平滑表现,且避免对页面其他元素的重排。
1.2 为什么要用 ::after 伪元素?
使用 ::after 的好处是可以避免额外的 HTML 结构,让按钮保持简洁,同时通过 伪元素的定位 和 动画属性 来实现视觉效果。
此外,利用伪元素可以更容易地控制波纹的颜色、亮度与混合模式,从而实现不同风格的反馈,例如白色高对比度波纹或半透明蓝色波纹,提升用户体验与界面的一致性。
2. 伪元素与按钮结构设计
2.1 伪元素定位与尺寸
要让水波纹从点击点开始扩散,必须把伪元素的定位设定为按钮内部的绝对定位,同时让其中心点与点击点对齐。左上角起点、圆形尺寸和圆心对齐是核心要点。
通常会为伪元素设定一个较大的初始尺寸(例如 180px 直径),再通过动画从 scale(0) 演变到 scale(1),在扩散结束时逐渐淡出,以避免阻塞后续交互。
实现时,若要支持任意点击位置的波纹,需要通过 JavaScript 读取点击坐标并动态写入 CSS 变量(如 --x、--y),从而让 ::after 的 left/top 值指向实际点击点。
3. animation 与关键帧设计
3.1 关键帧设计与性能要点
水波纹的核心在于一个简短、平滑的放大与淡出动画。关键帧通常定义为从圆心处的 scale(0) 变为 scale(1),同时渐隐以模拟能量扩散后散去的效果。
在实现时应关注 时间函数、持续时间和浏览器的渲染性能。ease-out 常用于波纹的自然减速,而对于需要更快的反馈,可以选择 ease-in-out。同时,考虑到 prefers-reduced-motion,应在用户开启减速动效时禁用或改为少量动画。
4. 实战演练:完整的代码示例
4.1 HTML 结构
在真实页面中,按钮通常放在一个容器内并承载文本或图标。下面给出一个简洁的按钮示例,用于演示水波纹效果的触发点与结构关系。
通过这段结构,可以将水波纹作为按钮的内外层视觉反馈,保持语义清晰且易于样式扩展。

按钮水波纹示例
4.2 CSS 与 JavaScript 实现
为了实现点击位置的水波纹,需要在 CSS 中给按钮增加定位与伪元素样式,并用 JavaScript 在每次点击时把点击点的坐标以 CSS 变量的形式传给伪元素。下面给出完整的实现要点:定位、溢出隐藏、伪元素的圆圈、以及交互触发的变量传递。
/* 按钮基础样式 */
.ripple-btn {position: relative;overflow: hidden;padding: 14px 28px;border: none;border-radius: 8px;background: #4a90e2;color: #fff;font-size: 16px;cursor: pointer;outline: none;/* 让动画更平滑地发生在 GPU 上 */will-change: transform;
}/* 波纹伪元素样式:圆形载体,初始置于点击点,缩放为 0 */
.ripple-btn::after {content: '';position: absolute;width: 180px;height: 180px;left: var(--x, 50%);top: var(--y, 50%);transform: translate(-50%, -50%) scale(0);background: rgba(255, 255, 255, 0.65);border-radius: 50%;pointer-events: none;opacity: 0;transition: transform 0.6s ease-out, opacity 0.6s ease-out;mix-blend-mode: overlay;
}/* 触发波纹动画的状态:让伪元素执行放大动画 */
.ripple-btn.ripple-active::after {transform: translate(-50%, -50%) scale(1);opacity: 0.9;
}@media (prefers-reduced-motion: reduce) {.ripple-btn::after { display: none; }
}
// 监听按钮点击,计算点击点相对按钮的坐标,并触发波纹动画
document.addEventListener('DOMContentLoaded', function() {var btn = document.getElementById('btn-demo');btn.addEventListener('mousedown', function(e) {var rect = this.getBoundingClientRect();var x = e.clientX - rect.left; // 相对于按钮左边的水平坐标var y = e.clientY - rect.top; // 相对于按钮顶端的垂直坐标// 将坐标写入 CSS 变量,作为 ::after 的圆心this.style.setProperty('--x', x + 'px');this.style.setProperty('--y', y + 'px');// 触发波纹动画this.classList.add('ripple-active');// 动画结束后移除状态,便于下次触发setTimeout(() => this.classList.remove('ripple-active'), 700);});
});
以上实现中,HTML 结构保持简洁,主要依赖 ::after 伪元素作为波纹载体,并通过 JavaScript 动态将点击坐标传递给 CSS 变量,从而实现从点击点出发的水波纹扩散效果。


