[JavaScript] JavaScriptで実現するレスポンシブデザイン: canvas と HTML/CSSの同期

はじめに

最近、暇さえあれば、早朝からブロック崩しゲームを開発してるのですが、canvasで描画した領域と、HTML/CSSで描画した領域を、同期させ、多様性のある表現をしようとした際に、かなり難しい事が分かったので本日苦戦した内容を忘れないように備忘録としてまとめておきます。

誤解なきように言うと単純な座標合わせだけでいうと凄く簡単です。

でも、CSSでborderやmargin、paddingなど、複雑な要素を追加すると、どうしてもズレが生じそこで挫折してロールバックして作り直しました。

やっぱり、基礎が分かっていないとこういう時に躓いて苦しむことになります。(´・ω・)

開発してるゲームに関しては、以下の記事で確認できます。

ホントは、Web Audio APIの実装方法とか、プログレスバーの実装など、書きたい事は沢山あるのですが、気力が追い付かず、午前零時も回ってしまったので一番苦労した点だけ。

余談ですが、時間を忘れて開発する程、アプリ開発は楽しいし、JavaScriptの自由度の高さには驚くばかりで、なぜもっと早くこの言語を学ばなかったのかと後悔しています。

概要

レスポンシブデザインは、異なる画面サイズに対応したアプリケーションやゲームの実装に欠かせません。

特に、HTML/CSSで作成したボックスcanvas の描画(ctx.rect など) を同期させるのは、多くの開発者が直面する課題です。

本記事では、HTML/CSSのサイズ調整とcanvasの描画内容を同期させる方法、そしてレスポンシブに対応するための考え方を紹介します。

1. レスポンシブデザインの基本

レスポンシブデザインとは、ユーザーがどのデバイス(PC、スマートフォン、タブレットなど)を使っても、コンテンツが見やすく配置されるように調整する設計思想です。これを実現するためには、以下の2つが主なポイントとなります:

  • フレキシブルなレイアウト: ビューポート(表示領域)のサイズに合わせて、コンテンツが自動的に調整されるようにする。
  • メディアクエリ: CSSを使って画面サイズに応じたレイアウトを切り替える。

例: メディアクエリの基本

/* スマートフォン向け */
@media (max-width: 600px) {
  .game-container {
    width: 100%;
    height: 100%;
  }
}

/* タブレット向け */
@media (min-width: 601px) and (max-width: 1024px) {
  .game-container {
    width: 80%;
    height: 80%;
  }
}

上記のように、画面サイズに応じてレイアウトを切り替えることが基本となります。

2. canvas のサイズ変更と描画の同期

canvas のサイズ変更に合わせて描画内容を更新する方法として、以下の2点が重要です:

  1. canvas の幅と高さをビューに合わせて変更
  2. 描画内容を再描画

canvasのリサイズ

canvas 要素は、ビューポートのサイズに合わせて動的にリサイズすることができます。この際、widthheight 属性を設定することで、正しくスケーリングできます。

function resizeCanvas() {
  const canvas = document.getElementById('gameCanvas');
  const ctx = canvas.getContext('2d');

  // ウィンドウサイズに合わせてcanvasの幅と高さを設定
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;

  // リサイズ後に描画を更新
  updateCanvas();
}

function updateCanvas() {
  const canvas = document.getElementById('gameCanvas');
  const ctx = canvas.getContext('2d');

  // 新しいサイズに合わせて描画
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = 'red';
  ctx.fillRect(10, 10, 100, 100);
}

// ウィンドウのリサイズ時にキャンバスを更新
window.addEventListener('resize', resizeCanvas);
resizeCanvas();  // 初回のリサイズ

このコードでは、window.innerWidthwindow.innerHeight を使って画面サイズに応じたcanvasのサイズを設定し、その後描画内容を更新しています。

3. block-box(HTML/CSS)の調整

HTML/CSSで作ったボックス(block-boxなど)とcanvasを合わせるためには、次の点に注意します。

CSSのマージンやボーダーに注意

block-box と canvas の間でズレが生じる主な原因は、marginborder の設定です。これらのプロパティが影響しないように、box-sizing: border-box を適用することが重要です。

#block-box {
  position: absolute;
  top: 20px;
  left: 0;
  width: calc(100vw - 20px); /* ビューポート幅に合わせて調整 */
  height: calc(100vh - 20px); /* ビューポート高さに合わせて調整 */
  box-sizing: border-box;
  border: 2px solid black;
}

canvas と block-box の同期

canvas のサイズ変更に合わせて、block-box の幅と高さも動的に変更することで、両者の同期を取ることができます。

function adjustBlockBoxSize() {
  const blockBox = document.getElementById('block-box');
  const canvas = document.getElementById('gameCanvas');

  blockBox.style.width = `${canvas.width}px`;
  blockBox.style.height = `${canvas.height}px`;
}

window.addEventListener('resize', () => {
  resizeCanvas();
  adjustBlockBoxSize();
});

4. 最適化:両者を無理に合わせない

canvasblock-box を無理に合わせようとするのではなく、一方で処理を完結させる方法を採用することが最適です。例えば、canvas 上でのゲームロジックとUI要素をすべて描画し、block-box は単にCSSの背景として使用するだけでも十分です。

結論

  • canvas のリサイズ: window.innerWidthwindow.innerHeight を使用して、動的にサイズを変更し、描画内容を更新する。
  • HTML/CSSの同期: box-sizing: border-boxcalc() を使って、canvasblock-box のサイズを同期させる。
  • 無理に合わせない: 両者を無理に同期させず、一方の領域で完結させる処理を行うことも一つの方法。

最後に

レスポンシブデザインは難しく感じることもありますが、少しずつ改善していくことが大切です。必要に応じてコードを調整し、動的に画面に合わせて描画を行うことで、柔軟に対応できるようになります。