4971 字
25 分钟
网页 UI 终于能进游戏和 3D 场景了:HTML-in-Canvas 为什么重要

如果只用一句话解释 HTML-in-Canvas:它让真实网页 UI 既保留“网页该有的好用”,又能进入 Canvas、WebGL、WebGPU 的视觉世界。

用户真正会注意到的不是一个新 API 名字,而是这些过去很别扭的体验开始变自然:

  • 游戏里的登录框真的像游戏画面的一部分,而不是一层浮在上面的网页。
  • 设计工具里的网页预览可以被缩放、旋转、做转场,但里面的输入框仍然能输入。
  • 直播和录屏工具可以把字幕、聊天、课件、网页面板和摄像头放进同一条合成管线。
  • 3D 或 XR 场景里的网页面板可以被空间里的物体遮挡、变形、发光,同时仍然是可访问的 HTML。

过去很长一段时间,开发者只能二选一:要么用 DOM 保住输入、焦点、IME、自动填充、屏幕阅读器;要么把界面画进 Canvas,获得 shader、3D、滤镜、粒子和视频合成能力。HTML-in-Canvas 要补的正是这个缺口。

它的目标不是“把网页截图快一点”,而是让一个真实 DOM 子树继续参与浏览器布局、命中测试和无障碍树,同时又能把它的渲染结果画进 2D Canvas,或上传成 WebGL/WebGPU 可用的纹理。

先把边界说清楚:截至 2026-06,这仍是实验中的 Web 平台能力。Chrome 已经把它放进 origin trial,Chromium 也能通过 chrome://flags/#canvas-draw-element 试用;它值得关注,但还不是一个可以无脑投产的跨浏览器标准。

这篇文章想回答两个问题:用户到底会从中得到什么体验,以及为什么 Web 平台等到今天才开始打通 DOM 和 GPU。


1. 用户现在为什么会感觉割裂#

先想象一个游戏里的登录表单。用户希望它能输入中文,能 Tab 切换焦点,能粘贴验证码,密码管理器能自动填充,屏幕阅读器能读出 label。这些是 DOM 擅长的事。

再想象提交之后,整个表单像玻璃一样碎裂成粒子,每一片都经过 shader 扭曲、3D 翻转、辉光后处理,再飞散到场景深处。这些是 Canvas、WebGL、WebGPU 擅长的事。

过去的问题是,这两种体验很难发生在同一个对象上。

DOM 是浏览器的应用层 UI 系统。它有语义、布局、字体、输入法、选区、复制粘贴、焦点管理、表单控件、自动填充、浏览器翻译、查找、无障碍树和扩展生态。你写一个 <input>,背后不是一个矩形和几行事件监听,而是一整套浏览器能力。

Canvas 则是另一种模型:一块像素网格,一条命令式绘制管线。它适合游戏、图形编辑器、数据可视化、视频合成、3D 场景和 shader 效果。它给你的是自由,但你也要自己承担 UI 系统原本替你做掉的事。

这个分工在简单页面里没问题,但一到复杂产品就会刺痛:

  • 游戏 UI 想要原生输入框和 IME,又想要 shader 转场。
  • 设计工具想把真实网页放进无限画布,再对它旋转、缩放、加滤镜。
  • WebXR 想在 3D 空间里显示一个可交互的 HTML 面板。
  • 直播工具想把网页、字幕、摄像头和特效都放进同一条 GPU 合成管线。

用户真正感受到的割裂不是“技术栈不同”,而是:表单像网页时就不像游戏画面,表单像游戏画面时又不像一个正常网页表单。

开发者真正想要的也不是“把网页截图快一点”,而是一个更底层的原语:DOM 继续是 DOM,但它的视觉结果也能成为 Canvas/GPU 世界的一等输入。


2. 浏览器明明已经在用 GPU 合成 DOM,为什么不给开发者?#

现代浏览器内部早就在做合成层:页面里的 DOM、动画元素、视频、Canvas 都可能被分到不同 layer,再由 compositor 合成为屏幕上的一帧。

