Canvas UIとは?html-in-canvasの対応状況

Canvas UIとは?html-in-canvasの対応状況

「Canvas UI が話題になっているけれど、これは本番のサイトに入れていい技術なのか」——canvasui.dev を開いてデモの派手さに驚いたあと、多くの開発者が最初に抱く疑問がこれです。

結論から言うと、Canvas UI の中核である html-in-canvas API は、まだ Chromium 系ブラウザでフラグまたは Origin Trial が必要な実験機能です。Safari は標準化ポジションを表明しておらず、Firefox もポジション未確定のまま。「対応済みの技術」とは呼べません。ただし、非対応環境で壊れないフォールバック設計にはなっています。

株式会社Fyveは日々クライアントのWebサイトを実装している立場から、この技術を「今どこまで信用してよいか」を切り分けます。この記事では公式ドキュメントに加えて、私が実際にリポジトリを取得してソースコードを読んだ結果も併せて整理しました。

Canvas UI(canvasui.dev)とは何か

Canvas UI は、html-in-canvas と WebGL を使ったクリエイティブ系コンポーネント集です。公式サイトは自らを「html-in-canvas ベースとしては世界初のコンポーネントライブラリ」と位置づけています。

作者は David Haz(DavidHDev)。アニメーション付き React コンポーネント集として知られる React Bits の作者と同一人物です。日本のフロントエンド界隈でも React Bits を触ったことがある人は多いはずで、その延長線上にある新作、という理解が近いです。

npm パッケージではなく「shadcn レジストリ」で配る

Canvas UI は npm でインストールする形を取りません。shadcn のレジストリ方式で、コマンドを叩くとコンポーネントのソースコード本体が自分のプロジェクトに直接落ちてくる仕組みです。

導入コマンドはこの形です。

npx shadcn@latest add @canvas-ui/liquid-react

落ちてきたファイルは components/canvasui/ に置かれます。ライブラリを更新する概念がなく、落ちてきたコードは自分のリポジトリのコードとして読んで、直して、バージョン管理する。この設計は実験的なAPIを扱ううえでは合理的です。仕様変更が来たときに、上流のアップデートを待たずに自分で直せるからです。

対応フレームワークは React 19 / Solid 1.9 / Vue 3.5 / Svelte 5 / vanilla TypeScript の5種類。どれも1ファイル完結で、同じエンジン・同じオプションを持ちます。

ライセンスは MIT + Commons Clause

ここは業務利用の前に必ず確認すべき点です。ライセンスは MIT + Commons Clause(Copyright (c) 2026 David Haz)。

  • 自社サービス・クライアント案件・商用サイトへの組み込みは自由
  • ただしコンポーネント自体を売る・再配布する・移植版を配ることは禁止(単体でもバンドルでも)

受託でクライアントのサイトに組み込む使い方は問題ありません。自社のテンプレート商材に同梱して販売する、といった使い方は抵触します。

25種のコンポーネントは、実は「2つの系統」に分かれる

ここは公式サイトの一覧を眺めるだけでは見えにくい部分です。私がリポジトリの src/lib 配下を実際に読んで分類したところ、コンポーネントは明確に2系統に割れていました。

  • html-in-canvas 依存:22種 — Asciify, Bend, Blaze, Bubble, Cloth, Clouds, Droplets, Frost, Glass, Glitch, Grid, HexFloat, Laser, Liquid, Magnify, ParticleReveal, ParticleScroll, Peel, RetroDither, Ripple, Shatter, VHS
  • three.js ベースで html-in-canvas 不使用:3種 — DitheredObject, GlassObject, ParticleObject

後者3つは 3Dモデル・SVG・画像を素材にする「Object」系で、html-in-canvas を一切使わないため、今日どのブラウザでもフルに動きます。逆に言えば、それ以外の22種は実験APIの上に乗っています。

Canvas UI の25コンポーネントの内訳。html-in-canvas 依存が22種、three.js ベースで今日どのブラウザでも動くものが3種

依存関係も確認しました。公開されているレジストリのJSONを取得したところ、html-in-canvas 系は dependencies が空配列、つまり外部ライブラリ依存ゼロでした。three.js が必要なのは Object 系3種だけです。

  • glass-react:依存なし/Glass.tsx 約21,500文字
  • liquid-react:依存なし/Liquid.tsx 約28,000文字
  • glass-object-react:three に依存/GlassObject.tsx 約36,700文字

html-in-canvas 系はレンダリングに three.js を使わず、生の WebGL2 シェーダーを手書きしています。1ファイル2万文字前後という重さはそのぶんですが、バンドルに three.js が増えないのは利点です。

中核技術 html-in-canvas API の仕組み

Canvas UI を評価する前に、土台となる html-in-canvas API そのものを押さえておく必要があります。これは <canvas> の中に生きた DOM をそのまま描き込めるようにする提案仕様です。

3つのプリミティブ

