世界を動かす技術を、日本語で。

HTML-in-Canvasの技術

概要

HTML-in-Canvasは、 HTMLコンテンツをCanvas上に描画 するための新しいAPI提案。 主な目的は、 アクセシビリティや国際化、パフォーマンスの向上。 drawElementやtexElement2Dなどの 新メソッドを追加 し、2D/3D描画やヒットテストを実現。 開発者トライアル はChrome Canaryで利用可能。 既知の制限やフィードバック募集ポイントも明記。

HTML-in-Canvas:新しいCanvas描画API提案

  • HTMLコンテンツをCanvasへ直接描画 可能にする新APIの提案
  • Canvas 2D および WebGL 両方に対応
  • アクセシビリティや国際化、描画品質の向上 を主な目的
  • 複雑なレイアウトやスタイル付きテキスト の描画ニーズに対応
  • アクセシビリティ改善 :Canvasのフォールバック内容と描画内容が一致
  • WebGLシェーダーとHTML要素の合成 が可能
  • 3Dコンテキスト内でのHTMLレンダリング を実現

主なAPIと仕様

  • layoutsubtree属性 :Canvas内の子要素にレイアウトを許可
    • 直接の子要素がスタッキングコンテキスト・コンテインメントブロックとなる
    • 子孫要素は描画やヒットテスト対象外、UAアルゴリズムからも除外
  • drawElement(element, x, y, options) :要素とそのサブツリーを2D Canvasへ描画
    • layoutsubtree指定時のみ有効
    • オプションでプライバシー保護 (allowReadback)
    • dwidth, dheight指定でリサイズ描画 も可能
  • texElement2D(target, level, internalformat, format, type, element) :要素をWebGLテクスチャへ描画
    • layoutsubtree指定時のみ有効
  • setHitTestRegions([{element, rect}, ...]) :Canvas上の要素ごとにヒットテスト領域を設定
    • マウスやタッチイベントを自動的に描画要素へ転送

追加仕様と動作詳細

  • getBoundingClientRect()は空矩形 (layoutsubtree未指定時)
  • drawElementはCanvasのCTMを考慮
  • 描画画像は静的 :要素変更時は再描画が必要
  • fireOnEveryPaint オプション(ResizeObserverOptionsで追加)
    • DOM状態変化時にCanvas再描画通知
  • Canvasの子孫要素はアクセシビリティ情報提供のフォールバック扱い
  • Offscreen canvasやDOM未接続canvasは非対応

セキュリティ・プライバシー

  • allowReadbackオプション :個人情報漏洩防止に利用
  • WebGL描画時はPII含む内容は常に未描画
  • DevTrial利用時は情報漏洩に要注意

デモ・利用例

  • drawElementの基本デモ :青枠がCanvas、黒枠が描画要素
  • texElement2Dのデモ :HTML内容でCubeの面をテクスチャリング
  • three.js拡張による応用デモ
  • setHitTestRegionsとfireOnEveryPaintのデモ :Canvas内で<input>のインタラクション例

開発者トライアル情報

  • Chrome Canary v138.0.7175.0以降 --enable-blink-features=CanvasDrawElement オプションで有効化
  • APIは開発中 :仕様変更の可能性あり
  • どんなHTMLも描画できる保証はない
  • インタラクティブ要素も描画できるが、直接の操作性は自動付与されない
  • 既知の制限
    • クロスオリジンiframeは描画不可
    • SVG foreignObjectは未対応

フィードバック募集

  • どのコンテンツが描画可能か/失敗するか

  • 重要な失敗モードや優先修正点

  • Canvasレンダリングコンテキストごとの不足サポート

  • アクセシビリティとの相互作用や改善案

    • バグ報告や設計提案は GitHub Issue で受付

その他参考資料

  • Security and Privacy Questionnaire
  • 追加ドキュメントや詳細仕様 へのリンク案内

Hackerたちの意見

もうすぐHTML-in-Canvasの中でCanvasレンダリングが必要になるね。

ネストされたキャンバスが同じアプローチを使っていれば、もう動くはずだよ。ただ、サイクルにはならないけどね。サイクルキャンバスを動かすには、親キャンバスを手動でネストされたキャンバスに描く必要がある。

https://github.com/WICG/html-in-canvas/blob/main/security-pr... > TODO: フィンガープリンティングのリスクについて詳しく書く