所以直觉上会觉得:既然浏览器内部已经把很多东西变成 GPU 可合成的表面,为什么不直接把某个 <div> 的纹理给 JavaScript?

难点不在“能不能画”,而在三个边界。

第一是安全与隐私。DOM 里可能包含跨域 iframe、跨域图片、被访问过的链接状态、拼写检查标记、系统主题、自动填充候选、用户偏好等信息。如果一个 API 允许把任意 DOM 像素读回 JavaScript,它就可能变成跨域信息泄露和指纹识别通道。

第二是渲染时序。DOM 的布局、绘制、滚动、CSS 动画和 Canvas 的绘制命令不是同一个抽象层。要把 DOM 的某一帧稳定地交给 Canvas,浏览器必须定义“什么时候快照”“什么时候触发更新”“主线程脚本和浏览器自己的绘制如何同步”。

第三是命中测试和无障碍。元素如果被画进 Canvas,但用户实际点击的是 Canvas 上的某个像素,浏览器要知道这个点击如何对应回真实 DOM;屏幕阅读器也要能理解画出来的东西不是一张死图,而是背后有语义元素。

HTML-in-Canvas 的设计基本都在围绕这三件事收边界:不是开放“任意 DOM 截图”,而是开放“Canvas 直接子元素的受控绘制”。


3. 旧方案为什么都差一口气#

在这个 API 出现之前,开发者一直在绕路。

3.1 html2canvas:用 JavaScript 重写半个浏览器#

html2canvas 的思路是解析 DOM 和 CSS,然后用 JavaScript 自己把它们画到 Canvas。

这个方向工程上很顽强,但注定很难完美。CSS 规范太大,字体度量、emoji、subpixel 抗锯齿、滤镜、阴影、混合模式、滚动容器、伪元素、浏览器默认样式,每一个细节都可能和真实页面有偏差。

它能解决“生成一张大致可用的图”,但解决不了“把浏览器真实渲染结果作为实时纹理”。

3.2 SVG <foreignObject>:借浏览器渲染,但只能做快照#

另一个常见技巧是把 HTML 序列化进 SVG 的 <foreignObject>,再把 SVG 当图片画进 Canvas。

它的优点是能借用浏览器自己的 HTML/CSS 渲染能力,保真度比纯 JS 重写更有希望。但它仍然是一次性快照:样式作用域、字体、跨域资源、浏览器兼容性都会出问题,输入框和光标也不会以真实 DOM 的方式继续工作。

这条路适合做静态图,不适合做活的 UI。

3.3 CSS3DRenderer / iframe:保住交互,但进不了你的 GPU 管线#

Three.js 生态里常见的 CSS3DRenderer,本质是让 DOM 用 CSS transform 伪装成 3D,再让 WebGL 场景匹配同一套相机参数。

这可以保住 DOM 交互,但它不是同一个渲染管线。DOM 仍然由浏览器合成器处理,WebGL 仍然在 Canvas 里处理;两边的 z-order、遮挡、后处理、shader、抗锯齿和刷新节奏都可能对不上。

iframe 也类似:它能显示活网页,但它是一个独立的浏览器嵌入上下文。跨域通信受限,Canvas 拿不到它的像素,和 3D 场景的深度关系也很难自然统一。

3.4 Canvas 自研 UI:自由度最高,债也最大#

很多游戏和图形编辑器最终会在 Canvas 里自己实现按钮、文本、输入框和面板。

这能完全进入 GPU 管线,但代价是重新实现一个 UI 平台。文本选择、IME、可访问性、表单校验、移动端键盘、屏幕阅读器、浏览器缩放、复制粘贴,每一项都不是小活。

所以旧方案的共同问题是:要么保留 DOM 能力,要么获得 GPU 自由,很难同时拿到。


4. HTML-in-Canvas 到底提供了什么#

