19

I'm creating a line with SVG and it is appearing blurry in my web page. To be more clear, it appears larger than the stroke width of 1px. Why is this happening and is there a way to fix it in SVG?

Here is the code. When I run this code by itself it is not blurry. When it's in my web page the line appears to be about 2px in height rather than 1.

#HorizontalLine1178  {
 stroke:rgb(154,154,154);
 stroke-width:1;
}
<svg style="width:100%;">
    <line id="HorizontalLine1178" y2="97" y1="97" x2="100%" x1="62" >
</svg>
1.21 gigawatts
  • 14,347
  • 30
  • 103
  • 209
  • 1
    Possible duplicate of [Avoiding lines between adjecent svg rectangles](http://stackoverflow.com/questions/23376308/avoiding-lines-between-adjecent-svg-rectangles) – Paul LeBeau Dec 11 '15 at 17:55
  • @PaulLeBeau I've updated the post. myf's answer includes new additional information not in the other post. – 1.21 gigawatts Dec 11 '15 at 19:08
  • To give credit where it is due, Pauls comment in his answers mentions it as well; it is possible I even learned that from him back then: https://stackoverflow.com/questions/23376308/avoiding-lines-between-adjecent-svg-rectangles#comment56203656_23376793 – myf Jul 12 '17 at 12:03

1 Answers1

35

Because when its Y coordinates lies on whole pixel, the 1px stroke is around it and thus "antialiased" (refer to Paul LeBeau's excellent illustration). Use half pixel coordinates in this case, or apply shape-rendering="crispEdges" that will do the pixel rounding for you, but will produce sharp edges even on rounded objects:

<svg style="width:100%; background-color: white" stroke="black" fill="white" stroke-width="1">
 <line y2="10.0" y1="10.0" x2="90%" x1="10">
  <title>.0</title>
 </line>
 <line y2="15.5" y1="15.5" x2="90%" x1="10">
  <title>.5</title>
 </line>
 <line y2="20.0" y1="20.0" x2="90%" x1="10" shape-rendering="crispEdges">
  <title>.0 + crispEdges</title>
 </line>

 <circle cy="50" cx="20" r="10">
  <title>.0</title>
 </circle>
 <circle cy="49.5" cx="44.5" r="10">
  <title>.5</title>
 </circle>
 <circle cy="50" cx="70" r="10" shape-rendering="crispEdges">
  <title>.0 + crispEdges</title>
 </circle>

 <rect x="90" y="40" width="20" height="20">
  <title>.0</title>
 </rect>
 <rect x="120" y="40" width="20" height="20" shape-rendering="crispEdges">
  <title>.0 + crispEdges</title>
 </rect>
 <rect x="149.5" y="39.5" width="20" height="20">
  <title>.5</title>
 </rect>

 <rect x="190" y="40" width="20" height="20" stroke="none" fill="black">
  <title>.0 + fill, no stroke</title>
 </rect>
 <rect x="219.5" y="39.5" width="20" height="20" stroke="none" fill="black">
  <title>.5 + fill, no stroke</title>
 </rect>
</svg>
myf
  • 7,711
  • 2
  • 34
  • 44
  • Great examples. So if I know ahead of time that a stroke is 1px in height (horizontal line) and the vertical position is an odd number, "81" not "80" than I should change that y position to "81.5" to keep the line 1px in height? – 1.21 gigawatts Dec 11 '15 at 18:25
  • DIdn't see your update. The crispEdges setting looks great. Why did you put Line to not have a fill? Do they have a fill by default? – 1.21 gigawatts Dec 11 '15 at 18:31
  • Not odd/even: for *strokes* keep in mind that they are rendered *around* lines connecting given coordinates, and that whole coordinates denotes pixel boundaries. See Pauls answer in linked question, it describes it better. Ad `fill` for line: no, just smashed it into selector to affect `rect`s. – myf Dec 11 '15 at 18:34
  • *Whole-pixel* coordinates are otherwise good for strokeless filled shapes (see the last square in example). – myf Dec 11 '15 at 18:36
  • An update. For some cases, the line disappears when using crispEdges at 1px in height on Firefox? or WebKit?. It's been a while since it happened so if I encounter the code that caused it and browser I'll post it back to this question. – 1.21 gigawatts Jun 15 '17 at 17:26
  • 2
    If you are like me and LOVE this answer -- but you are saying to yourself, _"Hey, that's sure a LOT of extra characters in my SVG and I am trying to keep things small!"_ -- then try placing this just after your opening `` tag and remember to close it just before ``: ``. Works for every object that way and really improved my work. – Geek Stocks Jul 12 '17 at 10:26
  • Yup, this is useful remark in general - properties inheritance to descendant nodes. In fact you don't even need a group: if you know you *entire* SVG should be "pixelated", you can just use `` – myf Jul 12 '17 at 11:58
  • Spent some more time on this so adding notes: All of this might make more sense if you understand the stroke is drawn after the fill and that in SVG in the browser the stroke is drawn on the edge of the shape. In some software you can specify that a stroke is drawn around the outside of the shape, centered on the edge of the shape or inside the shape. So when you a have an odd width stroke that is centered on the edge it causes that anti aliasing. If there was a way to draw the stroke inside or outside the edge you would be able to get rid of aliasing when using whole number coordinates. – 1.21 gigawatts Jul 12 '17 at 18:08