Canvas 和 DOM 分裂了二十年,Chrome 要把它们缝上了
做 Web 3D 的人,最后经常不是卡在模型、材质、灯光上,而是卡在一个按钮上。
你想在 Three.js 场景里放一个产品配置面板:有标题、有说明、有输入框、有按钮、有下拉菜单,最好还能复制文字、选中文本、支持输入法、支持无障碍。
最简单的做法,是把一个 DOM 面板浮在 Canvas 上面。
这样当然能用,但它看起来永远像“盖在 3D 画面上的网页”,不是真正在空间里。只要涉及遮挡、透视、3D 表面、WebXR 菜单、曲面 UI,DOM overlay 就会变得很别扭。
另一种做法,是把 UI 全部画进 WebGL 或 WebGPU。
视觉上统一了,但代价也很高:文本排版、表单、输入法、复制粘贴、选中、无障碍、浏览器翻译、右键菜单、查找,全都要自己补一遍。
HTML-in-Canvas 想解决的就是这个缝。
它让真正的 HTML 元素可以被绘制进 Canvas、WebGL 纹理或 WebGPU 纹理里,同时尽量保留浏览器原生的交互和语义。
换句话说,3D 场景里的按钮,不再只是看起来像按钮,而是真的可以被浏览器当作按钮处理。

这张图可以先抓住本文的核心:HTML-in-Canvas 不是把网页截成一张死图,而是让 DOM 的视觉结果进入 GPU,同时尽量保留浏览器原生交互。
这不是把网页截图贴上去
HTML-in-Canvas 最容易被误解成“把一个 DOM 截图贴到 Canvas 上”。
如果只是截图,那价值有限。你现在用 html2canvas 之类的方案,也能把 DOM 样子栅格化出来。但那种方式本质上只得到一张图,图里的输入框不能输入,按钮不能 hover,文本也不再是浏览器理解的文本。
HTML-in-Canvas 的关键不是“显示 HTML”,而是把 DOM 的能力带进 Canvas。
Chrome 官方文章里强调的能力包括:
- 文本布局和 CSS 样式;
- 表单控件;
- 文本选择、复制、右键菜单;
- 可访问性树;
- find-in-page 页面查找;
- 浏览器扩展、翻译、DevTools 等集成。
这件事对 Web 3D 很重要。
因为 Web 3D 过去最尴尬的地方,就是 Canvas 负责图形,DOM 负责语义,两边像两个世界。模型、材质、光照都在 Canvas 里,真正可用的 UI 却只能浮在外面。
HTML-in-Canvas 的方向,是让 DOM 还能是 DOM,只是它的视觉结果可以进入图形世界。
它怎么工作
这个 API 的思路可以简化成三步。
第一步,在 <canvas> 上加 layoutsubtree。
这会让 canvas 里的子元素参与浏览器布局和 hit testing。它们仍然是 HTML 元素,有自己的尺寸、样式、语义和交互区域。
第二步,把这些子元素绘制进 Canvas 或 GPU 纹理。
2D Canvas 里是 drawElementImage()。
WebGL 方向是 texElementImage2D()。
WebGPU 方向是 copyElementImageToTexture()。
第三步,同步它在屏幕上的位置。
这一步很关键。因为 HTML 元素虽然被画到了 3D 表面上,但浏览器要知道它实际出现在屏幕哪里,才能正确处理点击、hover、focus、输入和无障碍。
所以 API 会返回或计算一个 transform,把 DOM 元素的位置和 Canvas / 3D 场景里的绘制位置对齐。
这也是它和普通“贴图”的差别:图像进入了 GPU,交互仍然尽量交给浏览器原生系统。
Three.js 已经接了
对 Web3D 开发者来说,最值得看的不是 API 文档本身,而是 Three.js 的接入。
Three.js PR #31233 已经在 2026 年 4 月 10 日合并到 dev 分支,标题是 Added HTMLTexture。

