HTML-in-Canvas: proposta de nova API para renderizar conteúdo HTML diretamente no Canvas
(github.com/WICG)- HTML-in-Canvas é um projeto do WICG que propõe uma nova API padrão para renderizar diretamente elementos/conteúdo HTML dentro do
<canvas>na web - Surgiu para resolver problemas de layout de texto complexo, acessibilidade, internacionalização e questões de qualidade/desempenho, e permite usar estilização HTML diretamente em diversos casos de uso de Canvas, como gráficos, UI e menus de jogo
- Por meio de métodos novos como
drawElement,texElement2DesetHitTestRegions, é possível renderizar e texturizar elementos HTML diretamente no contexto 2D do Canvas ou WebGL - Áreas de interação, melhoria de acessibilidade, UI 2D em cenas 3D, layout baseado em CSS/HTML etc. refletem necessidades reais de desenvolvimento de web apps
- Atualmente pode ser habilitada no Chrome Canary (138.0.7175.0 ou superior) com flag experimental, e feedbacks e relatórios de bug são bem-vindos
Visão geral e importância
- Proposta de uma nova API para desenhar elementos HTML diretamente no
<canvas> - Antes não havia uma forma simples de renderizar facilmente texto complexo, layout e conteúdo baseado em HTML em
<canvas>, então havia limitações de acessibilidade, internacionalização, desempenho e qualidade - A HTML-in-Canvas surge como uma solução complementar, suportando renderização de HTML em Canvas 2D e WebGL, ampliando a aplicabilidade em diversas áreas, como ferramentas de gráfico, caixas de texto com recursos e UI de jogos.
Casos de uso
- Representação no canvas de texto e conteúdo de layout com estilos
- Ex.: legendas, eixos, caixas de editor rich-text e menus em jogos
- Melhoria de acessibilidade
- Resolve a inconsistência entre conteúdo alternativo de canvas e o conteúdo realmente renderizado
- Permite sincronizar informações de acessibilidade com a nova API
- Integração entre HTML e shaders WebGL
- Vai além dos efeitos de
filterdo CSS, atendendo à demanda por combinar HTML com shaders WebGL convencionais
- Vai além dos efeitos de
- Renderização de HTML em contexto 3D
- Permite inserir conteúdo 2D rico em áreas 3D de jogos e sites
API proposta e principais recursos
- O atributo
<canvas layoutsubtree>ativa o layout de elementos HTML filhos do canvas (por padrão, apenas renderização visual; não é exposto para algoritmos de navegação da UA) - CanvasRenderingContext2D.drawElement(element, x, y, options)
- Renderiza os elementos HTML filhos do canvas na posição especificada
options.allowReadbackcontrola a proteção contra vazamento de dados pessoais (uma política detaintingserá aplicada futuramente)- Os parâmetros
dwidth/dheightpermitem redimensionar para o tamanho desejado
- WebGLRenderingContext.texElement2D(...)
- Desenha o elemento HTML especificado diretamente como textura em WebGL para uso em cena 3D
- setHitTestRegions
- Conecta os elementos desenhados em uma região ao
hit testdo canvas, redirecionando automaticamente eventos de mouse/toque
- Conecta os elementos desenhados em uma região ao
- Opção fireOnEveryPaint (ResizeObserver)
- Detecta automaticamente o momento de rerender de mudanças/reposicionamentos HTML e aciona o redesenho do canvas
Funcionamento e limitações
- Na chamada de
drawElement, há consideração da matriz de transformação do canvas (CTM) e a imagem é recortada apenas dentro daborder boxdo elemento - A imagem desenhada no canvas é estática (se o elemento mudar após o render, é necessário chamar
drawElementnovamente) - Não há suporte para canvas offscreen ou fora do DOM (limitação técnica)
- Elementos interativos (botão, formulário etc.) podem ser desenhados, mas não se tornam automaticamente interativos
iframecross-origin eSVG foreignObjectnão são suportados- Questões de acessibilidade, segurança e privacidade (PII) ainda estão em discussão
Exemplo de demonstração
- Exemplo complex-text: desenhar diretamente no canvas, com
drawElement, textos com estilo HTML, caixas e layouts complexos - Exemplo webGL: gerar textura WebGL a partir de conteúdo HTML com
texElement2De mapear em um cubo 3D - Exemplo text-input: marcar regiões interativas usando
setHitTestRegionsefireOnEveryPaintpara formulários e outras áreas de entrada
Teste para desenvolvedores e observações
- Ative no Chrome Canary com a flag
--enable-blink-features=CanvasDrawElement - Como o conteúdo do canvas não fica
tainted, é obrigatório tomar cuidado com possível vazamento de dados pessoais - A API e seu funcionamento ainda estão em evolução, e ainda faltam casos de teste HTML em grande escala
- Feedback é bem-vindo: recomenda-se reportar em Issues do GitHub problemas de compatibilidade, falhas de renderização e questões de acessibilidade
Valor e perspectivas
- Em gráficos, visualização de dados, UI dentro de canvas, HUD e menus em jogos 3D, entre outros, traz ganho de expressividade e produtividade da web
- O que antes era uma conversão HTML→Canvas complexa (estilo, layout, suporte multilíngue, acessibilidade) passa a ser tratado diretamente via API padrão
- Para desenvolvedores de gráficos, jogos e apps web, representa uma tecnologia promissora
1 comentários
Comentários do Hacker News
Há muita preocupação com acessibilidade e abuso, mas vale olhar também para outro lado dessa discussão Vi um fio interessante no Twitter recentemente em que se dizia que 90% das boas coisas que poderiam acontecer na web não acontecem porque não se pode usar renderização de fontes e métricas no JS Houve respostas diversas, incluindo o ponto de que a web foi projetada para representar texto, mas não tem recursos para tratar texto em nível detalhado, e o pesar de que no tldraw foi necessário implementar à força a medição de texto (fio do Twitter: https://x.com/_chenglou/status/1951481453046538493) Como a web é uma plataforma de desenvolvimento de aplicações, torná-la mais fácil e poderosa é bom para todos Na minha opinião, as APIs da web deveriam ir mais a um nível mais baixo, e seria ótimo ter uma API de fonte/métricas de texto para canvas Ao mesmo tempo, como o layout de texto do motor da web é extremamente eficiente, seria ótimo se essa função também pudesse ser usada dentro do canvas O caso que venho relembrando há anos é a “edição de rich text com paginação”; como com
contenteditablesó não dá para fazer uma implementação em nível de produto, o Google Docs acabou criando um motor de layout próprio Se essa proposta for aplicada, dá para levar tanto a robustez docontenteditablequanto o controle de layout de página/impressão Espero que esse recurso seja aplicado nos navegadoresTenho dúvidas da afirmação de que “a maioria das boas coisas que podem acontecer na web é impossível por não termos acesso à renderização de fontes e métricas” Eu gostaria de ver qual é o caso realmente inovador Hoje, em JS, já há bastante informação de fontes e métricas disponível, e a maioria das funcionalidades necessárias pode ser contornada sem travar seriamente a performance Além disso, o que o HTML-in-Canvas oferece também não cria uma mudança fundamental nessa parte
Eu também estou usando Harfbuzz e um motor de layout próprio no Nutrient via WASM, como no Google Docs Demo: https://document-authoring-demo.nutrient.io/ Se essa API fosse oficialmente oferecida pela plataforma, o desenvolvimento ficaria muito mais fácil Graças ao WASM, não é realmente um beco sem saída Ouvi que o ElectricSQL está com trabalho de sincronização, então dei um alô ao Oleksii
Sobre o pedido de que “esse recurso seja aplicado ao navegador”, não sei por que querer estender para o canvas o motor de layout/UI mais ineficiente do mundo Isso só vai consolidar ainda mais o problema atual de não ter acesso a boas APIs O Figma funciona criando outro navegador dentro do navegador para superar os limites do DOM (veja: https://www.figma.com/blog/building-a-professional-design-tool-on-the-web/) Se o
contenteditablenão consegue uma implementação em nível de produto e por isso o Google Docs criou um motor próprio, essa nova proposta teria dificuldade em ajudar de fato no layout de rich textConsidero a utilidade grande, mas a própria estrutura de inserir HTML dentro de canvas dentro de HTML fica meio estranha e destoante Na minha visão, o canvas deveria ser um formato independente de primeira classe no navegador, para ser tratado com mais naturalidade Então ficaria natural tanto inserir canvas em uma página centrada em HTML quanto inserir elementos HTML em uma estrutura centrada em canvas Claro, isso é só a minha opinião
O que você disse não parece estranho Só para registrar, já dá para inserir HTML dentro de SVG, e dentro de HTML de novo Se o canvas for o elemento principal da página, onde salvar o título da página? No fim, teria de usar a tag , então, por exemplo:
Se fosse possível colocar conteúdo diretamente dentro da tag canvas, isso seria resolvido de forma simples
Sites com canvas como centro tendem a ser incômodos Não dá para usar serviços completos do sistema (autocompletar, acessibilidade etc.) e há também questões de privacidade Por exemplo, é difícil usar a correção ortográfica do sistema, e como a acessibilidade do sistema também não é oferecida, cada app teria que implementar acessibilidade de UI totalmente diferente
O que você descreveu seria como inventar Flash Mas colocar Flash na web também foi uma dor enorme
Há casos em que queremos colocar uma página HTML com canvas e adicionar layout/estilo ao texto dentro Alterar toda a forma de layout da página por conta disso é uma complicação desnecessária
No passado, as pessoas se opuseram a acesso do DOM via WASM Por isso, vejo essa direção de evolução como inevitável
Agora nós chegamos ao ponto de compilar o navegador inteiro para WASM e chegar no momento de executar esse navegador dentro do elemento canvas do navegador principal
Até o próprio sistema operacional com IE na web também já é possível (ex.: https://copy.sh/v86/?profile=windows2000)
A premissa é parecida com a famosa palestra The Birth & Death of JavaScript Referência: https://www.destroyallsoftware.com/talks/the-birth-and-death-of-javascript
https://www.chromium.org/blink/blink-in-js/ também é uma dessas tentativas
Pela questão de ‘sandboxing e segurança’, pode vir um futuro em que essa estrutura se torne necessária
Em https://trevorlinton.github.io, dá para ver um ambiente parecido em primeira mão
No https://github.com/WICG/html-in-canvas/blob/main/security-privacy-questionnaire.md há um TODO dizendo que precisa acrescentar mais sobre o risco de fingerprinting
Acredito que já é possível já hoje obter resultado parecido com HTML-in-Canvas usando a tag
foreignObjectdo SVG Por exemplo, há projetos como https://github.com/zumerlab/snapdom que copiam o DOM com estilo inline para dentro doforeignObjectdo SVG e renderizam isso no canvasforeignObjectno canvas Além disso, também suporta recursos novos, como atualizar automaticamente o canvas quando o conteúdo muda e interatividadeNão sei se estou errado, mas sinto que renderizar HTML sobre canvas com JS puro já é plenamente possível Canvas é usado para desenhar o que não pode ser feito com HTML, e não é uma estrutura para substituir o DOM
Hoje, por exemplo:
Se elementos HTML sempre estiverem na frente de tudo no canvas, tudo bem, mas se não estiverem, precisa colocar outro canvas por cima do html, e repetir por camada z Com essa mudança, acho que finalmente dá para corrigir a “camada de renderização invertida” do navegador Acredito que toda renderização de navegador deva ficar sobre uma API universal de canvas
Em breve, acho que vamos precisar novamente renderizar canvas dentro do HTML-in-Canvas
Me lembrei do meme Pimp My Ride “cara, como você gosta de HTML, te botei HTML dentro de canvas e canvas dentro de HTML”
Pensei em algo assim: dar um flag no elemento body:
Assim, a página inteira vira uma superfície de desenho igual à do canvas e passa a renderizar elementos DOM normalmente Internamente, talvez ficasse melhor abrir também o fluxo de rasterização até o DOM Em termos de arquitetura, renderização do DOM e do canvas se tornam camadas totalmente equivalentes Por exemplo, uma ação de desenhar linha na página poderia controlar se força ou ignora um reflow de elemento DOM
Dá para imaginar todos os leitores de tela gritando ao mesmo tempo
Nesse formato, o canvas também poderia ajustar automaticamente o tamanho, e se isso ocorrer, estaríamos abrindo uma nova era de composição HTML Poderíamos ir além do iframe
Embora soe estranho, sou a favor dessa proposta Às vezes, quando precisa desenhar alguma coisa, é comum reaproveitar um elemento HTML existente Antes, a jogada era renderizar isso em bitmap offscreen e copiar para o canvas, ou ajustar com
z-indexeposition absolute, mas o canvas sempre acabava cobrindo visualmente; isso melhorou bastante recentemente Talvez esse método não seja a solução perfeita, mas acho que é bem melhor do que os truques anteriores É uma solução utilizável como ohtml2canvas, para quando for estritamente necessário