163

I am trying to create a canvas element that takes up 100% of the width and height of the viewport.

You can see in my example here that is occurring, however it is adding scroll bars in both Chrome and FireFox. How can I prevent the extra scroll bars and just provide exactly the width and height of the window to be the size of the canvas?

aherrick
  • 18,488
  • 29
  • 100
  • 168

7 Answers7

282

In order to make the canvas full screen width and height always, meaning even when the browser is resized, you need to run your draw loop within a function that resizes the canvas to the window.innerHeight and window.innerWidth.

Example: http://jsfiddle.net/jaredwilli/qFuDr/

HTML

<canvas id="canvas"></canvas>

JavaScript

(function() {
    var canvas = document.getElementById('canvas'),
            context = canvas.getContext('2d');

    // resize the canvas to fill browser window dynamically
    window.addEventListener('resize', resizeCanvas, false);

    function resizeCanvas() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;

            /**
             * Your drawings need to be inside this function otherwise they will be reset when 
             * you resize the browser window and the canvas goes will be cleared.
             */
            drawStuff(); 
    }
    resizeCanvas();

    function drawStuff() {
            // do your drawing stuff here
    }
})();

CSS

* { margin:0; padding:0; } /* to remove the top and left whitespace */

html, body { width:100%; height:100%; } /* just to be sure these are full screen*/

canvas { display:block; } /* To remove the scrollbars */

That is how you properly make the canvas full width and height of the browser. You just have to put all the code for drawing to the canvas in the drawStuff() function.

