HTML-in-Canvas: propuesta de una nueva API para renderizar contenido HTML directamente en Canvas
(github.com/WICG)- HTML-in-Canvas es un proyecto de WICG que propone una nueva API estándar para dibujar elementos/contenido HTML directamente dentro de
<canvas>en la web - Surgió para resolver problemas de diseño de texto complejo, accesibilidad, internacionalización y calidad/rendimiento, y permite aprovechar la maquetación HTML directamente en casos de uso variados de Canvas, como gráficos, UI y menús de videojuegos
- Mediante métodos nuevos como
drawElement,texElement2DysetHitTestRegions, es posible renderizar y convertir en textura elementos HTML de forma directa en contextos Canvas 2D o WebGL - Refleja necesidades reales de desarrolladores de aplicaciones web, como áreas de interacción, mejoras de accesibilidad, UI 2D dentro de escenas 3D y layouts basados en CSS/HTML
- Actualmente está disponible como bandera experimental en Chrome Canary (a partir de 138.0.7175.0), y se aceptan comentarios y reportes de bugs
Resumen y relevancia
- Propuesta de una nueva API para dibujar elementos HTML directamente en
<canvas> - Antes, al no existir una forma sencilla de renderizar contenido con maquetación compleja, texto y HTML en
<canvas>, había limitaciones en accesibilidad, internacionalización, rendimiento y calidad - HTML-in-Canvas aborda estas carencias al habilitar renderizado HTML en Canvas 2D y WebGL, lo que mejora su aplicabilidad en herramientas de gráficos, cajas de texto enriquecido, UI de juegos y otros escenarios
Casos de uso
- Representación en canvas de texto con estilos y contenido de layout
- Ejemplos: leyendas y ejes de gráficos, cajas de editor enriquecido, menús dentro de juegos, entre otros
- Mejora de accesibilidad
- Soluciona la discrepancia entre el contenido alternativo del canvas y lo realmente renderizado
- Permite sincronizar mejor la información de accesibilidad con la nueva API
- Combinación de HTML con shaders de WebGL
- Responde a la necesidad de combinar HTML con shaders de WebGL estándar, más allá de los filtros CSS
- Renderizado de HTML en contexto 3D
- Permite insertar contenido 2D rico en áreas 3D de juegos o sitios web
API propuesta y funciones clave
- Activa el layout de elementos HTML hijos del canvas con el atributo
<canvas layoutsubtree>(por defecto, se renderiza solo de forma visual y no se expone a los algoritmos de navegación de la página ni de UA) - CanvasRenderingContext2D.drawElement(element, x, y, options)
- Renderiza un elemento HTML hijo del canvas en la posición indicada
options.allowReadbackcontrola la prevención de filtraciones de datos personales (se aplicará una política detaintingen el futuro)- Puede redimensionarse con los parámetros
dwidth/dheightal tamaño deseado
- WebGLRenderingContext.texElement2D(...)
- Dibuja un elemento HTML especificado directamente como textura de WebGL para usarlo en una escena 3D
- setHitTestRegions
- Asocia elementos dibujados en zonas específicas con eventos del canvas (hit test) para redirigir automáticamente eventos de mouse/táctil
- fireOnEveryPaint en ResizeObserver
- Detecta automáticamente el momento de rerender del canvas y dispara nuevo dibujo cuando hay cambios o reacomodos de HTML
Funcionamiento y limitaciones
- Al invocar drawElement, se refleja la matriz de transformación del canvas (CTM) y la imagen se recorta solo dentro del border box del elemento
- La imagen dibujada en el canvas es estática (si el elemento cambia después de renderizarlo, es necesario llamar a drawElement nuevamente)
- No se admite en canvas offscreen o canvas fuera del DOM (limitación técnica)
- Se pueden dibujar elementos interactivos (botones, formularios, etc.), pero no se vuelven interactivos automáticamente
- No se admite cross-origin iframe, SVG
foreignObject, entre otros - Los temas de accesibilidad y seguridad/privacidad (PII) siguen en discusión
Ejemplos de demo
- Ejemplo de texto complejo: dibujar directamente con drawElement texto con estilos HTML, cajas y layouts complejos sobre canvas
- Ejemplo de webGL: crear una textura de WebGL con
texElement2Da partir de contenido HTML y mapearla en un cubo 3D - Ejemplo de entrada de texto: mostrar regiones interactivas como formularios mediante
setHitTestRegionsyfireOnEveryPaint
Prueba para desarrolladores y consideraciones
- Habilitar en Chrome Canary con la bandera
--enable-blink-features=CanvasDrawElement - Como el contenido del canvas no se contamina (
tainted), es obligatorio tener cuidado para evitar fugas de información personal - La API y su comportamiento aún cambian, y todavía faltan casos de prueba HTML a gran escala
- Se invita a dejar feedback: reportar en GitHub Issues casos de compatibilidad, fallas de renderizado, problemas de accesibilidad, etc.
Valor práctico y perspectivas
- En áreas como gráficos, visualización de datos, UI dentro de canvas y HUD/menús en videojuegos 3D, mejora la expresividad y productividad de la web
- Lo que antes era una conversión compleja de HTML a Canvas (estilos, layout, soporte multilingüe, accesibilidad) ahora puede tratarse de forma directa con una API estándar
- Los desarrolladores de gráficos, juegos y aplicaciones web lo ven como una tecnología potente con gran potencial
1 comentarios
Comentario de Hacker News
Hay muchas preocupaciones sobre accesibilidad y abuso, pero creo que hay que ver otro ángulo de esta discusión Recientemente vi un hilo interesante en Twitter donde se decía que, en el desarrollo web, no se puede usar el renderizado ni las métricas de fuentes en JS, así que no ocurre el 90% de las cosas buenas Un ejemplo de esto es que la web está diseñada para representar texto, pero no tiene capacidades para manejar texto con detalle, y que en tldraw es una lástima que tengan que implementar la medición de texto a la fuerza (hilo de Twitter: https://x.com/_chenglou/status/1951481453046538493) La web es una plataforma para desarrollo de aplicaciones, así que hacer que sea fácil y poderosa para construir beneficia a todos En mi opinión, la API web debería bajar un poco más el nivel; sería fantástico tener una API de métricas de fuente/texto para canvas Pero al mismo tiempo, el layout de texto del motor web es increíblemente rápido, así que si esta capacidad también puede usarse dentro de canvas, aparecerán mejoras muy interesantes El caso que he ido repitiendo durante años es la edición de texto enriquecido con paginación; como con contenteditable no se puede lograr una implementación de nivel de producto, Google Docs terminó construyendo su propio motor de layout Si esta propuesta se aplica, se podría tener tanto la potencia de contenteditable como el control del layout de páginas/impresión Ojalá esta función llegue al navegador
Cuestiono un poco la afirmación de que “la mayoría de las buenas cosas que pueden pasar en la web no ocurren porque no hay acceso a renderizado y métricas de fuentes” Me gustaría ver un caso realmente innovador y representativo Aún hoy en JS ya se ofrece bastante información de fuentes y métricas, y la mayoría de funciones necesarias se pueden evitar sin un impacto serio en el rendimiento Además, lo que propone HTML-in-Canvas tampoco cambiaría ese punto de manera fundamental
Yo también estoy usando en Nutrient HarfBuzz y un motor de layout propio sobre WASM, como Google Docs Demo: https://document-authoring-demo.nutrient.io/ Si esta API se provee oficialmente en la plataforma sería mucho más fácil desarrollar Con WASM no es realmente un callejón sin salida Me comentaron que ElectricSQL está en proceso de sincronización, así que salúdales a Oleksii
No entiendo por qué pedir que se aplique al navegador algo así como extender el motor de layout/UI más ineficiente del mundo al ámbito de canvas Eso solo endurecería el problema actual de no tener buenas APIs Figma funciona construyendo otro navegador dentro del navegador para superar las limitaciones del DOM (ver: https://www.figma.com/blog/building-a-professional-design-tool-on-the-web/) Si Google Docs tuvo que construir su propio motor porque contenteditable no puede alcanzar implementación de nivel de producto, esta nueva propuesta apenas ayudaría al layout de texto enriquecido en la práctica
Creo que la propuesta es útil, pero la estructura en sí de meter HTML dentro de canvas dentro de HTML se siente rara y fuera de lugar En mi opinión, el canvas tendría que convertirse en un formato de primer nivel independiente dentro del navegador para que se lo pueda manejar de forma orgánica Así, sería natural insertar canvas en páginas centradas en HTML, o lo contrario, elementos HTML dentro de páginas centradas en canvas De todos modos, eso es solo mi opinión
No veo nada raro en lo que dices Por ejemplo, ya se puede meter HTML en SVG, nuevamente en HTML, y en otros lugares Si canvas es el elemento principal de la página, ¿dónde se guarda el título de la página? Al final, habría que usar la etiqueta , así que un ejemplo podría ser
Si se hiciera posible que el contenido entre dentro del tag canvas, se resolvería de forma simple
Los sitios web centrados en canvas son incómodos No se pueden usar todos los servicios del sistema (autocompletado, accesibilidad, etc.) y además hay problemas de privacidad Por ejemplo, es difícil usar la función de corrección ortográfica del sistema y la accesibilidad del sistema no se entrega, así que habría que implementar una accesibilidad de UI totalmente distinta en cada app
Si tomas esa estructura, es como inventar Flash Pero meter Flash en la web también fue un dolor enorme
A veces necesitas tener un canvas en una página HTML y agregarle layout o estilos al texto que está dentro No es necesario complicar de esa forma el modelo completo de layout de la página
La gente ya se opuso antes al acceso de WASM al DOM Por eso creo que esta dirección de evolución es inevitable
Ahora estamos en el punto de compilar todo el navegador en WASM y ejecutar ese navegador dentro del elemento canvas del navegador principal
Incluso es posible ejecutar IE junto con el sistema operativo completo en la web (por ejemplo: https://copy.sh/v86/?profile=windows2000)
Es parecido a la premisa de la charla The Birth & Death of JavaScript Referencia: https://www.destroyallsoftware.com/talks/the-birth-and-death-of-javascript
También existe un intento como https://www.chromium.org/blink/blink-in-js/
Por temas de sandboxing y seguridad, podría llegar un futuro donde esta arquitectura sea obligatoria
Por cierto, puedes ver un entorno similar directamente en https://trevorlinton.github.io
En https://github.com/WICG/html-in-canvas/blob/main/security-privacy-questionnaire.md hay un TODO que dice que hay que añadir más sobre el riesgo de fingerprinting
Pienso que ya se pueden obtener resultados similares a HTML-in-Canvas usando la etiqueta
foreignObjectde SVG Por ejemplo, existe un proyecto como https://github.com/zumerlab/snapdom que copia el DOM con estilos en línea dentro de unforeignObjectde SVG y lo renderiza en canvasforeignObjecten canvas Además, además, soporta funcionalidades nuevas como actualizar automáticamente el canvas cuando cambie el contenido y ofrecer interactividadNo sé si estoy equivocado, pero siento que renderizar HTML sobre canvas es totalmente posible con JS puro Canvas se usa para dibujar cosas que no se pueden hacer en HTML, no es un reemplazo del DOM
Por ejemplo, ahora mismo:
Si los elementos HTML están delante de todo en canvas, está bien, pero si no lo están hay que poner otro canvas sobre HTML, y eso se repite por cada capa Z Con este cambio creo que por fin podemos corregir el “stack de renderizado invertido” del navegador Pienso que todo el renderizado del navegador debería apilarse sobre una API universal de canvas
Me parece que pronto necesitaremos volver a renderizar canvas dentro de HTML-in-Canvas
Me trae a la mente el meme de Pimp My Ride Es como si dijera: “Bro, como te gusta HTML, te metí HTML dentro de canvas y un canvas dentro de HTML”
Me pregunto si sería mejor dar una bandera al elemento body así
Así, toda la página sería la misma superficie de dibujo que canvas y se podrían renderizar elementos DOM como de costumbre Quizás sería mejor abrir internamente el proceso de rasterizar también el DOM En términos de arquitectura, el renderizado DOM y el de canvas serían capas completamente equitativas Por ejemplo, una acción como dibujar una línea en la página podría controlar si fuerza o ignora un reflow de elementos DOM
Se me viene a la cabeza a todos los lectores de pantalla gritando al mismo tiempo
Con este enfoque, el canvas también podría autoajustar su tamaño, y si ese fuera el caso, sería una nueva era de composición en HTML Podría ir más allá de iframe
Aunque suene raro, tiendo a apoyar esta propuesta A veces pasa que para dibujar algo conviene reutilizar elementos HTML existentes Antes, aunque lo renderizábamos en un bitmap fuera de pantalla para copiarlo a canvas o intentábamos ajustarlo con z-index y position absolute, el canvas siempre terminaba tapándolo visualmente (aunque esto ya mejoró bastante últimamente) Esta forma no necesariamente es la solución perfecta, pero me parece claramente mejor que los trucos previos Justo como html2canvas, puede ser una solución útil cuando realmente hay que hacerlo así