Kilian Valkhof

Building tools that make developers awesome.

The problem with SVG and Canvas

Design, 25 January 2010, 2 minute read

SVG and canvas are awesome technologies, and are changing the way we use graphics on the web. I love working with both, and support for both keeps improving (IE9 might even support SVG!) However, they have one problem that is really getting to me, and it’s not even their fault.


You see, SVG and Canvas are based on vectors. This means that they don’t really care about the pixels they get drawn on, their graphic implementation takes care of that. And thats a problem. This is the code to draw a 1px line in canvas:

var canvas1, context1;
    canvas1 = document.getElementById("canvas1");
    canvas1.height = 20;
    canvas1.width = 560;
    context1 = canvas1.getContext("2d");
    context1.strokeStyle = '#000000';

    // draw

As you can see, that line is blurry. I don’t want my lines to be blurry. Luckily there is an easy fix:


Just offset with half a pixel, and it’ll render nice and sharp. This works, because in SVG and in Canvas, pixels aren’t seen as an indivisible unit. You can draw on a part of a pixel.

When you code a line to start at a certain pixel, you are actually starting the line in the top-left corner of that pixel. When that line is 1px wide, half a the line gets drawn on one pixel, and the other half on the one next to it, resulting in a blurry line.

As I said, this is’t really SVG or Canvas’ fault. SVG and Canvas should not care about pixels, because they work in vectors. The lines are blurry by design. However, the last thing a canvas or SVG developer should want is code littered with +0.5 and currently, this is exactly what happens.

What I want

I don’t want to have to write +0.5 all throughout my canvas or SVG generating code. I want the canvas or SVG implementation to be smart enough to know when that line is going to be unintentionally blurry, and make sure it’s not. Now, an implementation might not be able to determine this, I don’t know.

At the very least, give developers a global option to switch between the two “modes” (one being theoretically correct, the other giving sharp lines). Call it alignToRaster (a boolean, as a property of the canvas, defaults to false) and if set to true, silently add the 0.5px for me.

Polypane browser for responsive web development and design Hi, I'm Kilian. I make Polypane, the browser for responsive web development and design. If you're reading this site, that's probably interesting to you. Try it out!

  1. Oh, and canvas, setting a color of a line with strokeStyle, but a width with lineWidth? Shame. On. You.

  2. For svg you can try the following:

    – on the root svg element adjust the ‘viewBox’ attribute until you get the desired result for lines/rects in the svg (similar to adding 0.5px everywhere, but in one place instead of many).
    – use ‘shape-rendering: optimizeSpeed’ to disable anti-aliasing on any (or some) elements. Since it’s a CSS property you can easily write a selector that applies it only to the elements you want.

  3. thanks for the usefull post, a pixel based canvas should exist :)

  4. Erik’s suggestions are good. You can also set shape rendering to ‘crispEdges’. It’s annoying to have to do this; it might become the default behavior of Raphaël.js. See this issue:

  5. Pixels can’t be subdivided; they don’t have any area. Seems like yet another problem caused by the misconception that pixels have dimensions. In this case I hope it’s the browser developers, since it can be fixed by hacking code; if this is how SVG defines a conforming implementation then we need some serious reworking in the standard.

  6. What about context.translate(0.5, 0.5)?

  7. The problem arises from unpersicion float numbers in computation. it’s so common in all programming languages.

  8. Mike

    Thank you. This solved a giga-huge headache I was having.