WICG explainer 里的核心设计有三个部分:

  1. layoutsubtree:让 <canvas> 的直接子元素参与布局、命中测试和无障碍相关流程,但它们不会像普通 DOM 那样直接显示出来,除非被显式画进 Canvas。
  2. 绘制/上传方法:2D Canvas 使用 drawElementImage();WebGL 使用 texElementImage2D();WebGPU 通过 GPUQueue.copyElementImageToTexture() 上传。
  3. paint 事件:当 Canvas 子元素的渲染发生变化时,浏览器通知开发者,让 Canvas 有机会同步更新。

一个接近底层 API 的概念化例子大概是这样:

<canvas id="stage" layoutsubtree></canvas>

<script>
const canvas = document.querySelector("#stage");
const ctx = canvas.getContext("2d");

const form = document.createElement("form");
form.innerHTML = `
  <label>
    Email
    <input value="still editable" />
  </label>
`;

canvas.appendChild(form);

canvas.addEventListener("paint", () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  const transform = ctx.drawElementImage(form, 40, 40);
  form.style.transform = transform.toString();
});
</script>

这里的关键不是那一次绘制,而是最后一行 transform 同步:浏览器需要知道这个真实 DOM 元素在 Canvas 画面里的位置,才能把点击、焦点、选区和无障碍命中区域对回正确的元素。

真实业务里,多数开发者不会直接碰这些底层方法,而是通过渲染框架使用。PixiJS v8.19 已经提供了 pixi.js/html-source 子路径:

import { Application, Sprite } from "pixi.js";
import { HTMLSource } from "pixi.js/html-source";

const app = new Application();
await app.init({ resizeTo: window });
document.body.appendChild(app.canvas);

const form = document.createElement("form");
form.innerHTML = '<input value="still editable" />';

app.canvas.appendChild(form); // 必须是 Pixi canvas 的直接子元素

const sprite = Sprite.from(
  new HTMLSource({ resource: form, autoUpdate: true }),
);

app.stage.addChild(sprite);

这里最关键的是:form 仍然是 DOM,输入框仍然能编辑;同时它又以 PixiJS texture 的形式进入场景,可以被当成 sprite 做缩放、旋转、滤镜、mask、shader 和后处理。

PixiJS 还提供 ElementImageSource,适合把某一刻的元素渲染结果冻结成不可变快照,用于碎裂、拖影、转场这类不需要持续交互的效果。


5. 新 API 真正不一样的地方#

HTML-in-Canvas 的价值不只是“更快截图”。它改变的是责任分配,也改变了用户能感受到的界面边界。

用户期待旧方案HTML-in-Canvas
看起来像真实网页JS 重写或 SVG hack,容易偏浏览器自己渲染自己的 DOM
用起来像真实网页截图后输入、焦点和选区都丢失源元素仍是 DOM,浏览器继续处理
中文输入、复制粘贴、自动填充正常Canvas 内要大量自研复用浏览器行为
屏幕阅读器能理解界面Canvas fallback 很难和视觉同步绘制内容和对应 DOM 元素有明确关系
能融入游戏、3D、视频画面DOM 层难以接入 shader渲染结果可进入 Canvas/WebGL/WebGPU
内容变化能同步到画面多为手动快照浏览器通过 paint 事件暴露更新时机

这让一种过去很尴尬的 UI 变得合理:用 DOM 写交互和语义,用 GPU 处理视觉和合成。


6. 用户会在哪些产品里感受到它#

6.1 Web 游戏 UI#

游戏 UI 长期在两条路之间摇摆:用 HTML 浮在 Canvas 上方,或者在游戏引擎里重写控件。

前者交互正确,但很难融入游戏画面;后者视觉统一,但输入框、可访问性和移动端输入会迅速变成工程债。

HTML-in-Canvas 提供第三条路:登录框、聊天框、背包、设置面板仍然用真实 HTML 写,但它们的视觉结果可以作为 texture 进入游戏场景。