仕様は3つの部品でできています。

  • layoutsubtree 属性<canvas layoutsubtree> と書くと、直下の子要素がレイアウトとヒットテストの対象になります(描画されるまでは不可視)
  • 描画メソッド:2Dなら drawElementImage(element, dx, dy)、WebGL なら texElementImage2D()、WebGPU なら copyElementImageToTexture()
  • paint イベント:子要素の描画内容が変わると発火。canvas.requestPaint() で明示的に要求できます

最小構成はこれだけです。

<canvas layoutsubtree id="source"><div id="content">...</div></canvas>
const ctx = canvas.getContext("2d");
canvas.onpaint = () => { ctx.reset(); ctx.drawElementImage(content, 0, 0); };
canvas.requestPaint();

「スクリーンショット方式」との決定的な違い

これまで HTML を canvas に持ち込むには、html2canvas のようなライブラリで見た目を再現した画像を作るしかありませんでした。この方式では、テキストは選択できず、リンクは押せず、スクリーンリーダーからも見えない「ただの絵」になります。

html-in-canvas はブラウザ自身が描くため、以下がそのまま保たれます

  • アクセシビリティツリーへの露出(スクリーンリーダーが読める)
  • テキストの選択・コピー・右クリックメニュー
  • ページ内検索(Ctrl+F)と翻訳機能
  • フォームのオートフィル、ダークモード
  • ブラウザ拡張機能、DevTools でのインスペクト
  • 検索クローラやAIエージェントによる読み取り

「派手な演出を入れるとSEOとアクセシビリティを犠牲にする」という長年のトレードオフを、原理から解消しにいく提案だという点が本質です。

描かれないもの — プライバシー保護の除外リスト

一方で、意図的に描画から除外されている要素があります。canvas に描けるということは、その内容を getImageData() で読めてしまうことを意味するためです。

  • クロスオリジンの iframe や画像、URL 参照(background-imageclip-path など)
  • システムカラー・テーマ・ユーザー環境設定
  • スペルチェックの波線、訪問済みリンクの色
  • まだ確定していないオートフィルの内容
  • サブピクセルアンチエイリアス、字幕設定、IMEのポップアップ

訪問済みリンクの色を読めてしまえば閲覧履歴が抜けます。この除外リストは、そうした攻撃を潰すための設計です。

ブラウザ互換性 — 結論は「まだ実験機能」

本題です。2026年7月時点の状況を、ブラウザごとに整理します。

html-in-canvas・WebGL2・WebGPU のブラウザ対応状況一覧。html-in-canvas は Chromium 系のみフラグまたは Origin Trial で利用可、Safari と Firefox は未対応

Chrome・Chromium系:フラグまたは Origin Trial で利用可

Chromium には実装されていますが、既定では無効です。ローカル開発で試すには chrome://flags/#canvas-draw-element を有効化してブラウザを再起動します。

公開サイトで一般ユーザーに届けたい場合は、Chrome の Origin Trial にドメインを登録してトークンを取得し、meta タグか HTTP ヘッダで配信します。トークンはドメインに紐づきます。

マイルストーンの状況はこうなっています。

  • フラグによる開発者トライアル:Chrome 138 から
  • Origin Trial:Chrome 148〜150、延長が入り 154 まで
  • Chrome の安定版は執筆時点で 150(151 は 2026年7月28日予定)

つまりOrigin Trial は現在進行中で、登録すれば今日から Chrome / Edge ユーザーに届けられます。ただし期限があり、Chrome 154 以降も使える保証はありません。Chromium 側は延長理由を「WebGL / WebGPU 向けAPIとプライバシー面で大きな変更を入れたため、フィードバックを集め続けたい」と説明しています。API の形がまだ動く前提だということです。

