拡大するとぼやける:描画解像度と表示解像度の差
遊びをつくる執筆にClaudeを使用しています。

横320×縦180の小さなキャンバスでゲームを作り、CSSで画面幅いっぱいに伸ばす場面を考えてみます。パソコンの小さな画面では問題なく見えても、高解像度のノートPCやスマートフォンで開くと、細い線や文字の縁がにじんで見えることがあります。ゲームのロジックは変わっていないのに、見た目だけが「安っぽく」なります。 原因は、数字が2種類あることです。1つは、ゲームが絵を描いている内部の細かさ(描画解像度)です。もう1つは、その絵が画面上で占める大きさ(表示サイズ)です。2つがずれたまま引き伸ばすと、ブラウザが足りない点を補間して埋めるため、ぼやけます。 この記事では、同じ絵を「伸ばしただけ」と「画面の細かさに合わせた」の2通りで描き分ける小さなテストページを用意します。読者が自分の端末で切り替えて見比べる手順と、結果の読み方を解説し、最後にアソバースへ投稿する前に確かめたい点を整理します。ぼやけ方の程度は端末ごとに違うため、この記事に結果は書きません。見え方は、ご自身の画面で確かめてください。
描画解像度と表示解像度、そして物理ピクセル比
ブラウザのcanvas要素には、似た名前の数字が2組あります。
- 描画解像度:HTMLのwidth・height属性で決まる、canvasの内部の点の数です。
- 表示サイズ:CSSのwidth・heightで決まる、画面上の大きさです。単位はCSSピクセルです。
もう1つ、画面そのものの細かさを表す物理ピクセル比(window.devicePixelRatio)があります。1CSSピクセルが、画面の物理的な点いくつ分にあたるかを示す値です。一般に、高精細な画面では1より大きい値になります。この値が2なら、横1CSSピクセルは物理的に2点に相当します。
描画解像度が320、表示サイズが640CSSピクセル、物理ピクセル比が2の場合を考えてみます。画面上では物理的に1280点ぶんの幅に、わずか320点の絵が引き伸ばされます。4倍の拡大になり、補間によるぼやけが出やすい条件です。
「画面に合わせる」とは、描画解像度を「表示サイズ × 物理ピクセル比」に近づけることです。そのうえで、ゲームの座標系はCSSピクセルのまま使えるように、描画側で倍率をかけます。
ビフォーアフターを自分で作る
次のHTMLをtest.htmlのような名前で保存し、ブラウザで開いてください。外部ライブラリは不要で、1ファイルで動きます。ボタンで「まえ」(描画解像度を表示サイズと同じに固定)と「あと」(物理ピクセル比を掛ける)を切り替えます。
<!doctype html>
<meta charset="utf-8">
<style>
body{margin:0;font-family:sans-serif}
canvas{width:100%;height:240px;display:block;background:#fff}
</style>
<button id="b">切り替え</button> <span id="s"></span>
<canvas id="c"></canvas>
<script>
const c=document.getElementById('c'),x=c.getContext('2d');
let sharp=false;
function draw(){
const dpr=sharp?(window.devicePixelRatio||1):1;
const w=c.clientWidth,h=c.clientHeight;
c.width=Math.round(w*dpr);c.height=Math.round(h*dpr);
x.setTransform(dpr,0,0,dpr,0,0);
x.clearRect(0,0,w,h);
x.strokeStyle='#000';x.lineWidth=1;
x.beginPath();x.moveTo(10,20.5);x.lineTo(w-10,20.5);x.stroke();
x.beginPath();x.arc(80,120,50,0,7);x.stroke();
x.beginPath();x.moveTo(160,200);x.lineTo(300,60);x.stroke();
x.font='16px sans-serif';x.fillStyle='#000';
x.fillText('Hello 12345 あいうえお',160,140);
s.textContent=(sharp?'あと':'まえ')+' 内部'+c.width+'×'+c.height+' / dpr '+dpr;
}
b.onclick=()=>{sharp=!sharp;draw()};
addEventListener('resize',draw);
draw();
</script>ポイントは3行です。
- c.width = w * dpr:内部の点の数を、表示サイズより増やします。
- x.setTransform(dpr,0,0,dpr,0,0):描画命令の座標をCSSピクセルのまま書けるようにします。
- addEventListener('resize', draw):ウィンドウの大きさが変わったら描き直します。
記録の取り方
次の手順で、各条件を同じ順番で見比べてください。
- 「まえ」の状態で、線・円・文字をよく見ます。画面のスクリーンショットを撮っておくと、後で並べて比べられます。
- ボタンを押して「あと」にし、同じ場所を見ます。画面右の表示で、内部サイズの数字が変わっていることも確認します。
- ブラウザの拡大(CtrlまたはCommandキーと「+」)を何段階か変え、そのたびに「まえ」「あと」を見比べます。
- 可能なら、普通の解像度の画面と高精細な画面の両方で同じ手順を行います。
記録は、条件(端末・画面・ブラウザの拡大率)ごとに「内部サイズ」「物理ピクセル比」「線と文字の見え方の印象」をメモすれば十分です。1条件につき2回ほど見直すと、思い込みを減らせます。
結果の読み方
見え方と数字を、次の表で照らし合わせてください。
- 「まえ」と「あと」で見え方がほとんど変わらない、読み方:物理ピクセル比が1に近い画面の可能性があります。表示のdprの値を確認してください
- 「あと」のほうが線や文字がくっきりする、読み方:描画解像度の不足が原因だったと判断できます
- 「あと」でも線が太く灰色がかって見える、読み方:座標が半ピクセルにずれている可能性があります。1px線は座標を.5にする書き方を試します
- 拡大率を変えると「あと」の鮮明さが保たれる、読み方:リサイズ時の再設定が働いています
- 拡大率を変えると崩れる、または元に戻る、読み方:resizeでの再設定が足りない可能性があります
「あと」を選んでも変化がない場合、故障とは限りません。端末の画面が高精細でなければ、差はそもそも出ません。まずdprの値を確認することが、判断の出発点です。
ぼやけ以外の落とし穴
描画解像度を上げると、ぼやけは改善しやすくなりますが、別の問題も起きます。
- ポインタ座標のずれ:マウスやタッチの座標はCSSピクセル基準で届きます。setTransformで倍率をかけた描画とは単位が違う、と混同すると当たり判定がずれます。座標の基準をどちらにそろえるかは、最初に決めておきます。
- メモリと処理の増加:物理ピクセル比が大きい端末では、canvasの点の数が一気に増えます。比の上限を決める(たとえばMath.min(dpr, 2))という判断もあります。上限をいくつにするかは、対象の端末で確かめてください。
- ドット絵の扱い:ドット絵は、あえて補間しないほうが見栄えがよい場合があります。CSSのimage-rendering: pixelatedを使い、倍率を整数にそろえて拡大する手があります。この場合は「ぼやけを消す」より「にじませない」が目的になります。
- リサイズ時の状態の消失:resizeで描き直すときに、ゲームの状態まで初期化してしまう実装があります。描画の再設定と、ゲーム状態のリセットは分けて書きます。
アソバースの作品に当てはめて考える
アソバースでは、ゲームはsandbox付きのiframeの中で実行され、アップロードしたコードはメインサイトと別のオリジンから配信されます。iframeの大きさが変われば、中のcanvasの表示サイズも変わります。ですから、固定サイズを前提にせず、表示サイズに応じて描き直す設計が向いています。
確認済みの情報として、公式の13作品には「言語変更とプレイ画面の拡大で進行を保つ」という共通の仕様があります。ここから読み取れるのは、画面の大きさが変わる操作があっても、遊んでいる状態が失われないことを前提に作られている、という点です。前の章の「描画の再設定」と「ゲーム状態のリセット」を分ける考え方と、方向が重なります。
一方、個々の作品がcanvasを使っているか、描画解像度をどう決めているかは、確認済みの情報にはありません。この部分は作品を開いて確かめてください。ブラウザの拡大や、プレイ画面の拡大を試し、文字や線のくっきり具合と、途中の進行が保たれるかを見ます。
投稿前の確認は、次の順で行えます。
- 直下にindex.htmlを置き、素材は相対パスで参照します。
- 自分の端末で、通常の拡大率と大きめの拡大率の両方で見え方を確認します。
- アップロードは20MiB以内、ZIP展開後は合計100MiB・1,000ファイル以内です。高解像度用の画像を2倍・3倍の大きさで用意する場合は、容量にも気を配ります。
- 投稿画面の「表示の確認」の段階で、実際の表示を見直します。
次の行動
まず上のテストページを保存し、自分の端末で「まえ」と「あと」を切り替えて、dprの値と見え方をメモしてください。次に、手元のゲームのcanvasにdevicePixelRatioの考え方とresizeでの再設定を入れ、ポインタ座標がずれていないかを確かめます。その状態でアソバースに投稿し、プレイ画面の拡大でも崩れないかを見ておくと安心です。
参考資料
- MDN Web Docs「Window: devicePixelRatio プロパティ」
- MDN Web Docs「Canvas API」(高解像度ディスプレイ向けの最適化に関する解説)
- MDN Web Docs「image-rendering」

