Size of Html5 Canvas Via CSS Versus Element Attributes

Size of HTML5 Canvas via CSS versus element attributes

The explanation is here: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#attr-canvas-width as seen in another post, thanks!

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.

HTML5 get scaled canvas size

The canvas element has it own width and height attributes, so editing the width and height in css will only scale it but the canvas' attributes will remain the same. So to change the canvas size you will have to resize it by JavaScript with onresize function.

Canvas width and height in HTML5

The canvas DOM element has .height and .width properties that correspond to the height="…" and width="…" attributes. Set them to numeric values in JavaScript code to resize your canvas. For example:

var canvas = document.getElementsByTagName('canvas')[0];
canvas.width = 800;
canvas.height = 600;

Note that this clears the canvas, though you should follow with ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height); to handle those browsers that don't fully clear the canvas. You'll need to redraw of any content you wanted displayed after the size change.

Note further that the height and width are the logical canvas dimensions used for drawing and are different from the style.height and style.width CSS attributes. If you don't set the CSS attributes, the intrinsic size of the canvas will be used as its display size; if you do set the CSS attributes, and they differ from the canvas dimensions, your content will be scaled in the browser. For example:

// Make a canvas that has a blurry pixelated zoom-in
// with each canvas pixel drawn showing as roughly 2x2 on screen
canvas.width = 400;
canvas.height = 300;
canvas.style.width = '800px';
canvas.style.height = '600px';

See this live example of a canvas that is zoomed in by 4x.

var c = document.getElementsByTagName('canvas')[0];var ctx = c.getContext('2d');ctx.lineWidth   = 1;ctx.strokeStyle = '#f00';ctx.fillStyle   = '#eff';
ctx.fillRect( 10.5, 10.5, 20, 20 );ctx.strokeRect( 10.5, 10.5, 20, 20 );ctx.fillRect( 40, 10.5, 20, 20 );ctx.strokeRect( 40, 10.5, 20, 20 );ctx.fillRect( 70, 10, 20, 20 );ctx.strokeRect( 70, 10, 20, 20 );
ctx.strokeStyle = '#fff';ctx.strokeRect( 10.5, 10.5, 20, 20 );ctx.strokeRect( 40, 10.5, 20, 20 );ctx.strokeRect( 70, 10, 20, 20 );
body { background:#eee; margin:1em; text-align:center }canvas { background:#fff; border:1px solid #ccc; width:400px; height:160px }
<canvas width="100" height="40"></canvas><p>Showing that re-drawing the same antialiased lines does not obliterate old antialiased lines.</p>

Is canvas scaling more performant via CSS or JS?

This is unclear. Should I make the canvas as small as possible, then scale with CSS, or set the larger canvas dimensions from the canvas.width and canvas.height attributes (and "not scale the canvas" at all?)

Yes and no, it means scaling an element (canvas or any other) is faster using transforms (ie. transformation matrix) than using CSS width and height on the element, as transforms uses the available GPU. Plus:

Everything goes through transform matrices anyways (unless optimized not to when a identity matrix is encountered). Layout properties such as width and height etc. triggers layout reflow. Transforms can usually skip to paint and composition.

Example: As you can see here, the second div has transforms applied but does nothing to layout (the ghost space for the div is still there):

div {  width:100px;padding:100px 0 0 0;margin:0 5px;  display:inline-block;background:#7f9;border:2px solid #000  }
div:nth-child(2) { transform:scale(1.5) translate(30px, 30px)}
<div></div><div></div><div></div><div></div>

HTML5: Canvas width and height

Yes, those units are always in pixels and applies to the bitmap the canvas element uses. However, if there is no size defined on the element using CSS (ie. style attribute or using a style sheet) the element will automatically adopt to the size of its bitmap.

There is no other way of setting the size of the bitmap than by number of pixels. Using CSS will only change the size of the element itself, not the bitmap, stretching whatever is drawn to the bitmap to fit the element.

To use other units you will have to manually calculate these using JavaScript, for example:

// using % of viewport for canvas bitmap (pixel ratio not considered)
var canvas = document.getElementById("myCanvas"),
vwWidth = window.innerWidth,
vwHeight = window.innerHeight,
percent = 60;

canvas.width = Math.round(vwWidth * percent / 100); // integer pixels
canvas.height = Math.round(vwHeight * percent / 100);

// not to be confused with the style property which affects CSS, ie:
// canvas.style.width = "60%"; // CSS only, does not affect bitmap

If you want to support retina then you need to use the window.devicePixelRatio and multiply it with the sizes. In this case CSS would be necessary as well (combine with code above):

var pxRatio = window.devicePixelRatio || 1,
width = Math.round(vwWidth * percent / 100),
height = Math.round(vwHeight * percent / 100);

canvas.width = width * pxRatio;
canvas.height = height * pxRatio;

canvas.style.width = width + "px";
canvas.style.height = height + "px";

Difference between HTML width attribute and CSS width property (canvas)?

According to the relevant spec:

4.8.11 The canvas element — HTML5

The canvas element has two attributes to control the size of the coordinate space: width and height. These attributes, when specified, must have values that are valid non-negative integers. The rules for parsing non-negative integers must be used to obtain their numeric values. If an attribute is missing, or if parsing its value returns an error, then the default value must be used instead. The width attribute defaults to 300, and the height attribute defaults to 150.

Emphasis added.

In your case, since the first element, #trail, doesn't have a width or height attribute, the attribute values default to width="300" height="150", which is why you're seeing a difference.

In essence, the width/height attributes set the intrinsic dimensions of the canvas's coordinate space, whereas the CSS properties set the actual size of the canvas element:

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.

Therefore if you gave the canvas element the attributes width="100" height="100", then set a CSS width of 100%, the image would be scaled to fit the layout while maintaining the aspect ratio (example).

Canvas is stretched when using CSS but normal with width / height properties

It seems that the width and height attributes determine the width or height of the canvas’s coordinate system, whereas the CSS properties just determine the size of the box in which it will be shown.

This is explained in the HTML specification:

The canvas element has two attributes to control the size of the element’s bitmap: width and height. These attributes, when specified, must have values that are valid non-negative integers. The rules for parsing non-negative integers must be used to obtain their numeric values. If an attribute is missing, or if parsing its value returns an error, then the default value must be used instead. The width attribute defaults to 300, and the height attribute defaults to 150.



Related Topics



Leave a reply



Submit