离屏渲染仅在内容稳定且更新可控时才有效——需同时满足低频更新、高绘制开销、高频复用、可监听真实变更四个条件;否则反而降低性能。

离屏渲染不是加个 OffscreenCanvas 就能变快,关键在于「内容是否真稳定」和「更新是否被跳过」——90% 的性能退化来自每帧重绘离屏画布,而不是没用它。
什么时候该用离屏渲染而不是直接 draw
只在满足以下全部条件时才值得引入离屏:
- 某图层内容更新频率远低于整体帧率(比如 UI 背景、HUD、图标模板)
- 该图层单次绘制开销高(含文字度量、渐变、阴影、多图层合成等)
- 它被频繁复用(如上百个相同按钮、缩放旋转但内容不变的贴图)
- 你有能力监听真实变更源(主题切换、资源加载完成、配置变化),而非轮询或每帧检查
反例:粒子系统、实时摄像头流、用户输入触发的文字编辑器——这些内容每帧都变,离屏只会多占内存、拖慢首帧。
用 document.createElement('canvas') 而不是 new OffscreenCanvas()
new OffscreenCanvas() 在 Safari 16.6 之前完全不可用,安卓 WebView 支持也不统一;而 document.createElement('canvas') 兼容所有现代浏览器,且能直接获取 getContext('2d')。
立即学习“前端免费学习笔记(深入)”;
- 必须显式设置
width和height属性(不是 CSS 样式),否则getContext('2d')可能返回null - 高 DPI 设备下,若主 Canvas 按
window.devicePixelRatio缩放,离屏 Canvas 的像素尺寸也得同步放大:offscreen.width = canvas.clientWidth * window.devicePixelRatio - 调试时可临时把离屏 Canvas 插入 DOM 并加
border,确认绘制区域是否匹配预期
离屏内容更新必须受控,不能塞进 requestAnimationFrame
很多卡顿源于“以为用了离屏就万事大吉”,结果每帧都调用 clearRect() + 重绘——这等于把一次复杂绘制拆成两次,还白占内存。
- 只在内容实际变更时才重绘:监听
themeChange事件后重绘带渐变的按钮,等img.onload触发后再批量绘制精灵图 - 对分层结构(如 “UI-背景层”“UI-图标层”),用
clearRect(x, y, w, h)精确擦除局部区域,避免全屏清空 - 别在
requestAnimationFrame回调里做离屏更新——除非你 100% 确认这一帧内容确实变了
DOM 节点数超 2000 时,离屏渲染救不了 layout 重排
Canvas/WebGL 容器里混用 HTML overlay,DOM 节点超 2000 就会卡帧——这不是 JS 慢,是 layout 阶段反复重排拖垮的。此时离屏渲染本身无效,必须先做 DOM 减排:
- 用
::before/::after生成分隔线、角标,禁用<hr>和空<div class="divider"> - 间距优先用
gap或margin,不用空<div style="height: 8px"></div> - 动态 overlay 必须用
position: fixed+z-index脱离文档流,插入前设父容器style.display = 'none'屏蔽中间态 layout
真正起效的离屏方案,永远是「离屏渲染 + DOM 减排」双线并行;单靠任何一方,在复杂图形容器中都撑不住。



















