box-shadow 是实现脉冲圆圈动画最轻量可靠的方式,因其不触发重排、支持 gpu 加速且无需 js;关键帧需三段式节奏(0%略收、70%快扩、100%缓散),并注意 border-radius、颜色格式与像素匹配。

纯 CSS 实现脉冲圆圈动画,box-shadow 是最轻量、最可靠的方式——它不触发重排,能 GPU 加速,且无需 JS 就能做出“向外扩散”的视觉错觉。
为什么用 box-shadow 而不是 transform: scale()
关键区别在于渲染路径:box-shadow 只影响绘制层(paint),而 scale() 若作用在非 position: absolute 元素上,容易因布局计算引发重排;更隐蔽的问题是:当元素有内容或边框时,scale() 会连带缩放文字或边框粗细,破坏设计一致性。而 box-shadow 扩散完全独立于元素本体,只控制“光晕”大小和透明度。
常见错误包括:
- 直接给
div设width/height动画,导致 layout thrashing - 忘了设
border-radius: 50%,圆环变方块 - 用
rgba(…, 0)做透明终点,但没配animation-timing-function: ease-out,看起来像戛然而止
@keyframes pulse 的关键帧怎么写才自然
真正“呼吸感”来自三段式节奏:起始略收(避免突兀)、中段快速扩张、末段缓慢消散。推荐写法:
@keyframes pulse {
0% {
box-shadow: 0 0 0 0 rgba(233, 29, 182, 0.4);
}
70% {
box-shadow: 0 0 0 25px rgba(233, 29, 182, 0.1);
}
100% {
box-shadow: 0 0 0 35px rgba(233, 29, 182, 0);
}
}
注意点:
- 不要只写
to,必须显式定义70%中间态,否则浏览器插值会拉平过渡,失去“爆发→衰减”的节奏 - 颜色通道建议用十六进制或 rgb(),避免 hsl() 在部分安卓 WebView 中解析异常
- 像素值(如
25px)要和基础圆直径匹配——若圆本身是40px宽,阴影从0到35px才显得协调
多层脉冲怎么叠加而不卡顿
伪元素(::before/::after)最多只能两层,且无法动态增删或单独控制延迟。真需求如“按钮点击弹出 3 圈波纹”,必须用 JS 插入真实元素:
- 每次点击新建一个
<span class="ripple"></span>,append 到目标按钮内 - 用 JS 设置
ripple.style.animationDelay = `${i * 0.15}s`,控制每圈节奏 - 务必加
pointer-events: none到.ripple,否则新插入的元素会拦截后续点击 - 动画结束后调用
element.remove(),否则高频点击 1 分钟后 DOM 节点可能破千
性能敏感场景(比如地图标记密集区域),建议限制最大并发波纹数,超过则丢弃旧的。
移动端点击不触发?先查这三件事
iOS 和部分安卓 WebView 对 click 事件有延迟或吞掉行为,导致波纹“有 log 无动画”。优先排查:
- 按钮是否设了
touch-action: manipulation?缺了它,iOS 会等 300ms 确认是否双击 - 有没有定义
button:active { opacity: 0.7; }这类样式?它可能和波纹动画冲突,遮盖初始帧 - 是否在
click回调里用了event.preventDefault()却没传参?漏写(e)导致事件对象丢失,e.target拿不到
最稳妥的写法是监听 touchstart + mousedown 双事件,并在回调开头加 if (e.cancelable) e.preventDefault()。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











