Chrome 157 中的 HTML-in-Canvas:2D、WebGL 和 WebGPU 中的交互式 DOM

发布时间:2026 年 10 月 26 日

在成功完成源试用后,Chrome 157 正式发布了 HTML-in-Canvas API 的稳定版本。HTML-in-Canvas API 弥合了 DOM 的交互式、无障碍世界与 <canvas> 的高性能、像素级控制之间的差距。此 API 兼具丰富的浏览器功能和 GPU 加速的画布图形,让您两全其美。

HTML-in-Canvas API 视频概览。

Canvas 与 DOM 的两难选择

以前,在创建对视觉效果要求较高的 Web 应用时,您必须在标准 HTML 元素和原始画布上下文之间做出选择。

技术 优势 限制
<canvas> 通过 GPU 访问权限进行低级像素控制,以驱动 2D 和 3D 图形流水线、自定义着色器和离屏工作器。为繁重、数据密集的界面提供高性能渲染。 没有内置的 Web 平台功能,例如文本选择、复制和粘贴、右键点击操作以及文本换行。不透明像素网格默认不支持屏幕阅读器、页内查找、自动翻译或自动填充,需要采用后备实现。
HTML 开箱即用的 Semantic UI,内置表单控件、自适应排版和 CSS 样式。与屏幕阅读器、页内查找和开发者工具深度集成。 控制复杂界面性能的能力有限。视觉效果仅限于标准 CSS 和 SVG,不涉及直接像素操作或着色器。

HTML-in-Canvas 推出之前

在此 API 推出之前,如果您构建了大量使用画布的界面,则必须在以下两种方法之间做出选择,每种方法都有其自身的缺点:

  1. 直接将文本渲染为画布像素 (fillText()):应用以命令式方式将文本和界面控件绘制为原始像素。这种方法存在以下缺点:
    • 无障碍功能故障:屏幕阅读器和辅助工具无法读取画布像素,除非您手动构建并同步一个不可见的后备 DOM。
    • 浏览器功能失效:用户无法使用“在页面中查找”功能(Ctrl/Cmd+F)进行搜索、无法自然地复制和粘贴文本、无法触发上下文菜单,也无法使用浏览器翻译和拼写检查功能。
    • 复杂的排版引擎:支持国际化需要捆绑大型 JavaScript 布局引擎。
  2. 画布顶部的浮动 HTML 叠加层:例如,使用 JavaScript 计算边界框和矩阵转换,从而在画布上定位标准 HTML 元素的库。这种方法的缺点包括:
    • 同步延迟和视觉撕裂:在 3D 模式下滚动、缩放或移动摄像头时,由于帧时间差异,叠加层 DOM 元素可能会相对于画布像素发生漂移或抖动。
    • 剪裁和 Z 轴排序限制:HTML 叠加层始终位于整个画布缓冲区的顶部。如果不采用复杂的 iframe 到图片解决方法,就无法在 3D 场景内嵌入 HTML(例如,在 3D 对象后面、玻璃材质内或在镜子中反射)。
    • 性能开销:为了使叠加层与画布保持一致,您必须在 JavaScript 中重新计算每个叠加层的转换,并在每一帧中将其写入 style.transform。然后,浏览器会解析每个字符串并重新计算元素的样式,然后才能渲染帧,因此主线程工作量会随着您添加的每个叠加层而增加。在 2D 上下文中,drawElementImage() 会为您更新元素的位置。在 WebGL 和 WebGPU 中,您需要将计算出的转换作为矩阵传递给 updateElementGeometry()。无论采用哪种方式,浏览器都不会解析 CSS 或重新计算样式。

HTML-in-Canvas 的主要优势

HTML-in-Canvas 消除了这些弊端。通过将 HTML 放置在 <canvas> 元素中,内容可保持互动性,并且所有浏览器集成都会自动运行。

在 <canvas> 内呈现的 HTML 内容与 <canvas> 之外的 HTML 具有相同的功能:

  • 文本布局和格式设置:支持文本布局和格式设置,包括应用了 CSS 样式的多行或双向文本。
  • 表单控件:富有表现力的表单控件,具有丰富的 CSS 和着色器自定义选项。
  • 文本选择、复制和粘贴以及右键点击:用户可以突出显示 3D 场景中的文本或触发上下文菜单。
  • 无障碍功能:在画布内呈现的 HTML 内容会向无障碍树公开,以便屏幕阅读器读取。
  • 浏览器功能集成:翻译、自动填充和页面内查找等浏览器功能开箱即用。用户可以翻译或搜索 WebGL 和 WebGPU 纹理中的文本。
  • 扩展程序集成:浏览器扩展程序可对内容执行操作。例如,文本替换扩展程序会自动更新 3D 网格上呈现的文本。
  • 开发者工具集成:直接在 Chrome 开发者工具中检查和调整画布界面元素的 CSS 样式。
  • 可编入索引性与 AI 智能体:网络爬虫和 AI 智能体可以为渲染到 2D 和 3D 场景中的 DOM 内容编入索引。
  • 媒体编辑和导出:将包含实时 DOM 元素的完整画布合成直接导出为图片(toDataURL()、toBlob())或视频流 (captureStream())。