这张 PR 截图比普通 demo 更适合放进文章:它同时显示了合并状态、HTMLTexture / InteractionManager 的设计说明,以及 HTML 内容进入 3D 物体表面的实际效果。
它新增了两个关键东西。
第一个是 HTMLTexture。
它可以把一个 live HTML element 渲染到 3D mesh 的纹理上。示例代码大概是这样:
const element = document.createElement('div');
element.innerHTML = 'Hello <b>world</b>! <input type="text">';
const material = new MeshStandardMaterial();
material.map = new HTMLTexture(element);
const mesh = new Mesh(geometry, material);
scene.add(mesh);这意味着你可以用正常 HTML 写一块 UI,再把它贴到 Three.js 物体表面。
第二个是 InteractionManager。
它的作用更重要:为带有 HTMLTexture 的 mesh 计算 CSS matrix3d,让浏览器原生处理 hit testing、hover、focus 和 input。
也就是说,它不是用 Three.js raycaster 去模拟一套点击系统,而是尽量把交互还给浏览器。
Three.js 里还加了 WebGL 和 WebGPU 两个示例:
webgl_materials_texture_htmlwebgpu_materials_texture_html
这说明这件事已经不是纯概念,有框架开始把它封装成开发者能理解的 API。
PlayCanvas 也在跟进
PlayCanvas 文档里也已经有 HTML-in-Canvas 页面。
它的描述很直接:HTML-in-Canvas 可以把 live HTML 和 CSS 内容作为 WebGL texture 渲染,让 styled text、交互 UI 面板、表单和其他 DOM 内容出现在 3D 场景表面,同时保留 accessibility、internationalization 和 CSS 样式支持。
不过 PlayCanvas 的文档也更保守。
它明确要求通过 device.supportsHtmlTextures 检测支持情况。如果不支持,就要准备 fallback:
- DOM overlay;
- Canvas 2D rasterization。
它还写明:目前 PlayCanvas 支持的是 WebGL backend,WebGPU 支持还在等待对应浏览器层 API 可用。
这个细节很重要。
它说明生态已经开始接这套能力,但现在还不是“所有 WebGL / WebGPU 项目马上都能稳定用”的阶段。
真正的应用场景
如果 HTML-in-Canvas 成熟,最先受益的不是普通网页,而是那些 Canvas-heavy 和 3D-heavy 应用。
比如 3D 产品配置器。
现在很多产品配置页面会把 3D 模型放中间,参数面板放旁边。未来参数面板可以直接出现在产品旁边,甚至贴在物体表面,同时仍然是可输入、可复制、可访问的 HTML。
比如 WebXR 菜单。
VR / AR 场景里的设置面板、说明卡片、控制台,不一定要重新写一套 UI 系统。如果 HTML 可以进入 3D 表面,很多网页已有能力就能复用。
比如 3D 书籍、教程、展板。
Chrome 官方 demo 里就提到 3D book 这种方向:书页可以用 HTML 布局,字体、翻译、文本提取都能继续靠浏览器能力处理。
再比如 Figma、Miro、Google Docs 这类大型 Canvas 应用。
它们不是 Web3D,但同样长期面对一个问题:Canvas 性能强,DOM 语义强。HTML-in-Canvas 如果成熟,可能让复杂 UI 组件更自然地进入 Canvas 工作区。
所以这件事不只是 Three.js 的小功能。
它更像浏览器在补一个长期缺口:让 Canvas 不再是语义孤岛。
现在还不能盲目上生产
这篇文章最需要讲清楚的边界是:HTML-in-Canvas 还在实验阶段。
Chrome 官方文章写得很明确:它现在处于 Chrome 148 到 150 的 origin trial。开发者测试需要 Chrome Canary 149 或更新版本,并开启:
chrome://flags/#canvas-draw-elementWICG 仓库也说这是 living explainer,会随着反馈持续变化。
也就是说,它不是稳定 Web 标准,不是所有浏览器都支持,更不是你今天就可以无脑塞进生产环境的东西。
还有几个限制要注意。
第一,跨域内容不会随便被画进去。
WICG 文档里专门有 privacy-preserving painting 的部分。跨域 iframe、跨域图片、被污染的 canvas、visited link、autofill 等敏感信息都要受限制。否则这个 API 很容易变成隐私泄露通道。
第二,滚动和动画不是天然完美。
Chrome 官方提到,HTML-in-Canvas 是由 JavaScript 驱动绘制的。滚动和动画不能像普通 DOM 那样完全独立于 JavaScript 更新。复杂滚动内容放进 Canvas 前,仍然要考虑性能和同步问题。
第三,必须有 fallback。
PlayCanvas 文档里也明确建议:如果 supportsHtmlTextures 不支持,就退回 DOM overlay 或 Canvas 2D rasterization。
所以现在更合理的态度是:可以关注,可以实验,可以为未来项目做技术储备,但不要把它当稳定方案直接押上生产。
这件事的真正意义
HTML-in-Canvas 最有意思的地方,不是多了一个 API 名字。
它代表浏览器正在重新连接两个长期分裂的世界:
一边是 DOM,强在语义、交互、可访问性、文本和浏览器集成。
另一边是 Canvas、WebGL、WebGPU,强在高性能图形、复杂视觉和 3D 空间。
过去做 Web 3D UI,经常要在这两边做取舍。
要么保留 DOM 能力,但 UI 像贴在画面外面。
要么进入 3D 世界,但自己重写一堆浏览器已经解决过的东西。
HTML-in-Canvas 的方向,是让这两个世界可以重叠。
如果它成熟,Three.js 里的 3D 面板、WebXR 菜单、产品配置器、空间官网、游戏内终端,可能都会少掉一层自制 UI 系统。
3D 场景里的按钮,不再只是一个看起来像按钮的贴图。
它可以是真的 HTML。
这才是这件事最值得关注的地方。
参考资料:
- Chrome 官方:Introducing the HTML-in-Canvas API origin trial
https://developer.chrome.com/blog/html-in-canvas-origin-trial (opens in a new tab) - WICG HTML-in-Canvas proposal
https://github.com/WICG/html-in-canvas (opens in a new tab) - Three.js PR:Added HTMLTexture
https://github.com/mrdoob/three.js/pull/31233 (opens in a new tab) - PlayCanvas HTML-in-Canvas 文档
https://developer.playcanvas.com/user-manual/graphics/advanced-rendering/html-in-canvas/ (opens in a new tab) - Chrome for Developers 视频:Build next-generation UIs with the HTML-in-Canvas API
https://www.youtube.com/watch?v=TUtKGTeFWjQ (opens in a new tab) - WebGPU.com 介绍
https://www.webgpu.com/news/google-html-in-canvas-webgl-webgpu/ (opens in a new tab)