Edge や Brave など Chromium 派生ブラウザでも、同じフラグ名が使えます(Brave なら brave://flags/#canvas-draw-element)。

Safari は「表明なし」、Firefox は「ポジション未確定」

ここが最も重要な判断材料です。

  • Safari / WebKit:標準化ポジションの表明(signal)がない状態。実装予定のアナウンスもありません
  • Firefox / Mozilla:standards-positions の該当 issue は 2024年9月に起票されたまま「Needs proposed position」。仕様の議論を次段階へ進めること自体には反対していない一方、フィンガープリンティングと互換性の懸念を継続して議論中です。実装予定はありません

相互運用上の懸念として挙がっているのは、「グラデーションやフォームコントロールが実際にどう描かれているかのピクセルが読めてしまう」点です。ブラウザやOSごとに描画が微妙に違うため、それが端末識別の材料になり得ます。

加えて、仕様そのものが WICG の「living explainer(継続的に更新される解説)」段階です。メソッド名や引数が今後変わる可能性が明記されています。

対比:フォールバック側の WebGL2・WebGPU は実用段階

誤解しないでほしいのは、Canvas UI が使う技術のうちWebGL 側は完全に実用段階だという点です。

  • WebGL2:全モダンブラウザで利用可能
  • WebGPU:2026年1月に Baseline 入り。Chrome / Edge 113以降、Safari 26以降、Firefox は Windows 141以降・macOS ARM64 145以降で有効(Linux と Android の Firefox は対応作業中)

「Canvas UI は実験的」と一括りにせず、実験的なのは html-in-canvas のレイヤーだけと切り分けて理解するのが正確です。

非対応ブラウザで実際に何が起きるか

公式は「graceful degradation(優雅に劣化する)」と説明していますが、実際の挙動を確かめるためソースコードを読みました。

判定は2つの関数の有無だけ

全コンポーネントに共通する判定ロジックは、驚くほど単純でした。

const probe = document.createElement("canvas");
const ctx = probe.getContext("2d");
return Boolean(
  ctx &&
  typeof ctx.drawElementImage === "function" &&
  typeof probe.requestPaint === "function"
);

2Dコンテキストに drawElementImage があり、canvas 要素に requestPaint があるか。この2条件だけです。自分で機能検出を書く場合も、この形をそのまま流用できます。

判定が真なら canvas.onpaint を張り、ライブHTMLをテクスチャ化して WebGL2 のシェーダーに渡します。偽ならその経路をまるごと張らず、例外も投げません

機能検出の結果による分岐。対応環境ではライブHTMLが歪む中核表現が動き、非対応環境では普通のHTML表示とWebGL2オーバーレイのみになる

「壊れない」は本当。ただし「同じ体験」ではない

非対応ブラウザで起きることを正確に言うと、こうなります。

  • コンテンツは普通のHTMLとして問題なく表示される(テキストもリンクも生きている)
  • WebGL2 のオーバーレイだけが上に走る
  • 「HTMLそのものを歪ませる・粒子化する・溶かす」という中核の表現は丸ごと落ちる

つまり Safari と Firefox のユーザーには、デモサイトで見た体験とは別物が届きます。壊れないことと、意図した表現が届くことは、別の話です。ここを混同したまま「フォールバックがあるから大丈夫」と判断すると、後で説明に困ります。

なお実装上の細かい点として、Canvas UI はサーバーサイドレンダリング時には「対応している」と仮定して警告バナーを隠す設計になっていました。フラグOFFのほうを例外扱いする、開発者向けの割り切りです。

導入判断のチェックポイント

今日から本番に入れてよい条件

私の整理では、以下をすべて満たすなら本番投入は現実的です。

  • その演出が「あったら嬉しい」レベルの装飾であり、体験の必須要素ではない
  • 非対応ブラウザで表現が落ちた状態を、それ単体で完成品として見せられる
  • Origin Trial のトークン更新と、Chrome 154 以降に打ち切られた場合の運用を誰が見るか決めてある
  • Object 系3種で足りるなら、そもそも html-in-canvas を使わない選択も検討した

逆に、コンバージョンに直結するファーストビューの主役として据えるのは、現時点では勧めません。ユーザーの相当数に届かない演出に、サイトの第一印象を預けることになるためです。

LPファーストビューの作り方|成約を生む設計の型

見落としやすい3つの落とし穴

仕様書と実装を読んで、事前に知っておくべきだと感じた制約が3つあります。

1つ目は、スクロールがメインスレッド依存になること。canvas の中身は JavaScript から描画されるため、通常のDOMスクロールのようにコンポジタスレッドへ逃がせません。canvas 内に長いスクロールリストを置くと、スクロールのたびに毎回 paint ハンドラを通ります。演出の対象は、スクロールし続ける領域ではなくセクション単位に絞るのが安全です。

2つ目は、描画元の CSS transform が無視されること。描画対象の要素に掛けた CSS transform は描画時には効きません(ヒットテストとアクセシビリティには効きます)。既存のアニメーションと組み合わせるとき、見た目と当たり判定がずれる原因になります。はみ出したコンテンツが border box でクリップされる点も同様です。

3つ目は、仕様変更リスクを誰が引き受けるかという問題。API名も引数も変わり得る段階です。ソースが自分のリポジトリに落ちてくる shadcn 方式は、この点では有利に働きます。上流の更新を待たずに自分で直せるからです。ただしそれは「自分で直す前提」を引き受けるということでもあります。クライアント案件で使うなら、保守範囲の会話を先にしておくべきです。

まとめ

Canvas UI と html-in-canvas について、現時点の結論を整理します。

  • html-in-canvas は実験機能。Chromium 系でフラグまたは Origin Trial(Chrome 148〜150、延長で154まで)が必要。Safari は表明なし、Firefox はポジション未確定
  • Canvas UI の25種のうち22種がこのAPIに依存。残る3種(Object系)は three.js ベースでどこでも動く
  • フォールバックは正しく実装されている。判定は drawElementImagerequestPaint の有無のみで、非対応環境でも例外は出ない
  • ただし非対応環境では中核の表現が丸ごと落ちる。「壊れない」と「同じ体験が届く」を混同しない
  • 装飾レイヤーとしてなら今日から実用可能。体験の主役に据えるのは時期尚早

技術的な筋の良さと、今日の実用性は別の話です。html-in-canvas は「演出とアクセシビリティのトレードオフ」という長年の課題に正面から挑む提案で、方向性としては極めて健全だと私は考えています。だからこそ、Safari と Firefox が動くかどうかを見極める段階にある、というのが今の正確な位置づけです。

参考リンク

成果から逆算するHP制作
← Back to Blog