マガジン

CanvasとHTML、ゲーム画面はどちらで作る?操作と表現から選ぶ

遊びをつくる

執筆にClaudeを使用しています。

絵の具で描いた動きと紙のカード型部品を、一つの駒がつなぐコラージュ
記事のテーマをもとに制作したAI生成イラスト。

Webゲームを作り始めると、最初の岐路がここにあります。「ゲーム画面はCanvasに描くのか、HTMLの要素で組むのか」。どちらもブラウザ標準の機能ですが、得意なことがはっきり違います。この記事では、速度の話だけに絞らず、テキスト・入力・アクセシビリティまで含めて違いを整理し、自分のゲームに合う方式を選べるようにします。

この記事の目次
  1. CanvasとHTML DOMの正体を確認する
  2. アニメーションと描画速度:Canvasが強い場面
  3. テキストとフォーム:DOMが素直な場面
  4. キーボード・タッチ入力の扱い方の違い
  5. アクセシビリティ:現状と現実的な対処
  6. 混在パターンと選び方の基準

CanvasとHTML DOMの正体を確認する

Canvas APIは、HTMLの<canvas>要素をビットマップ描画の領域として使い、JavaScriptで線・図形・画像・テキストを直接書き込む仕組みです。ブラウザはその結果を1枚の画像として扱います。ページ上に「何が描かれているか」という意味情報は持たず、支援技術(スクリーンリーダーなど)からは基本的に見えません。

一方のHTML DOM方式は、<div>・<button>・<p>などの要素をCSSで配置し、JavaScriptでクラスや属性を切り替えてゲームの状態を表現します。ブラウザはレイアウトエンジンを通じて各要素を描画し、フォーカス管理・テキスト選択・アクセシビリティツリーなどの機能がそのまま使えます。

簡単に言えば、Canvasは「自分で全部描く」、HTML DOMは「ブラウザに任せる部分が多い」という構造の違いです。この違いが、以降の各場面での挙動の差に直接つながります。

アニメーションと描画速度:Canvasが強い場面

毎フレーム多数のオブジェクトが動くゲームでは、Canvasが有利です。理由はシンプルで、DOMの再レイアウトコストを払わずに済むからです。HTML DOMで要素の位置やサイズを毎フレーム変更すると、ブラウザはレイアウト計算を繰り返します。要素数が増えるほどこのコストは重くなります。

Canvasでは、requestAnimationFrameのコールバック内でcanvasを全消去して描き直す方法が基本です。MDNのCanvas最適化ガイドには、更新頻度が異なるレイヤー(背景・ゲーム本体・UI)を別々の<canvas>要素に分けて重ねる手法が紹介されています。静止している背景を毎フレーム描き直さないことで、無駄な処理を省けます。

javascript
// 説明用の簡略例:毎フレームの描画ループ
function gameLoop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  // ゲームオブジェクトを描画
  sprites.forEach(s => s.draw(ctx));
  requestAnimationFrame(gameLoop);
}
requestAnimationFrame(gameLoop);

上のコードは仕組みを示す説明用の簡略例です。実際のゲームでは衝突判定・状態管理・サウンドなど多くの処理が加わります。

HTML DOM方式でも、CSSトランジションやWeb Animations APIを使えばスムーズなアニメーションを実現できます。ただしオブジェクト数が多く、位置が毎フレーム変わるような場面(スクロールアクション・粒子エフェクトなど)では、DOMのレイアウト計算が負担になりやすい点を意識しておく必要があります。

テキストとフォーム:DOMが素直な場面

ゲーム内にセリフ・説明文・スコア表示・名前入力欄があるなら、HTML DOMの方が扱いやすいです。<p>や<span>で書いたテキストはブラウザが折り返し・フォントレンダリング・テキスト選択を処理し、<input>や<textarea>はソフトウェアキーボードの表示やオートフィルとも連携します。

Canvasでテキストを描く場合、ctx.fillText()を使います。しかしCanvas上のテキストはビットマップとして描かれるため、ピンチズームや画面拡大で滲むことがあり、コピー&ペーストもできません。長い説明文をCanvasに描くと、読みにくくなる場面が出てきます。スコア表示のような短い数値ならCanvasで問題ありませんが、ゲーム内テキストが多い場合はDOMに委ねる方が無難です。