テキストの中で探してみたけど、追加すべき欠けてる部分だね(「TODO: Don't be evil」にも関連するかも)。

すぐに「Pimp My Ride」の雰囲気を感じたよ。Yo dawg、HTMLが好きって聞いたから、HTMLをキャンバスの中に、さらにそのHTMLの中に入れたんだ。

今やるべきことは、ブラウザをWASMにコンパイルして、そのブラウザをメインブラウザのキャンバス要素内で動かすことだけだね…

IEを使ったOS全体はどう? https://copy.sh/v86/?profile=windows2000

https://www.chromium.org/blink/blink-in-js/

https://trevorlinton.github.io

それが「JavaScriptの誕生と死」の前提なんだよね。[1]: https://www.destroyallsoftware.com/talks/the-birth-and-death...

それから、「サンドボックスとセキュリティの理由で」、これが必須になるんだろうね。

これはすごく便利かもしれないけど、私にとってはHTMLの中のキャンバスってなんか呪われてる感じがする。私の意見では、キャンバスはウェブブラウザのための一級フォーマットであるべきだから、HTMLの中に入る必要はないと思う。そうすれば、HTML優先のページにキャンバス要素を入れるか、キャンバス優先のページにHTML要素を入れるかを選べるようになる。でも、私が何を知ってるっていうんだろう。

HTML優先のページにキャンバスを入れたいけど、キャンバス内のテキストにレイアウトやスタイリングが必要だと気づいたらどうする?その状況をトップレベルのページのタイプにまで持ち上げるのは無駄な気がする。

Canvasファーストのサイトは最悪だね。プライバシーの問題があるから、システムサービスが使えないんだ。修正のためにシステム辞書を使えないし、辞書の内容か、少なくともユーザーがカスタマイズした修正を問い合わせる方法が必要になる。システムレベルのアクセシビリティも提供できないから、自前で作る羽目になって、canvasを使うアプリごとに全然違うUIになっちゃう。

あなたがFlashを発明したと思うけど、Flashを埋め込むのは面倒だって言うのも分かるよ!

あなたが言ってることに全然問題はないと思うよ。参考までに、SVGの中にHTMLを持つことはすでにできるからね。もしcanvasファーストのページがあったら、タイトルはどこに保存するの?そう、<title>に入れるんだ。だから、実際にはcanvas要素の中にコンテンツを許可すればいいだけだと思うよ。要するに、Canvassingって感じ。

みんながWASM DOMアクセスにNOって言ったから、こうなるのは避けられなかったよね。

ちょっと変かもしれないけど、これに賛成だよ。何かを描く必要がある時に、他の場所からHTML要素を再利用できるのは便利だよね。前は、それをオフスクリーンでビットマップにレンダリングしてから、フルスクリーンのクアッドにコピーするか、canvasに描画する必要があった。最近まで、position: absoluteで要素のz-indexを設定しても、canvasに上書きされちゃってたんだ(でも、これもほとんど修正されたと思う)。これがベストな解決策かは分からないけど、以前のハックよりはマシだよ。もしその方法を選ぶなら、基本的にはhtml2canvasって感じ。

SVGのforeignObjectはこれにどう関わってくるの?SVGはすでにこの提案をサポートしてるみたいだね。例えば、https://github.com/zumerlab/snapdomのようなプロジェクトが、インラインスタイルを持つDOMをforeignObjectタグにコピーしてウェブページの「スクリーンショット」を取れるってことが証明してる。もちろん、そのSVGはcanvasにレンダリングできるし。

この提案は、canvasにforeign objectを描くための簡単な方法に似てるね。コンテンツが変わった時にcanvasを更新したり、インタラクティブな機能もサポートしてる。

もし間違ってたら教えてほしいけど、キャンバスの上にHTMLをレンダリングするのは、バニラで十分解決できると思う。キャンバスはHTMLではできないことをレンダリングするためのもので、DOMの代わりにはならないよね。

それは、HTMLの部分がキャンバスにレンダリングされたものの上にある場合にだけ機能するよ。そうじゃないと、HTMLの上に別のキャンバスを追加する必要がある(それぞれの別のzレイヤーについてもね)。私の意見では、このステップはブラウザの「逆転したAPIレイヤースタック」をついに修正し始めると思う。すべてのブラウザレンダリングは、ユニバーサルキャンバスAPIの上に構築されるべきだよ。

これが現在非常に難しい例で、いろいろなハッキーで満足できないワークアラウンドが必要なものだよ:

  1. 例えば博物館の像の3Dモデル
  2. モデルに特定の特徴に注意を引く注釈を追加する(特に注釈が単語や数字だけでない場合) カメラを動かすときに、注釈がモデルに適切に隠れるようにしたいなら、難しいよ。HTMLは使えないし、HTMLを使うと3Dシーンの正しい位置に合わせるために複雑な計算をしなきゃいけないし、常にフレーム遅れになるし、隠蔽も悪い。通常は3Dモデルのバウンディングボックスに基づいて、HTML注釈全体を表示または非表示にするだけだよ(もっと良い解決策を見たことがあるけど、すごく手間がかかった)。だから、3Dテキストを使うこともできるけど、たぶんSDFを使うことになる。でもそうすると、アクセシビリティやその他のものなしに、完全なテキストレンダリングシステムを作ることになっちゃう。さらに、非常にシンプルな注釈以上のもの(例えば、動画、リスト、選択メニューなど)を求めるなら、それらを再発明するか、HTMLに戻る必要があるよ。

アクセシビリティや悪用に関する懸念は確かに多いけど、反対意見も見るのは大事だと思う。数日前にTwitterでいいスレッドがあったんだ:

最近のFigmaのニュースを受けて、ウェブに起こりうる良いことの90%は、JSでフォントレンダリングやメトリクスにアクセスできないせいで実現できないってことを再確認したい。 https://x.com/_chenglou/status/1951481453046538493 いくつかの選ばれた返信もあったよ: テキストを表示するために特別に設計されたプラットフォームが、テキストを詳細に操作する機能を提供していないのはちょっとクレイジーだね。 tldrawでテキストの測定を強引にやるのは心が痛む。 好きか嫌いかは別として、ウェブはアプリケーション開発のためのプラットフォームだから、これを簡単にするのはみんなにとって良いことだよ。ウェブAPIについての私の主張は、もっと低レベルに進むべきだってこと。だから、キャンバス用のフォントやテキストメトリクスAPIがあれば最高だし、これに代わるものになると思う。でも、私は「プラットフォームを使う」ことの支持者でもあって、テキストレイアウトに関してはウェブエンジンは素晴らしくて、すごくパフォーマンスがいい。キャンバス内でのレイアウト機能を拡張することで、たくさんの素晴らしい機能が実現できる。私が何度も振り返ってきたのは、ページネーションされたリッチテキスト編集なんだ。これは、コンテンツエディタブルではプロダクトレベルで実現するのが不可能だから、Googleドキュメントがカスタムレイアウトエンジンを持っている理由の一つだよ。この提案がブラウザに実装されることを願ってる。

ウェブに起こりうる良いことの90%は、JSでフォントレンダリングやメトリクスにアクセスできないせいで実現できない。 この人の「ウェブに起こりうる良いこと」の代表的な抜粋を見てみたいな。私にはかなり馬鹿げて聞こえるから。そんなに多くのものがそれを必要としているわけじゃないし、最近では多くのものがJSで公開されているし、残りの多くはパフォーマンスに悪影響を与えずに回避できるよ。ここではあまり関係ない話だし(つまり、キャンバス内のHTMLについて):HTMLをキャンバスに描画することは、これらの領域では全く影響を与えないよ。

私が何度も振り返ってきたのは、ページネーションされたリッチテキスト編集なんだ。これは、コンテンツエディタブルではプロダクトレベルで実現するのが不可能だから、Googleドキュメントがカスタムレイアウトエンジンを持っている理由の一つだよ。 私たちもNutrientでそうしていて、WASMでHarfBuzzを使って、独自のレイアウトを行ってるよ。デモはここで見てね: https://document-authoring-demo.nutrient.io/ それをプラットフォームにAPIとして組み込むことができれば、かなり楽になるけど、WASMのおかげで完全にストップするわけじゃないよ。ところで、ElectricSQLで同期作業をしてるって聞いたけど、Oleksiiによろしくね :)

ブラウザに対応してくれるといいな。なんで世界で最もパフォーマンスが悪いレイアウト/UIエンジンがキャンバスに影響を与える必要があるの? これって、良いAPIにアクセスできないっていう状況をさらに悪化させるだけだよね。FigmaがDOMの制限を回避するために「ブラウザの中にブラウザを作らなきゃいけなかった」ってことを思い出してほしいな。 https://www.figma.com/blog/building-a-professional-design-to... コンテンツエディタブルをプロダクトレベルで使うのは本当に不可能だから、Googleドキュメントがカスタムレイアウトエンジンを持ってる理由の一つだよ。この提案は、リッチテキストのためにコンテンツエディタブルをフルに活用できるようにするけど、ページ全体や印刷のレイアウト制御もできるようになるんだ。もし自分でうまくいかないって言ってるなら、リッチテキストのためにコンテンツエディタブルを有効にする理由は何なの?

キャンバスの本来の目的は、HTMLとCSSのひどいごちゃごちゃから脱却することだよ。キャンバスのために新しいシンプルなUIライブラリが開発されるのを見たいな。