关键在于用requestAnimationFrame逐帧线性更新globalAlpha实现均匀渐变,双图层反向调节(A:1−t,B:t)确保严丝合缝叠加,每帧后重置globalAlpha=1或使用save/restore隔离作用域,并保留alpha两位小数兼顾精度与性能。

用 Canvas 的 globalAlpha 实现图层平滑淡入淡出,关键不是“设个值就完事”,而是让透明度随时间均匀变化,并严格控制作用范围和渲染节奏。
用 requestAnimationFrame 驱动渐变过程
不能靠 setTimeout 或 setInterval 控制透明度变化——它们时间不准,容易跳帧、闪烁。必须用 requestAnimationFrame 作为动画节拍器:
- 定义起始 alpha(如 0)、目标 alpha(如 1)、总动画帧数(如 60)
- 每帧计算当前值:
currentAlpha = start + (target - start) * (frame / total) - 每次绘制前设置
ctx.globalAlpha = currentAlpha,再调用drawImage() - 当
Math.abs(currentAlpha - targetAlpha) 时,直接赋目标值并停止动画
双图层交叉过渡:A 淡出 + B 淡入
单图淡入淡出有空白间隙;真正平滑的切换需两张图同时绘制、反向调节透明度:
- 先绘制图像 A,设
ctx.globalAlpha = 1 - t(t 从 0 线性增至 1) - 再绘制图像 B,设
ctx.globalAlpha = t - 两张图必须使用完全相同的
drawImage(img, x, y, width, height)参数,确保位置与尺寸严丝合缝 - t 每帧递增,视觉上就是 A 完全消失的同时 B 完全显现,无闪、无断
避免 globalAlpha 波及后续内容
globalAlpha 是上下文状态,不自动隔离,一设就影响之后所有绘图(文字、线条、新图像都会变淡):
立即学习“前端免费学习笔记(深入)”;
- 每次动画帧结束前,务必重置:
ctx.globalAlpha = 1.0 - 更稳妥做法:用
ctx.save()包裹过渡绘制,ctx.restore()恢复原始状态 - 不要在循环外长期保留低 alpha 值;若某次只需一个图形半透明,优先用
rgba(r,g,b,a)设置 fillStyle/strokeStyle
精度与性能的小优化
人眼对透明度变化不敏感,过度计算反而拖慢渲染:
- alpha 值保留两位小数即可(如
0.42而非0.417832) - 大图过渡阶段可临时关闭抗锯齿:
ctx.imageSmoothingEnabled = false - 若图像带原生 Alpha 通道(如 PNG),
globalAlpha会二次叠加——这是预期行为,无需规避
不复杂但容易忽略。真正决定是否“平滑”的,是帧率稳定性和 alpha 步进是否线性均匀,而不是数值本身有多精细。



