フォーム要素については、HTML DOMほぼ一択です。<input type="text">はモバイルでのキーボード表示・入力補完・パスワードマネージャーとの連携が自然に動きますが、これをCanvasで再現しようとするとかなりの実装コストがかかります。ゲームのスタート画面やプレイヤー名入力は、HTML要素を使う方が現実的です。

キーボード・タッチ入力の扱い方の違い

キーボードイベント(keydown・keyup)はCanvasでもDOMでも同様にdocumentやwindowにリスナーを登録して取得できます。この点に大きな差はありません。

マウス・タッチの「どこをクリック/タップしたか」の処理には差が出ます。HTML DOMでは各要素がクリックイベントを独立して受け取れるので、ボタンや選択マスを要素として並べれば、「どの要素がクリックされたか」はブラウザが判定します。Canvasでは描画した図形はブラウザには見えないため、クリック座標をcanvas全体のmousedownイベントで受け取り、自前で「どのオブジェクトの領域か」を計算する必要があります。オセロや将棋のようなマス目ゲームでは、この判定ロジックはシンプルですが、不規則な形のオブジェクトが多いゲームではDOMに分がある場合もあります。

フォーカス管理もDOMの強みです。Tabキーでボタンを移動する操作や、:focus-visibleによるフォーカスリングの表示はHTML要素なら自動です。ゲームパッドやキーボードだけで操作したいユーザーへの配慮を入れるなら、UI部分はDOM要素で作る方が出発点が楽です。

アクセシビリティ:現状と現実的な対処

MDNのCanvas API解説には明記されています。Canvas要素はビットマップであり、その内容をアクセシビリティツリーに公開しません。スクリーンリーダーは原則としてCanvas上に描かれた内容を読み上げられず、画面拡大ツールとの相性も悪くなりやすいです。

HTML DOMはセマンティクスを持つため、role・aria-label・tabindexなどの属性を適切に設定すればスクリーンリーダーとの連携が可能です。ゲームで絶対的なアクセシビリティ対応が必要な場合は、少なくともUI部分(メニュー・スコア・操作説明)はDOM要素で書くことが現実的な出発点になります。

完全に対応することが難しい場合でも、Canvas上の重要な状態(スコア・手番・ゲームオーバーなど)を画面外のHTML要素として持たせ、aria-live領域を通じて変化を通知する方法があります。ゲームの中核がCanvasでも、状態の読み上げをDOMで補うことは組み合わせれば可能です。

混在パターンと選び方の基準

実際のWebゲームでは、CanvasとHTML DOMを併用するパターンが多く見られます。典型的な構成は次のとおりです。

  • ゲームフィールド → Canvas:キャラクター・弾・背景など毎フレーム変化する部分。描画速度が必要で、セマンティクスは不要。
  • UI・HUD → HTML DOM:スコア表示・ライフ残数・ボタン・テキスト説明。ブラウザのフォントレンダリングと拡大縮小に任せられる。
  • メニュー画面・入力フォーム → HTML DOM:プレイヤー名入力・設定・スタート画面。フォーム機能とキーボードナビゲーションが自然に動く。

逆にHTML DOMだけで完結するゲームもあります。たとえばカードゲーム・パズル・クリッカーのように、アニメーションが穏やかで要素数が少ないゲームです。CSSのtransitionやgridレイアウトを活用すれば、Canvasなしでも十分滑らかに動かせます。

以下は判断の目安です。

  • 毎秒60フレームで多数のオブジェクトを動かす → Canvasを中心に検討
  • テキストが多い・フォームがある・キーボードナビゲーションが必要 → DOMを中心に検討
  • スクリーンリーダー対応が必要 → CanvasにDOMで状態通知を組み合わせる
  • ゲーム部分はCanvas、HUDはDOMの混在でもよい → CSSでcanvasとDOM要素をposition:absoluteで重ねるのが定番

「どちらが正解か」という問いより、「このゲームの何の部分で速度が必要か」「テキストや入力はどこにあるか」を先に整理する方が、選択しやすくなります。迷ったら小さな画面をどちらかで作ってみて、実際の動作で判断するのが確実です。

作り上げたゲームはHTMLファイルやZIPをアソバースに投稿するか、公開済みURLを登録する形で公開できます。CanvasベースでもDOMベースでも投稿方式は共通です。

出典・参考資料