用 Canvas 写一个不拖慢页面的星空背景
占位示例文章,记录分层采样、帧率分档与降级策略的实现思路。
阅读约 2 分钟
目录(6 节)
占位示例文章:这篇记录星空背景的实现方式,重点在性能边界与降级路径,而不是视觉效果本身。
分层与采样
星点数量按视口面积计算,远景与中景使用不同密度,近景亮星数量固定。总数设上限,移动端直接降到 90 颗。
ts
const area = width * height;
const far = Math.min(120, Math.round(area * 0.00012));
const mid = Math.min(70, Math.round(area * 0.00005));
const near = mobile ? 0 : 16;为什么不用 shadowBlur
shadowBlur 每帧都要做一次模糊计算,星点一多就会掉帧。替代方案是预先生成一张带光晕的星点精灵,绘制时用 drawImage 缩放。
帧循环的约束
- 预分配星点数组,帧循环内不创建对象
- 设备像素比上限为 2
- 页面不可见时取消 RAF
- 首屏滚出视口后降到 30fps
ts
const dt = Math.min(performance.now() - last, 50);
last = performance.now();
draw(dt);
raf = requestAnimationFrame(loop);时间差必须裁剪,否则切回标签页时透明度会跳变。
降级策略
- 开启“减少动效”时只绘制一帧。
- Canvas 不可用时由 CSS 星云与两层径向渐变兜底。
- 低端设备依据硬件并发数降级为静态渲染。
检查清单
- 关闭 JS 后仍有可见星点
- 移动端不出现横向滚动
- 连续运行一分钟后内存不增长
结论
背景动画的上限不是视觉想象力,而是每帧的时间预算。先把预算写下来,再决定要不要加视差与流星。