
本文详解如何通过监听 resize 事件动态调整 Canvas 尺寸,并同步更新绘图逻辑(如雨滴动画列数、坐标计算等),确保画布始终铺满视口且动画不因尺寸变化而错乱或失效。
本文详解如何通过监听 `resize` 事件动态调整 canvas 尺寸,并同步更新绘图逻辑(如雨滴动画列数、坐标计算等),确保画布始终铺满视口且动画不因尺寸变化而错乱或失效。
在 Web 开发中,将 <canvas> 元素设为全屏背景并随浏览器窗口实时响应缩放,是实现沉浸式视觉效果(如粒子动画、动态雨滴背景)的关键一步。但仅设置 CSS 样式(如 width: 100vw; height: 100vh)无法真正改变 Canvas 的渲染分辨率——Canvas 的 width 和 height 属性控制的是其内部位图的像素尺寸,而非显示尺寸。若仅靠 CSS 拉伸,会导致图像模糊、坐标偏移、动画失真。
因此,正确做法是:在 JavaScript 中显式更新 Canvas 的 width 和 height 属性,并重置所有依赖尺寸的变量(如列数、雨滴位置数组等)。
以下是优化后的 background.js 核心代码(已整合 resize 响应逻辑):
const canvas = document.getElementById('background_canvas');
const context = canvas.getContext('2d');
// 初始化画布尺寸
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
// 初始化雨滴状态(需在 resize 后重新计算)
let columns;
let rainDrops;
function initRaindrops() {
columns = Math.floor(canvas.width / 16); // fontSize = 16
rainDrops = Array(columns).fill(1);
}
// 初始设置
resizeCanvas();
initRaindrops();
// 监听窗口缩放事件
window.addEventListener('resize', () => {
resizeCanvas();
initRaindrops(); // 重置雨滴列数和初始位置
});
// 字符集与字体配置
const katakana = 'アァカサタナハマヤャラワガザダバパイィキシチニヒミリヰゲジヂビピウゥクスツヌフムユュルグズブヅプエェケセテネヘメレヱゲゼデベペオォコソトノホモヨョロヲゴゾドボポヴッン';
const latin = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const nums = '0123456789';
const alphabet = katakana + latin + nums;
const fontSize = 16;
// 动画主循环
function draw() {
context.fillStyle = 'rgba(0, 0, 0, 0.05)';
context.fillRect(0, 0, canvas.width, canvas.height);
context.fillStyle = '#0F0';
context.font = `${fontSize}px Monocraft`; // 注意:CSS 中定义了 @font-face,此处需匹配字体名
for (let i = 0; i < rainDrops.length; i++) {
const text = alphabet.charAt(Math.floor(Math.random() * alphabet.length));
context.fillText(text, i * fontSize, rainDrops[i] * fontSize);
// 重置超出底部的雨滴
if (rainDrops[i] * fontSize > canvas.height && Math.random() > 0.975) {
rainDrops[i] = 0;
}
rainDrops[i]++;
}
}
// 启动动画
setInterval(draw, 30);✅ 关键要点说明:
立即学习“前端免费学习笔记(深入)”;
- canvas.width/height 必须赋值为数值(如 window.innerWidth),不能使用 CSS 单位(如 '100vw');
- resize 事件需同时更新 Canvas 像素尺寸 和 所有依赖该尺寸的变量(如 columns、rainDrops 数组);
- initRaindrops() 在每次 resize 后调用,避免旧数组长度与新宽度不匹配导致绘制异常(如空白列或越界访问);
- 若使用自定义字体(如 Monocraft),确保 context.font 中的字体名与 @font-face 定义完全一致;
- 建议添加防抖(debounce)优化频繁触发的 resize 事件(尤其在拖拽窗口时),例如使用 setTimeout 缓存一次执行。
⚠️ 常见误区提醒:
- ❌ 错误:仅设置 canvas.style.width = '100%'; canvas.style.height = '100%' → 仅拉伸显示,不提升分辨率;
- ❌ 错误:未重置 rainDrops 数组 → 新宽度下列数变化,但数组长度不变,导致部分区域无雨滴或绘制溢出;
- ❌ 错误:在 resize 回调中遗漏 initRaindrops() → 动画逻辑仍按旧尺寸运行。
通过以上实现,Canvas 将真正响应浏览器窗口变化,保持清晰锐利的渲染效果与流畅稳定的动画表现。



















