“雨点般的字符落下,像《黑客帝国》里的数字世界在流动。”
本文将带你从 0 到 1 实现一个 Canvas 文字雨效果,并深入解析它的动画原理。
效果预览

核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| const canvas = document.querySelector("#canvas"); const ctx = canvas.getContext("2d"); const ratio = window.devicePixelRatio; const w = window.innerWidth * ratio; const h = window.innerHeight * ratio;
canvas.width = w; canvas.height = h;
const fontSize = 10 * ratio; ctx.font = `${fontSize}px "Roboto Mono"`; const columnCount = Math.floor(w / fontSize); const charIndex = new Array(columnCount).fill(0);
function getRandomChar() { const str = "0123456789abcdefghijklmnopqrltuvwxyz"; return str[Math.floor(Math.random() * str.length)]; }
function draw() { ctx.fillStyle = "rgba(0, 0, 0, 0.1)"; ctx.fillRect(0, 0, w, h);
ctx.fillStyle = "#6be445"; ctx.textBaseline = "top"; for (let i = 0; i < columnCount; i++) { const text = getRandomChar(); const x = i * fontSize; const y = charIndex[i] * fontSize; ctx.fillText(text, x, y); if (y > h && Math.random() > 0.99) { charIndex[i] = 0; } else { charIndex[i]++; } } window.setTimeout(draw, 50); } draw();
|
原理解析
文字雨的动画主要依赖两个关键技巧:
1. 半透明幕布叠加
每一帧先用 rgba(0,0,0,0.1)
这样的半透明颜色填充整个画布:
1 2
| ctx.fillStyle = "rgba(0, 0, 0, 0.1)"; ctx.fillRect(0, 0, w, h);
|
- 作用:不是一次性清空画布,而是让之前的内容逐渐变暗
- 效果:形成“尾迹”,看起来像字符带着残影下落
- 如果透明度=1:旧内容会一次性消失,没有流动感
2. 列位置与字符落下
- 按列计算
columnCount
,每列独立控制一个字符的纵向位置
- 每一帧在该列的下一行绘制一个新字符
- 当字符到底部后,以一定概率重新从顶部开始落下
3. 颜色与字体
- 绿色字符:
ctx.fillStyle = "#6be445"
- 单一字体:保证列宽和字符对齐
- 可以改成任意字符集(比如日文假名、emoji)
优化建议
- 在高 DPI 屏幕上使用
window.devicePixelRatio
,防止模糊
- 控制
requestAnimationFrame
的绘制频率,降低 CPU 占用
- 使用更高透明度(如
0.05
)获得更长的尾迹效果
总结
文字雨的酷炫效果并不复杂,关键是半透明幕布 + 按列落下的字符逻辑。
理解了这个原理,你还可以用它做星空、烟雾、粒子尾迹等各种特效。
🎬 拓展阅读: