I've created a few svg-based icons for a small website I'm working on but I'm having trouble getting the stroke to look how I'd like. If you look at this jsfiddle you can see my issue. The stroke for the outer <rect>
is 1px all the way around but for some reason the right and bottom sides of that outer square seem to have a thicker stroke than the top and left sides, sort of like a drop shadow effect.
I was thinking that maybe the browser renderer was maybe evaluating the stroke as not being a whole number and was rounding down for the left and top edges and rounding up for the right and bottom edges (like happens in a lot of rasterization problems) but no matter where I move it around the page, it is only ever the right and bottom edges.
Can somebody tell me what is going on here and how to fix it?
Thanks in advance.
What you encounter is indeed a case of surprising sub-pixel rendering. You see, SVG strokes are applied exactly on the path where they are specified. Example: If a path runs from the point (0,0) to (0,5) and is assigned a 1px wide stroke, the stroke covers the rectangle (-0.5,0), (0.5,0), (0.5,5), (-0.5,5). The first one of these images illustrates this:
Your rectangle is drawn from (0,0) (the default position) to (36,36). Therefore the stroke is placed in such a way, that it lies exactly between the screen pixels. That’s the reason for the right and bottom edges to look blurry.
What’s up with the top and left edges? Well, since you didn’t define a size for your SVG image, the browser determined one for you. The default is to start at (0,0) (top-left corner) and make the SVG 300x150 pixels wide.
Since the top and left edges of the rectangle outline are directly on the edge of the image, they still are drawn blurry, but you don’t see the part outside the image. Hence it appears to be a sharp line, but if you look closely, you notice, that it is not fully black, but half transparent.
How to fix this? There are two options. Option 1 is to place the rectangular on half pixels:
<rect x="0.5" y="0.5" .../>
The other option is to move the viewport of your image around, so that the image as a whole is shifted for half a pixel:
<svg viewBox="-0.5 -0.5 37 37">
Note, that I’ve set width and height of the viewport to 37px. That’s because your rectangle will have a final size of 37px: 36px for the outline, and then 0.5px on every side, where the outer half of the 1px stroke rests.
For a general overview on scaling SVGs I suggest this post on CSS Tricks.