0%

文字雨效果原理解析与实现

“雨点般的字符落下,像《黑客帝国》里的数字世界在流动。”
本文将带你从 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
/** @type {HTMLCanvasElement} */
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() {
// 1. 半透明幕布,让旧文字逐渐变暗
ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
ctx.fillRect(0, 0, w, h);

// 2. 画新文字
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]++;
}
}
// 此处改为用setTimeout延迟执行,这样效果看起来好一点
window.setTimeout(draw, 50);
// requestAnimationFrame(draw);
}
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)获得更长的尾迹效果

总结

文字雨的酷炫效果并不复杂,关键是半透明幕布 + 按列落下的字符逻辑
理解了这个原理,你还可以用它做星空、烟雾、粒子尾迹等各种特效。


🎬 拓展阅读