HTML в Canvas вышел, что он нам несёт?
• dom, html, js
Введение
Шёл 2011 год. Вышла экспериментальная технология – CSS Shaders (оно же CSS Custom Filters). Это была возможность нарисовать привычный нам HTML, а “поверх” применить к нему произвольные шейдеры (будь то попиксельная трансформация или более навороченные эффекты). По итогу возможность “заворачивать” уголок элемента, переворачивать элементы спиралькой и прочие весёлые вещи удалили.
Что ж. Наступил октябрь 2026го, и вышел Хром 157. В нём – возможность под названием HTML in Canvas. Которая позволяет рисовать привычный HTML, а затем брать его в виде картинки и делать с ним, что вздумается (например, применять к нему те же шейдеры). Как же оно работает?
Новое апи
Новое апи использует идею того, что внутрь <canvas> можно положить произвольный HTML:
<canvas>
<input id="input">
</canvas>В существующих браузерах такая конструкция значит, что в случае отсутствия поддержки <canvas> вложенная вёрстка будет использоваться, как фолбек.
Для того, чтобы заработала новая логика, нужно добавить новый атрибут content=drawable на канвас и drawable на вложенную вёрстку:
<canvas content="drawable">
<input id="input" drawable>
</canvas>content=drawable переключает режим работы вложенной вёрстки с фолбека на новую механинку. Вёрстка с атрибутом drawable отрисовывается в невидимую картинку, но не рисуется на экран. Эту картинку можно использовать программно при отрисовке канваса: для 2д контекста новый метод называется drawElementImage, а для 3д контекстов есть методы для получения текстуры. Передать в них можно только элемент, помеченный атрибутом drawable.
Чтобы всё это работало, нужно отслеживать обновление узлов – без этого мы получим статичную картинку. Для отслеживания изменений появилось новое событие paint:
canvas.addEventListener('paint', () => {
ctx.reset();
ctx.drawElementImage(input, /*x*/ 0, /*y*/ 0);
});Всё, этого кода хватает для минимального примера работы. Напечатав что-нибудь в инпуте, можно увидеть, что канвас перерисовался.
Что осталось за кадром? Взаимодействие с вёрсткой: смена курсора мыши при наведении, клики и другое. Ведь мы можем нарисовать “картинку” в произвольном месте, как браузер понимает, что конкретный пиксель кликабелен? drawElementImage сам передаёт эту информацию при вызове.
Однако drawElementImage – метод 2д контекста, а что с 3д? WebGL и WebGPU канвасы могут использовать методы updateElementGeometry / clearElementGeometry. Они позволяют сообщить браузеру, где именно в итоге оказался (или не оказался) указанный элемент.
Доступность
Важным плюсом данного подхода является доступность из коробки, ведь это обычная вёрстка. Работает также и aria-hidden, и другие стандартные штуки.
Что происходит, если элемент в канвасе есть, но по итогу не был нарисован? Он всё ещё может получить фокус (а в инпуты можно вводить текст), однако у них нет геометрии. Теоретически, скринридеры могут отфильтровывать элементы без геометрии, как ненарисованные.
Политика безопасности
Как вы понимаете, отрисовка элементов в текстуры / картинки означает определённые требования к контенту. Следующая информация считается чувствительной и может тем или иным способом не рисоваться или блокировать отрисовку:
- Кроссдоменный контент (ифреймы, картинки, канвасы с кроссдоменным содержимым и прочее)
- Системные цвета, темы и настройки
- Ошибки правописания
- Маркировка ссылок “посещёнными” (
:visited) - Промежуточное состояние автозаполнения форм
- Субпиксельное сглаживание текста (текст по итогу будет иметь сглаживание, но в виде полупрозрачных “grayscale” пикселей), тем самым отрисовка будет отличаться от других частей сайта
- Субтитры и кнопки управления видео
- Служебные элементы ввода текста (попапы, подчёркивания и прочее, например, в азиатских языках)
Есть и информация, которая не считается “приватной” и по итогу попадёт на “скриншот” элемента.
Что ещё?
Я не останавливался на целой россыпи апи: вложенных drawable, трансформациях, поддержке OffscreenCanvas и многом другом. Более подробно и с некоторыми примерами можно ознакомиться на странице с объяснением АПИ.
Я же здесь приведу свой небольшой пример:
Итог?
Меня беспокоит, что функция вышла в стабильном релизе браузера, однако позиция Файерфокса и Сафари не ясна. Фича сложная, с россыпью апи и с хардварными завязками, насколько она даже реализуема в других движках – большой вопрос.
Опасения всё ещё есть и про безопасность. В такой сложной фиче нужно продумать пересечение буквально со всеми возможностями, которые уже есть. Не всплывёт ли где-то случай, из-за которого разработчики Хрома резко побегут что-то чинить? А то и вовсе всё выключат.
В остальном выглядит очень здорово. Я даже могу представить, когда какие-то украшения или визуальные эффекты можно заворачивать в подобный канвас и получать необычный эффект. Главное, чтобы по итогу оно не осталось в загончике, как CSS Paint API.
Обсудить в Telegram