玩家感受到的是:聊天框可以被场景光照影响,菜单可以 3D 翻转,按钮可以被 shader 扭曲,表单提交时可以粒子化;但输入文字、粘贴内容、切换焦点这些动作仍然像普通网页一样可靠。

6.2 设计工具和无限画布#

Figma、Miro、tldraw 这类产品的核心体验是“万物皆可放进画布”。如果画布里能放同源或受控的活 HTML 面板,设计稿、文档块、数据看板、组件预览就不一定要退化成截图。

用户感受到的是:画布里的组件预览不再只是图片。它可以被拖拽、缩放、旋转、遮挡,也可以保持文本选择、表单输入、浏览器查找和无障碍语义。

这不等于可以任意抓取别人网站的像素,但对产品内部的可控内容已经足够有价值:真实表单、真实组件、真实预览,可以和其他图形对象一样参与画布编排。

6.3 视频会议、教学和直播合成#

WebCodecs、WebRTC 和 WebGPU 已经让浏览器具备越来越强的媒体处理能力,缺的常常是“HTML UI 如何高质量进入合成管线”。

HTML-in-Canvas 可以让课件、字幕、聊天、网页面板、摄像头画面和品牌包装在同一条 GPU 管线上合成。

观众感受到的是:讲师在网页里操作的面板不是低清截图,字幕和聊天可以跟着画面一起缩放、转场、录制和推流。对轻量直播工具、在线课堂、产品演示和浏览器版 OBS 来说,这个方向很自然。

6.4 WebXR 和 3D 应用#

WebXR 里一直需要“空间中的网页面板”。过去把 HTML 截图贴到 3D 面上会失去交互;用 DOM/CSS 叠在外面又很难和 WebGL 场景的光照、遮挡、深度关系统一。

如果 HTML 能成为 3D 场景里的纹理,面板就可以被放在空间里、被几何体遮挡、被 shader 处理,同时背后的控件仍然有 DOM 语义。

用户感受到的是:空间里的网页面板不再像一层贴在屏幕上的 HUD,而像真的挂在场景里的控制台。这对浏览器里的 3D 工具、虚拟工作台和空间计算界面都很关键。

6.5 IDE 和组件预览#

StackBlitz、CodeSandbox、VS Code Web、设计系统文档站都大量使用 iframe 预览。iframe 很好用,但它和编辑器主画布之间仍然有明显边界。

HTML-in-Canvas 让受控预览有机会变成可编排的视觉图层:多个设备尺寸并排、3D 倾斜展示、转场动画、像素级对比、录制输出,都可以在一个 Canvas 场景中完成。

需要强调的是,跨源 iframe 仍然不能被随意画进 Canvas。它的价值主要在同源、沙箱内可控、或产品自己生成的预览内容上。


7. 容易误读的地方#

7.1 它不是任意网页截图 API#

这个 API 的安全模型不是“你想画什么就画什么”。WICG explainer 明确把跨域嵌入内容、跨域图片、被污染的 Canvas、系统主题、拼写标记、visited link 信息、未公开的自动填充信息、IME 相关 UI、字幕偏好等列为敏感信息,并要求绘制和失效通知不能泄露这些内容。

换句话说,它的目标是让可控 DOM 更好地进入 Canvas,而不是绕过同源策略。

7.2 它不是零成本#

一个活的 HTML surface 需要布局、绘制、上传、同步和显存。少量大型富交互区域很适合;把页面里几百上千个小组件都做成 HTML texture,通常会把性能和内存推向错误方向。

合理用法更像“给 Canvas 场景嵌入几个复杂 UI 面板”,而不是“把整棵 React 组件树全部镜像成纹理”。

7.3 它有明确的结构限制#

当前提案要求源元素必须是 Canvas 的直接子元素,并且最近一次渲染更新里要生成布局盒子(generated boxes),也就是不能是 display: none。这不是随手加的限制,而是为了让浏览器能明确计算布局、绘制、命中测试和更新通知。

