径向波纹效果本质是遮罩层动画,依赖圆形伪元素的scale和opacity动画;radial-gradient仅静态填充背景,不参与动画;按钮需relative定位,伪元素用absolute+translate居中;JS动态计算点击坐标以实现真实落点波纹。
很多人误以为 @keyframes 需要配合 radial-gradient 实现波纹,其实不然。真实可落地的波纹效果依赖的是一个「圆形 ::after 伪元素」从中心点放大并透明度渐隐——radial-gradient 在这里仅用于背景填充,不参与动画逻辑。用渐变做动画会触发重绘(paint),性能差,且无法精确控制起始半径和扩散节奏。
transform: scale() 和 opacity
radial-gradient 只在伪元素上静态设置为纯色(如 radial-gradient(circle, rgba(0,0,0,0.2) 0%, transparent 70%)),它本身不随帧变化forwards,否则波纹缩回后会闪一下如果按钮没设 position: relative,::after 默认按文档流渲染,top: 50%; left: 50% 会相对于最近的定位祖先计算,结果偏移不可控。波纹看起来“歪了”或“飞出按钮外”,基本都是这个原因。
position: relative 是强制前提position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0)
scale(0) 比 width/height: 0 更可靠——避免 Safari 下 0 尺寸元素触发渲染 bug把 background 放进 @keyframes 会导致每帧重绘渐变,Chrome DevTools 的 Rendering 面板里能看到频繁的 paint 事件。实测在中低端安卓机上容易掉帧。
background: radial-gradient(circle, rgba(255,255,255,0.3) 0%, transparent 70%)
@keyframes ripple 里只包含 transform: scale(4) 和 opacity: 0
@keyframes ripple { to { transform: translate(-50%, -50%) scale(4); opacity: 0; }}
固定居中只能模拟“按下整个按钮”的感觉;真实点击波纹必须从鼠标/手指落点出发。CSS 本身做不到这点,必须靠 JS 获取 clientX/clientY 并设置伪元素的 left 和 top。
立即学习“前端免费学习笔记(深入)”;
click 或 touchstart,用 getBoundingClientRect() 算相对偏移x、y 塞进伪元素的 style.left 和 style.top
scale 和 opacity),避免多层叠加卡顿touchstart 要 preventDefault() 否则可能触发双击缩放