element.requestFullscreen() fills the screen with any element, but only from a user gesture. document.fullscreenElement names it, document.exitFullscreen() leaves, and fullscreenchange fires both ways: resize the bitmap there. The API is not Baseline, since iPhone Safari 10 offers full screen for video only.
<button id="full">Full screen</button>
<canvas id="designer" style="width:600px; height:190px"></canvas>
<script src="hidpi.js"></script>
<script>
full.onclick = () => designer.requestFullscreen(); // Esc also leaves
designer.ondblclick = () => document.fullscreenElement && document.exitFullscreen();
document.addEventListener('fullscreenchange', () => {
hidpi(designer); // new size, new bitmap; then redraw
const shown = document.fullscreenElement?.id ?? 'page';
console.log(`${shown}: ${designer.width} x ${designer.height}`);
});
designer.requestFullscreen().catch(e => console.log(`on load: ${e.name}: ${e.message}`));
</script>Output
on load: TypeError: Permissions check failed designer: 1600 x 1200 page: 1200 x 380
In headless Chrome 154 1 (800 x 600, ratio 2) the request on load was refused, a click entered full screen and a double-click left. CSS styles that state with :fullscreen.
<!doctype html>
<style>
body { margin: 0; padding: 8px; font: 13px system-ui, sans-serif; background: #fafaf7; }
#designer { width: 600px; max-width: 100%; height: 200px; display: block; background: #fff; border: 1px solid #ddd; }
#designer:fullscreen { width: 100vw; height: 100vh; max-width: none; border: 0; }
</style>
<button id="full">Full screen</button>
<canvas id="designer"></canvas>
<p id="status"></p>
<script>
function hidpi(c, r = devicePixelRatio) {
c.width = c.clientWidth * r; c.height = c.clientHeight * r;
const ctx = c.getContext('2d'); ctx.scale(r, r); return ctx;
}
const designer = document.getElementById('designer');
const status = document.getElementById('status');
// Redraw the shelf to fit whatever size the canvas has now
function draw() {
const ctx = hidpi(designer), w = designer.clientWidth, h = designer.clientHeight;
const colors = ['#1f5f8b', '#5b3f99', '#e09a10', '#3f7d3a', '#b5452f', '#2a9d8f'];
const bw = w / 8, bh = h * 0.7;
ctx.fillStyle = '#8d6e63'; ctx.fillRect(0, h * 0.85, w, h * 0.06); // the shelf
colors.forEach((color, i) => {
ctx.fillStyle = color;
ctx.fillRect(bw * (i + 1), h * 0.85 - bh * (0.8 + 0.2 * Math.sin(i * 2)), bw * 0.8, bh * (0.8 + 0.2 * Math.sin(i * 2)));
});
ctx.fillStyle = '#263238'; ctx.font = `${Math.round(h / 12)}px sans-serif`;
ctx.fillText(`${designer.width} × ${designer.height} bitmap pixels`, 10, h / 10);
}
// requestFullscreen() works only from a user gesture (and in frames allowed to use it)
document.getElementById('full').onclick = () => {
designer.requestFullscreen()
.catch(e => status.textContent = `Refused: ${e.name}. Embedded frames need allow="fullscreen".`);
};
designer.ondblclick = () => document.fullscreenElement && document.exitFullscreen();
// fullscreenchange fires on entering and leaving: resize the bitmap and redraw
document.addEventListener('fullscreenchange', () => {
draw();
status.textContent = document.fullscreenElement ? 'In full screen: double-click or Esc to leave' : 'Back on the page';
});
draw();
status.textContent = document.fullscreenEnabled
? 'Click the button to enter full screen.'
: 'Full screen is disabled in this frame (fullscreenEnabled is false).';
</script>