演示,比较直接渲染到画布中的文本和 HTML-in-Canvas 的功能集成。在 HTML-in-Canvas 窗格中,内容可供选择和翻译,并且浏览器功能(例如自动填充)开箱即用。在标准画布窗格中,内容会使用 fillText 方法直接渲染到画布中,并且不具有互动性。

主要应用场景

HTML-in-Canvas 可在多个方面发挥作用:

  • 大型 Canvas 应用:重量级 Web 应用可以直接在 Canvas 工作区中渲染界面组件,从而提高无障碍性并缩减软件包大小。
  • 3D 场景和游戏:沉浸式 WebXR 体验和游戏可以直接在场景中放置交互式 DOM 元素,例如游戏内终端或可阅读的 3D 书籍。
  • 媒体编辑和导出:将丰富的 HTML 排版与着色器效果相结合的创意工具,可将合成场景直接导出为图片或视频流。
  • 富有表现力的界面:您可以将 HTML 内容作为原始像素进行操作,以构建着色器驱动的视觉效果。

HTML-in-Canvas 快速入门

在画布中呈现 HTML 需要执行以下步骤:

  1. 准备画布。以声明方式设置正确的属性,让浏览器知道它应该将 HTML 渲染到画布中。此设置在 2D、WebGL 和 WebGPU 上下文中完全相同。了解如何设置画布以及如何声明要独立绘制的 HTML 元素。

    <!-- Prepare your canvas by setting the `content` attribute -->
    <canvas id="canvas" width="600" height="400" content="drawable">
      <!-- Mark child as `drawable` to render to canvas -->
      <div id="myElement" drawable>
        <!-- Your HTML here -->
      </div>
    </canvas>
    
  2. 将元素图片绘制到画布中。具体实现取决于您是在 2D、WebGL 还是 WebGPU 上下文中呈现 HTML。

    const ctx = canvas.getContext("2d");
    // Draw HTML element into canvas in 2D
    ctx.drawElementImage(myElement, myElementX, myElementY);
    
  3. 可选:同步 DOM 和像素。几何图形同步还取决于您使用的上下文。在 2D 模式下,浏览器默认会自动处理,而在 3D 上下文中,您需要构建一个转换并将其传递给 updateElementGeometry 方法。

    // In 3D, construct a transform as needed, for example:
    const transform = new DOMMatrix().translate(x, y);
    // Synchronize the element's DOM and pixels
    canvas.updateElementGeometry(myElement, { canvasTransform: transform });
    

框架和生态系统支持

主要的 WebGL 和 3D 图形库都支持 HTML-in-Canvas:

  • Three.js:使用 THREE.HTMLTexture 提供实验性支持。

    const material = new THREE.MeshBasicMaterial();
    material.map = new THREE.HTMLTexture(uiElement);
    const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material);
    scene.add(mesh);
    
  • PlayCanvas:支持使用 setSource() 进行 HTML 纹理流式传输。

    canvas.addEventListener('paint', () => {
      htmlTexture.setSource(htmlElement);
    }, { once: true });
    
  • Babylon.js:通过 BABYLON.HtmlTexture 提供内置绑定。

    const htmlTexture = new BABYLON.HtmlTexture("htmlTexture", uiElement, scene);
    material.diffuseTexture = htmlTexture;
    
  • PixiJS:在版本 v8.19.0 中提供了对 HTMLSource 的内置支持。

    import { HTMLSource } from 'pixi.js/html-source';
    const sprite = Sprite.from(new HTMLSource({ resource: form, autoUpdate: true }));
    app.stage.addChild(sprite);
    
  • CanvasUI:一个专为 HTML-in-Canvas 设计的开源组件库。

如需了解更多实现详情,请参阅各框架的文档。

功能检测和后备策略

为确保跨浏览器兼容性,请在运行代码之前验证 API 支持情况:

export function supportsHtmlInCanvas() {
  if (typeof document === "undefined") return false;
  const canvas = document.createElement("canvas");
  canvas.setAttribute("content", "drawable");
  return canvas.content === "drawable";
}

如果该 API 不可用,您可以回退到备用界面、浮动 HTML 叠加层或某个可用库(例如 three-html-render、html2canvas 或 dom-to-image)。

后续步骤