粒子需用 position: absolute 脱离文档流,以 left/top 锚定点击坐标为起点,再用 transform: translate(x,y) 实现硬件加速扩散;数量控制在 20–60,偏移量用 Math.random()*150-75 随机生成;加 pointer-events: none 防拦截点击;动画用 steps(1) forwards 实现瞬时炸裂;颜色尺寸须内联写死,推荐 HSL 随机色与 2–6px 尺寸;高频点击需节流+setTimeout 兜底删除;滚动时需校正 window.scrollX/Y。

用 position: absolute + transform 控制粒子初始位置和扩散方向
粒子必须脱离文档流,否则位移会触发重排、拖慢动画。每个粒子用 div 创建后,立刻设 position: absolute,并用 left/top 锚定到点击坐标——这是所有后续 transform 动画的起点。
扩散靠的是 transform: translate(x, y),不是改 left/top。原因很实在:CSS 动画对 transform 的硬件加速支持更稳,尤其在低端设备上;而频繁写 left/top 容易掉帧。
- 粒子数量建议控制在 20–60 个之间:少于 20 显单薄,多于 60 在旧 Android 或 Safari 上容易卡顿
- 每个粒子的
translate偏移量别用固定值,推荐用Math.random() * 150 - 75这类表达式生成 ±75px 范围内的随机值 - 别忘了给粒子加
pointer-events: none,否则新生成的div可能拦截后续点击
animation 中用 steps(1) 防止过渡插值干扰爆炸感
烟花要的是“炸开”的瞬时感,不是平滑飞出去。如果只写 animation: explode 0.8s ease-out,浏览器会在起始和结束帧之间自动补中间帧,导致粒子像被弹弓甩出去,而不是炸裂。
解决方法是强制关键帧跳变:animation: explode 0.8s steps(1) forwards。这样动画只在 0% 和 100% 两个状态间切换,视觉上就是“原地消失 → 瞬移到目标点”。
-
steps(1)必须配forwards,否则粒子会在动画结束后回退到初始位置 - 不要用
step-start或step-end,它们行为不一致,Chrome 和 Firefox 解析可能不同 - 若需轻微缓动(比如让最后 10% 减速),可拆成两段动画:前 90% 用
steps(1),后 10% 单独加一个带ease-in的微调动画
颜色和尺寸随机化必须在创建 DOM 时完成,不能靠 CSS 变量延迟计算
想让每个粒子颜色不同?别在 CSS 里写 background: hsl(var(--h), 100%, 60%) 再用 JS 改 style.setProperty。实测在大量粒子同时生成时,这种写法在 iOS Safari 上有明显延迟,部分粒子会晚几百毫秒才上色,破坏同步感。
正确做法是:JS 创建 div 后,直接内联写死样式:
const p = document.createElement('div');
p.style.cssText = `background: hsl(${Math.random() * 360}, 100%, 60%); width: ${2 + Math.random() * 4}px; height: ${2 + Math.random() * 4}px;`;
- 尺寸控制在
2px–6px最安全:太小看不见,太大显得像色块不是粒子 - HSL 比 HEX 更适合随机——
hsl(h, s, l)中只动h就能保证饱和度和亮度统一,避免出现脏灰或过曝色 - 别用
opacity做淡出,而是用animation控制transform+scale(0),这样能复用硬件加速路径
高频点击时必须限制粒子创建速率,否则 DOM 泄漏
用户连点三次,你却生成了 180 个 div 并只靠 animationend 删除——这在 Chrome DevTools 的 Memory 面板里会立刻暴露:节点数持续上涨,GC 不及时,几秒后页面就卡死。
核心防线只有两条:
- 用节流(throttle)限制点击事件触发频率,例如
if (Date.now() - lastFire - 每个粒子添加后,用
setTimeout(() => p.remove(), 1200)做兜底删除,时间略长于动画时长(比如动画 0.8s,这里设 1200ms),避免因动画未触发animationend导致残留
真正难处理的是滚动中点击+缩放页面时的定位偏移——clientX/clientY 拿到的是视口坐标,但粒子 left/top 是相对于 document.body 的。如果页面可滚动,必须加上 window.scrollX 和 window.scrollY 才准。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











