Set the canvas’s CSS size to fill its container, then set its actual width/height (backing store) to CSS size times devicePixelRatio for sharpness. Listen for resize and orientationchange, recompute a scale factor, and rescale your game’s internal coordinate system on every change.
At a glance
| Fact | Value | Source |
|---|---|---|
| Canvas has CSS size and backing store size | two separate sizes | developer.mozilla.org |
| devicePixelRatio scales backing store for sharpness | multiply width/height | developer.mozilla.org |
| Core Web Vitals segmentation | segment mobile and desktop | web.dev |
A canvas has two sizes: the CSS size (how big it looks) and the backing store size (its actual pixel width/height attributes). For responsive behavior, set the CSS size with a stylesheet rule like canvas { width: 100%; height: 100%; } inside a container sized by flexbox or viewport units, then on load and on every resize set canvas.width = cssWidth * devicePixelRatio and the same for height, and call ctx.scale(devicePixelRatio, devicePixelRatio) so drawing coordinates stay in CSS pixels while the output stays sharp on high-DPI phones.
If you publish to multiple platforms, Playgama Bridge adapts one HTML5 build to 25+ platforms so platform SDK integrations stay unified.
Listen for both resize and orientationchange – mobile browsers fire orientation changes separately and often resize the viewport with a delay, so debounce the handler and recompute your layout scale factor rather than assuming one event covers both. Keep your game logic in a fixed internal coordinate space and apply a single uniform scale to fit it inside the current canvas, adding letterboxing rather than stretching, to avoid distorted sprites or hitboxes on unusual aspect ratios.
What about engines that compile to WebGL?
Unity WebGL exposes a canvas you resize the same way from JavaScript, calling into the page through a .jslib plugin as described in the Unity browser scripting docs. Godot 4 web exports use the JavaScriptBridge singleton for the same purpose. For layout details specific to the canvas element itself, see MDN’s Canvas API reference.
Sources
- MDN: Canvas API
- web.dev: Core Web Vitals
- Unity manual: interacting with browser scripting
- Godot docs: exporting for the Web
- Playgama Bridge docs
Related questions
Should I use CSS pixels or device pixels for game logic?
Keep game logic in a fixed internal coordinate space and scale it to fit the canvas; only the backing store (drawing buffer) needs devicePixelRatio for sharpness.
Why does my canvas look blurry on phones?
The backing store width/height is smaller than the CSS display size times devicePixelRatio, so the browser upscales the rendered image.
Last updated: 24 September 2026