Search code examples
svg

Why is my SVG line blurry or 2px in height when I specified 1px?


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>


Solution

  • Because when its Y coordinates lies on whole pixel, the 1px stroke is around it and thus "anti-aliased" (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>

    Heavily up-scaled screenshot of above snippet made on screen with 1:1 DPI ratio, without zoom (where 1 virtual CSS pixel = 1 physical screen pixel):

    From top-left to bottom-right: 1: Wide blurry line; 2, 3: two thin sharp lines; 4, 5: two reasonably smooth circles; 6: overly sharp circle; 7: blurry square; 8, 9: two sharp squares second slightly shifted up); 10: sharp filled square; 11: blurry filled square

    With different DPI settings or zoom values you can get different results, depending on where given coordinate ends after adjustments.