jaredwilli
  • 10,288
  • 5
  • 39
  • 40
  • 2
    Why is it necessary to remove the padding and set width, height to 100%? – Kos Jan 22 '13 at 17:07
  • 3
    I believe it is mainly for overriding the user stylesheet which the browser has defaults for. If you are using some kind of normalize or reset css file, this isn't necessary since that will be taken care of already. – jaredwilli May 24 '13 at 15:16
  • 2
    If you expect quite a lot of resizing; on a portrait/landscape device for instance, you'd want to ```debounce``` the resize otherwise you'll flood the browser. – dooburt Apr 08 '14 at 08:07
  • 25
    `display: block`: Not only does this remove scrollbars, but it removes 2px from the document body's height, that are normally added under text lines inside a block. So +1 for that – Neptilo Dec 18 '14 at 13:41
  • 4
    plus one for no jQuery – Félix Gagnon-Grenier Oct 06 '16 at 19:00
  • This is arguably the wrong solution because it's hardcoded and inflexible. [See examples here](http://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html) – gman Oct 14 '16 at 23:10
  • Hi what does this declaration of a function mean: `(function() {` function inside a function? – utdev Mar 28 '17 at 13:58
  • Do you really need useCapture = false? – SuperUberDuper Apr 04 '17 at 17:19
  • If you use jQuery, use `$('#canvas') instead of `document.getElementById('canvas')` because the first one prevents NULL calls (error in console). – Roland Nov 15 '19 at 13:45
  • This seems to work too: canvas.height = canvas.parentNode.clientHeight; canvas.width = canvas.parentNode.clientWidth; – Kim T Jan 04 '20 at 00:59
  • @jaredwilli thanks, from a Swift programer, for the wonderful answer! cheers bra – Fattie Jan 25 '21 at 17:35
28

You can try viewport units (CSS3):

canvas { 
  height: 100vh; 
  width: 100vw; 
  display: block;
}
Vitalii Fedorenko
  • 97,155
  • 26
  • 144
  • 111
  • 5
    Add `display: block;` and it does the job. – superlukas Aug 20 '14 at 12:40
  • 19
    I tried this and found that in Chrome and Firefox, the canvas simply shows the image stretched to the full viewport. Even newly drawn elements are stretched, as well. – Vivian River Aug 21 '14 at 03:03
  • 9
    @Daniel is right - this answer is *wrong*. It won't set the internal dimension of the canvas context, but rather the dimensions of the DOM element. For the difference, see [my answer to a related question](http://stackoverflow.com/questions/4032179/how-do-i-get-the-width-and-height-of-a-html5-canvas/31195651#31195651). – Dan Dascalescu Jul 03 '15 at 02:32
  • 23
    **This method does not work, it stretches the text. You unfortunately** ***have*** **to use JS.** – i336_ May 10 '16 at 01:56
  • There are cases where you want to stretch (i.e. progress bar). Thanks, great for my case! – Andrew McOlash Oct 14 '20 at 06:59
16

I'll answer the more general question of how to have a canvas dynamically adapt in size upon window resize. The accepted answer appropriately handles the case where width and height are both supposed to be 100%, which is what was asked for, but which also will change the aspect ratio of the canvas. Many users will want the canvas to resize on window resize, but while keeping the aspect ratio untouched. It's not the exact question, but it "fits in", just putting the question into a slightly more general context.

The window will have some aspect ratio (width / height), and so will the canvas object. How you want these two aspect ratios to relate to each other is one thing you'll have to be clear about, there is no "one size fits all" answer to that question - I'll go through some common cases of what you might want.

Most important thing you have to be clear about: the html canvas object has a width attribute and a height attribute; and then, the css of the same object also has a width and a height attribute. Those two widths and heights are different, both are useful for different things.

Changing the width and height attributes is one method with which you can always change the size of your canvas, but then you'll have to repaint everything, which will take time and is not always necessary, because some amount of size change you can accomplish via the css attributes, in which case you do not redraw the canvas.

I see 4 cases of what you might want to happen on window resize (all starting with a full screen canvas)

1: you want the width to remain 100%, and you want the aspect ratio to stay as it was. In that case, you do not need to redraw the canvas; you don't even need a window resize handler. All you need is

$(ctx.canvas).css("width", "100%");

where ctx is your canvas context. fiddle: resizeByWidth

2: you want width and height to both stay 100%, and you want the resulting change in aspect ratio to have the effect of a stretched-out image. Now, you still don't need to redraw the canvas, but you need a window resize handler. In the handler, you do

$(ctx.canvas).css("height", window.innerHeight);

fiddle: messWithAspectratio

3: you want width and height to both stay 100%, but the answer to the change in aspect ratio is something different from stretching the image. Then you need to redraw, and do it the way that is outlined in the accepted answer.

fiddle: redraw

4: you want the width and height to be 100% on page load, but stay constant thereafter (no reaction to window resize.

fiddle: fixed

All fiddles have identical code, except for line 63 where the mode is set. You can also copy the fiddle code to run on your local machine, in which case you can select the mode via a querystring argument, as ?mode=redraw

mathheadinclouds
  • 2,737
  • 1
  • 22
  • 30
  • 1
    fyi: `$(ctx.canvas).css("width", "100%");` is equivalent to `$(canvas).css("width", "100%");` (the context's canvas is just the canvas) – Brad Kent Jan 24 '17 at 15:59
  • @BradKent when you call a helper function which does the "canvas-things" you want done, you can either, as argument(s) 1) pass the canvas object, 2) pass the canvas context, 3) both. I don't like 3), and `ctx.canvas` is a lot shorter than `canvas.getContext('2d')` - that's why I do 2). Hence, there is no variable called canvas, but there is ctx.canvas. That's where ctx.canvas comes from. – mathheadinclouds Dec 06 '19 at 05:55
9

I was looking to find the answer to this question too, but the accepted answer was breaking for me. Apparently using window.innerWidth isn't portable. It does work in some browsers, but I noticed Firefox didn't like it.

Gregg Tavares posted a great resource here that addresses this issue directly: http://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html (See anti-pattern #'s 3 and 4).

Using canvas.clientWidth instead of window.innerWidth seems to work nicely.

Here's Gregg's suggested render loop:

function resize() {
  var width = gl.canvas.clientWidth;
  var height = gl.canvas.clientHeight;
  if (gl.canvas.width != width ||
      gl.canvas.height != height) {
     gl.canvas.width = width;
     gl.canvas.height = height;
     return true;
  }
  return false;
}

var needToRender = true;  // draw at least once
function checkRender() {
   if (resize() || needToRender) {
     needToRender = false;
     drawStuff();
   }
   requestAnimationFrame(checkRender);
}
checkRender();
David
  • 608
  • 7
  • 12
9

http://jsfiddle.net/mqFdk/10/

<!DOCTYPE html>
<html>
<head>
    <title>aj</title>
</head>
<body>

    <canvas id="c"></canvas>

</body>
</html>

with CSS

body { 
       margin: 0; 
       padding: 0
     }
#c { 
     position: absolute; 
     width: 100%; 
     height: 100%; 
     overflow: hidden
   }
Marc Audet
  • 42,628
  • 10
  • 57
  • 78
nonopolarity
  • 130,775
  • 117
  • 415
  • 675
  • This works, but it leaves my canvas without a defined width and height. The canvas width and height must be defined on the element I believe. – aherrick Nov 26 '10 at 22:49
  • @aherrick: No, you do not have to have an explicit width/height set on the canvas element for it to work. This code should work fine. – Jon Adams Sep 13 '11 at 14:04
  • 19
    Actually yes, canvas elements do need an explicit width/height set. Without it they default to some browser pre-set (in chrome, I think it's 300x150px) size. All drawing to the canvas gets interpreted at this size and then scaled to 100% of the viewport size. Try drawing ___anything___ in your canvas to see what I mean -- it'll be distorted. – Mark Kahn Dec 13 '11 at 08:46
  • if you're trying to make the canvas 100% width and height then that doesnt even matter at all. you just resize it anyways – jaredwilli Jan 21 '12 at 12:58
  • 2
    The intrinsic dimensions of the canvas element equal the size of the coordinate space, with the numbers interpreted in CSS pixels. However, the element can be sized arbitrarily by a style sheet. During rendering, the image is scaled to fit this layout size. – jaredwilli Jan 21 '12 at 13:05
  • Answer including needed resize logic: http://stackoverflow.com/questions/4288253/html5-canvas-100-width-height-of-viewport/18215701#18215701 – Vincent Scheib Aug 14 '13 at 14:22
2

(Expanding upon 動靜能量's answer)

Style the canvas to fill the body. When rendering to the canvas take its size into account.

http://jsfiddle.net/mqFdk/356/

<!DOCTYPE html>
<html>
<head>
    <title>aj</title>
</head>
<body>

    <canvas id="c"></canvas>

</body>
</html>

CSS:

body { 
       margin: 0; 
       padding: 0
     }
#c { 
     position: absolute; 
     width: 100%; 
     height: 100%; 
     overflow: hidden
   }

Javascript:

function redraw() {
    var cc = c.getContext("2d");
    c.width = c.clientWidth;
    c.height = c.clientHeight;
    cc.scale(c.width, c.height);

    // Draw a circle filling the canvas.
    cc.beginPath();
    cc.arc(0.5, 0.5, .5, 0, 2*Math.PI);
    cc.fill();
}

// update on any window size change.
window.addEventListener("resize", redraw);

// first draw
redraw();
Vincent Scheib
  • 13,630
  • 7
  • 56
  • 74
1

For mobiles, it’s better to use it

canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;

because it will display incorrectly after changing the orientation.The “viewport” will be increased when changing the orientation to portrait.See full example

dzanis
  • 409
  • 5
  • 6