[Перевод] HTML-in-Canvas в Chrome 157: интерактивный DOM в 2D, WebGL и WebGPU

Эта статья перевод оригинальной статьи «HTML-in-Canvas in Chrome 157: Interactive DOM inside 2D, WebGL, and WebGPU».
Также я веду телеграм канал «Frontend по‑флотски», где рассказываю про интересные вещи из мира разработки интерфейсов и AI.
Вступление
После успешного origin trial API HTML-in-Canvas официально вышел в стабильной версии Chrome 157. Он объединяет интерактивность и доступность DOM с производительностью и попиксельным управлением <canvas>. Так возможности браузера можно использовать вместе с графикой canvas, ускоренной на GPU.
Выбор между canvas и DOM
Раньше при создании веб-приложений со сложной графикой приходилось выбирать между стандартными HTML-элементами и непосредственной работой с контекстами canvas.
Технология | Сильные стороны | Ограничения |
|---|---|---|
| Низкоуровневое управление пикселями с доступом к GPU для конвейеров 2D- и 3D-графики, собственных шейдеров и воркеров для внеэкранного рендеринга. Высокая производительность в тяжёлых интерфейсах с большим объёмом данных. | Нет встроенных возможностей веб-платформы: выделения, копирования и вставки текста, действий по правому клику и переноса строк. Непрозрачная для браузера сетка пикселей по умолчанию не поддерживает скринридеры, поиск по странице, автоматический перевод и автозаполнение. Для них нужна отдельная реализация. |
HTML | Семантический интерфейс со встроенными элементами форм, адаптивной типографикой и CSS-стилями. Интеграция со скринридерами, поиском по странице и DevTools. | Ограниченные возможности управления производительностью сложных интерфейсов. Визуальные эффекты ограничены стандартными CSS и SVG, без прямого управления пикселями или шейдеров. |
До HTML-in-Canvas
До появления этого API для интерфейсов, активно использующих canvas, было два подхода. У каждого были свои недостатки.
Отрисовка текста непосредственно в пикселях canvas с помощью fillText(). Приложение императивно рисовало текст и элементы управления как наборы пикселей. Это создавало несколько проблем:
Скринридеры и вспомогательные инструменты не могут прочитать пиксели canvas. Для доступности приходилось вручную создавать и синхронизировать невидимый резервный DOM.
Пользователь не мог искать текст через поиск по странице (Ctrl/Cmd+F), привычным образом копировать и вставлять его, вызывать контекстные меню, пользоваться переводом и проверкой правописания в браузере.
Для интернационализации приходилось включать в сборку большие JavaScript-движки компоновки текста.
HTML-элементы поверх canvas. Например, библиотеки размещали стандартные HTML-элементы над холстом, вычисляя ограничивающие прямоугольники и матричные преобразования в JavaScript. Здесь возникали другие проблемы:
Задержки синхронизации и визуальные разрывы. При прокрутке, масштабировании или движении камеры в 3D DOM-элементы могли смещаться или дрожать относительно пикселей canvas из-за разницы во времени подготовки кадров.
Ограничения обрезки и порядка наложения. HTML-слои всегда располагались поверх всего буфера canvas. Поместить HTML внутрь 3D-сцены, например за трёхмерный объект, внутрь стеклянного материала или в отражение зеркала, без сложных обходных решений с преобразованием iframe в изображение было нельзя.
Дополнительная нагрузка. Чтобы HTML-слои оставались на своих местах относительно canvas, на каждом кадре нужно пересчитывать преобразование каждого слоя в JavaScript и записывать его в
style.transform. Перед отрисовкой браузер разбирает каждую строку и пересчитывает стиль элемента, поэтому каждый новый слой увеличивает работу основного потока. В 2D-контекстеdrawElementImage()обновляет положение элемента автоматически. В WebGL и WebGPU вычисленное преобразование передаётся вupdateElementGeometry()как матрица. В обоих случаях браузеру не приходится разбирать CSS и пересчитывать стили.
Что даёт HTML-in-Canvas
HTML-in-Canvas устраняет необходимость в этих компромиссах. HTML внутри элемента <canvas> остаётся интерактивным, а интеграции с браузером работают автоматически.
HTML-содержимое внутри <canvas> сохраняет те же возможности, что и снаружи:
Компоновка и форматирование текста, включая многострочный и двунаправленный текст с CSS-стилями.
Элементы форм с широкими возможностями оформления через CSS и шейдеры.
Выделение, копирование и вставка текста, а также правый клик. Пользователи могут выделять текст внутри 3D-сцен и вызывать контекстные меню.
Доступность: HTML-содержимое canvas попадает в дерево доступности для скринридеров.
Функции браузера, включая перевод, автозаполнение и поиск по странице, работают без дополнительной настройки. Можно переводить и искать текст внутри текстур WebGL и WebGPU.
Расширения браузера тоже работают с этим содержимым. Например, расширение для замены текста автоматически обновляет текст на трёхмерных мешах.
В Chrome DevTools можно просматривать и менять CSS-стили элементов интерфейса внутри canvas.
Поисковые роботы и AI-агенты могут индексировать DOM-содержимое, отрисованное в 2D- и 3D-сценах.
Готовую композицию canvas с живыми DOM-элементами можно экспортировать в изображение (
toDataURL(),toBlob()) или видеопоток (captureStream()).
Сравнение возможностей браузера при отрисовке текста непосредственно в canvas и через HTML-in-Canvas. В области HTML-in-Canvas текст можно выделять и переводить, а автозаполнение и другие функции браузера работают без дополнительной настройки. В области обычного canvas содержимое отрисовано методом fillText и не интерактивно.
Основные сценарии использования
API подходит для следующих задач:
Крупные приложения на canvas могут отрисовывать компоненты интерфейса прямо в рабочих областях холста, улучшая доступность и уменьшая размер сборки.
В 3D-сценах, играх и иммерсивных приложениях WebXR можно размещать интерактивные DOM-элементы прямо внутри сцены: например, внутриигровые терминалы или трёхмерные книги, которые можно читать.
Инструменты для создания и редактирования медиа могут сочетать HTML-типографику с шейдерными эффектами и экспортировать составные сцены непосредственно в изображения или видеопотоки.
Для выразительных интерфейсов можно обрабатывать HTML-содержимое как пиксели и создавать визуальные эффекты с помощью шейдеров.
Как начать работу с HTML-in-Canvas
Подробности есть в технической документации HTML-in-Canvas.
Для отрисовки HTML в canvas выполните следующие шаги.
1. Подготовьте canvas
Декларативно задайте атрибуты, которые сообщают браузеру, что HTML нужно отрисовывать в canvas. Эта настройка одинакова для контекстов 2D, WebGL и WebGPU. В документации описаны подготовка canvas и объявление 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. Нарисуйте изображение элемента в canvas
Конкретная реализация зависит от контекста: 2D, WebGL или WebGPU.
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 });
Поддержка библиотек и экосистемы
HTML-in-Canvas поддерживают основные библиотеки для WebGL и трёхмерной графики.
Перечисленные инструменты являются сторонними проектами сообщества. Google и команда Chrome не разрабатывают, не сопровождают и официально не поддерживают их.
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 поддерживает потоковую передачу HTML-текстур через setSource().
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-слои поверх canvas или одну из готовых библиотек, например three-html-render, html2canvas или dom-to-image.
Эти библиотеки являются сторонними проектами сообщества. Google и команда Chrome не разрабатывают, не сопровождают и официально не поддерживают их.
Что дальше
Изучите полную документацию HTML-in-Canvas на Chrome for Developers.
Дополните возможности ассистентов для программирования с помощью Modern Web Guidance.
Поделитесь обратной связью в репозитории WICG на GitHub.
Посмотрите демонстрации HTML-in-Canvas от сообщества.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.