跳到主要内容

用 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);

时间差必须裁剪,否则切回标签页时透明度会跳变。

降级策略

  1. 开启“减少动效”时只绘制一帧。
  2. Canvas 不可用时由 CSS 星云与两层径向渐变兜底。
  3. 低端设备依据硬件并发数降级为静态渲染。

检查清单

  • 关闭 JS 后仍有可见星点
  • 移动端不出现横向滚动
  • 连续运行一分钟后内存不增长

结论

背景动画的上限不是视觉想象力,而是每帧的时间预算。先把预算写下来,再决定要不要加视差与流星。