Canvas实现下落樱花背景更可控轻量,因CSS需为每个花瓣创建独立元素和动画规则导致性能差,而Canvas用循环绘制数百花瓣,支持风力、碰撞、透明度渐变等自然动效。

直接用 canvas 实现下落樱花背景,比 CSS 动画更可控、更轻量,新手照着抄就能跑起来,不用装库、不依赖框架。
为什么不用 CSS @keyframes 做樱花飘落
CSS 动画对每个花瓣都得单独建元素 + 动画规则,100 个花瓣就要 100 个 <div> 和对应样式,内存涨、重绘卡、控制位置/旋转/加速度几乎没法做。而 <code>canvas 用一个循环画几百个点,CPU 占用低,还能加风力、碰撞、透明度渐变。
canvas 绘制樱花的核心逻辑
本质是每帧清空画布 → 更新每个花瓣的 y(下落)、x(左右飘)、alpha(透明度)→ 用 ctx.beginPath() + arc() 或小图片画花瓣。关键不是“画得多像”,而是“动得自然”:
-
y每次加speed * dt(dt是帧间隔,避免不同设备掉帧导致速度不一) -
x加一个微小正弦偏移:Math.sin(y * 0.01) * 2,模拟风的影响 - 花瓣到底部后,重置到顶部并随机
x、新speed(0.5–2.5)、新大小(2–6px) - 用
ctx.fillStyle = `rgba(255, 220, 220, ${alpha})`控制淡入淡出
可直接粘贴运行的最小可行代码
把下面这段保存为 index.html,双击打开就行。只用了原生 JS + canvas,无外部依赖:
立即学习“前端免费学习笔记(深入)”;
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><style>
body { margin: 0; overflow: hidden; background: #f8f4f0; }
canvas { display: block; }
</style></head>
<body>
<canvas id="sakura"></canvas>
<script>
const canvas = document.getElementById('sakura');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
<p>const petals = [];
const petalCount = 120;</p><p>for (let i = 0; i < petalCount; i++) {
petals.push({
x: Math.random() <em> canvas.width,
y: Math.random() </em> -canvas.height,
size: Math.random() <em> 4 + 2,
speed: Math.random() </em> 2 + 0.5,
sway: Math.random() <em> 0.02,
swayOffset: Math.random() </em> Math.PI * 2,
alpha: Math.random()
});
}</p><p>function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}</p><p>function animate(timestamp) {
if (!lastTime) lastTime = timestamp;
const dt = Math.min(50, timestamp - lastTime) / 16; // 归一化帧差
lastTime = timestamp;</p><p>ctx.clearRect(0, 0, canvas.width, canvas.height);</p><p>for (const p of petals) {
p.y += p.speed <em> dt;
p.x += Math.sin(p.y </em> p.sway + p.swayOffset) <em> 0.5 </em> dt;</p><pre class="brush:php;toolbar:false;">if (p.y > canvas.height + 10) {
p.y = -10;
p.x = Math.random() * canvas.width;
p.size = Math.random() * 4 + 2;
p.speed = Math.random() * 2 + 0.5;
p.sway = Math.random() * 0.02;
p.swayOffset = Math.random() * Math.PI * 2;
p.alpha = Math.random() * 0.5 + 0.2;
}
ctx.globalAlpha = p.alpha;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fillStyle = '#ffdddd';
ctx.fill();} ctx.globalAlpha = 1;
requestAnimationFrame(animate); }
let lastTime; window.addEventListener('resize', resize); requestAnimationFrame(animate);



