另外,源元素自己的 CSS transform 在绘制时会被忽略,但仍然会影响命中测试和无障碍相关行为。这类细节意味着真实项目需要仔细做几何同步,而不能把它当成普通截图函数。

7.4 它还远没到跨浏览器稳定#

截至 2026-06,Chrome 官方文档标注的是 Chrome 148 到 150 的 origin trial;Blink intent 里也能看到 Firefox/Gecko 和 WebKit 仍有标准立场与实现信号上的不确定性。引擎接入状态也要分开看:例如 PlayCanvas 文档写的是当前支持 WebGL 后端,WebGPU 后端还在等待对应浏览器级 API 接入。

因此,现阶段更适合 demo、内部工具、受控 Chrome 环境、渲染框架实验和未来架构验证。生产系统要做 feature detection 和 fallback。


8. 放进 Web 渲染演进史里看#

Web 渲染能力大致沿着这条线往前走:

HTML/CSS          声明式文档和应用 UI
Canvas 2D         命令式像素绘制
WebGL             可编程 GPU 图形管线进入浏览器
OffscreenCanvas   Canvas 绘制脱离主线程
WebGPU            更现代的 GPU 计算和图形接口
HTML-in-Canvas    DOM 渲染结果进入 Canvas/GPU 管线

这不是某个框架的小功能,而是 Web 平台的一次边界调整。

过去的默认分工是:

  • DOM 负责语义、交互、可访问性。
  • Canvas/GPU 负责自由绘制、shader、后处理和合成。

HTML-in-Canvas 让这两边第一次有了更直接的交换方式。它不取消分工,而是让分工后的结果可以重新组合。

原生平台早就有类似思想:Android 有 SurfaceTexture,Apple 平台有 IOSurface / Metal 相关 surface 共享,Flutter 有 texture 嵌入机制。Web 缺的不是 shader,也不是 DOM,而是两者之间受控、可同步、可解释的桥。

HTML-in-Canvas 正是在补这座桥。


9. 短中长期判断#

短期看,它会先出现在 PixiJS 这类渲染框架的 demo、教程和内部实验里。因为只有少数开发者愿意要求用户打开实验 flag 或注册 origin trial。

中期看,如果标准形态稳定、浏览器厂商逐步达成共识,Web 游戏 UI、设计工具预览、无限画布、可视化编辑器、在线直播合成会最先受益。这些场景都有同一个特点:它们需要 DOM 的正确性,也需要 GPU 管线的表现力。

长期看,HTML-in-Canvas 会成为“Web 作为一等媒体与创作平台”的一块拼图。它不会让 Native 失去意义,但会让更多复杂界面不再必须离开浏览器。


10. 结语#

写过 html2canvas 相关逻辑的人都知道,重写浏览器渲染器是一条没有尽头的路。

写过 CSS3DRenderer、iframe overlay 或 Canvas 自研 UI 的人也知道,两套渲染体系并排运行时,总会在交互、遮挡、性能或无障碍上露出代价。

HTML-in-Canvas 的重要性就在这里:它不是又一个截图库,而是浏览器开始承认一个现实需求:

DOM 应该继续负责它最擅长的语义和交互;GPU 也应该能够处理 DOM 的视觉结果。

对用户来说,这意味着复杂 Web 应用不必总在“像网页一样好用”和“像游戏、视频、3D 场景一样有表现力”之间切开。

这个 API 很小,但背后是 Web 渲染架构里一条很长的裂缝。裂缝一旦补上,很多过去只能 hack 的产品体验,就会变成平台能力。


参考与延伸#

作者立场提示:本文从 Web 平台架构演进角度做分析,不构成任何具体框架或产品的技术选型建议。HTML-in-Canvas 当前仍处在实验阶段,生产可用性请以浏览器厂商和框架官方文档为准。

网页 UI 终于能进游戏和 3D 场景了:HTML-in-Canvas 为什么重要
https://wsafight.github.io/personBlog/posts/html-in-canvas/
作者
wsafight
发布于
2026-06-23
许可协议
CC BY-NC-SA 4.0