纯css只能实现按钮中心波纹,因:active无坐标信息;js+css可精准定位点击位置,通过自定义属性控制样式与动画,需注意定位、层级及移动端兼容性。

纯CSS实现中心扩散波纹,但不依赖JS
能做,但只能从按钮中心出发,无法响应真实点击位置。这是纯CSS的硬限制——:active 伪类不提供坐标,::after 也没法读取 e.clientX。
关键配置点:position: relative + overflow: hidden 是基础;::after 必须设 content: ""、position: absolute、border-radius: 50%;动画靠 transition 控制缩放和透明度变化。
-
transform: translate(-50%, -50%) scale(0)初始状态缩成一个点 -
:active::after中把scale放大到足够覆盖按钮(比如scale(3)),同时opacity从0.3降到0 - 动画时长建议控制在
300ms–400ms,太短用户感知弱,太长拖慢操作节奏 - 注意:Safari 对
:active在某些移动端场景下触发不稳定,需加-webkit-tap-highlight-color: transparent
JS + CSS 实现点击位置精准波纹
这才是真正“指哪打哪”的方案。JS 不渲染,只记坐标;CSS 负责动画,性能不掉帧。
核心逻辑是监听 click,用 e.clientX - e.target.getBoundingClientRect().left 算出相对 X,同理算 Y;然后动态设置两个 CSS 自定义属性 --x 和 --y,CSS 动画直接读取它们定位。
- 按钮必须有
position: relative,否则::after会相对于 body 定位 -
::after的left和top改为var(--x)和var(--y),再配合transform: translate(-50%, -50%)居中圆心 - 避免重复添加动画元素:每次 click 前先
remove()已存在的波纹节点,或用 class 控制显隐 - 移动端要注意
e.touches[0]替代e.clientX,否则真机点击无反应
波纹颜色、大小、持续时间可配置
把样式参数抽成 CSS 自定义属性,就能一套代码适配多种主题,不用改 JS。
比如定义 --ripple-color: rgba(255, 255, 255, 0.5)、--ripple-duration: 400ms、--ripple-max-size: 200px,然后在 ::after 里引用它们,动画 @keyframes ripple 也用这些变量控制关键帧。
-
width和height可绑定--ripple-max-size,避免小按钮撑开布局 - 动画
animation属性写成ripple var(--ripple-duration) ease-out forwards,方便全局统一调控 - 深色模式下,
--ripple-color可设为rgba(255, 255, 255, 0.2),浅色模式用rgba(0, 0, 0, 0.15) - 别忘了给
::after加pointer-events: none,否则新插入的元素会拦截后续点击
常见错误:波纹不显示或卡在中间
90% 是定位或层级问题,不是动画写错了。
- 忘记给按钮加
position: relative→ 波纹飞到页面左上角 -
overflow: hidden没设 → 波纹溢出按钮边界,像炸开一样难看 -
::after缺少content: ""→ 伪元素根本不会渲染 - 动画用了
transition却没触发状态变化(比如没写:active或没调用classList.add())→ 看不到任何效果 - 移动端点击后波纹一闪就消失 → 没处理
touchstart,或者click事件被延迟 300ms
真正麻烦的是多层嵌套按钮或 flex/grid 布局里的定位偏移,这时候 getBoundingClientRect() 算出的坐标得再减一次父容器的 scrollLeft/scrollTop —— 很少人想到这点,但线上真会出问题。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











