Polyline与Path的差异:为何渲染后线条显示粗细不一致?
Great question! This comes down to how SVG renders strokes relative to the pixel grid, and the impact of anti-aliasing. Let’s break it down using your code:
First, here’s your original SVG for reference:
<svg xmlns="http://www.w3.org/2000/svg"> <polyline points="200 100, 220 120, 280 120, 300 100" style="stroke:red; stroke-width:2px; fill:none" /> <path d="M200 100 L220 150 H280 L300 100" style="stroke:blue;stroke-width:2px; fill:none" /> </svg>
The Core Issue: Pixel Alignment & Anti-Aliasing
SVG strokes are drawn along the centerline of the path. When you use an even stroke width (like 2px), if your path’s coordinates land exactly on integer pixel boundaries, the stroke’s centerline aligns with that boundary. This means the stroke extends 1px above and 1px below the centerline—right across the edge between two pixel rows.
Browsers use anti-aliasing to smooth these edges, which fills those partial pixels with a semi-transparent color. The result? The stroke looks visually thinner than its defined width.
In your case:
- The red
<polyline>’s horizontal segment sits aty=120(an integer coordinate). Its centerline aligns with the pixel boundary, triggering anti-aliasing and making it look thinner. - The blue
<path>’s horizontal segment is aty=150—while this is also an integer, the angle of the preceding line segment can subtly shift how the browser renders the stroke’s edge, but the root cause is still pixel alignment and anti-aliasing inconsistencies.
Fixes to Make Strokes Look Consistent
You have a few options to get both strokes looking the same thickness:
Shift coordinates to half-integers
Move your horizontal segments to a half-integer y-coordinate (like120.5or150.5). This places the stroke’s centerline directly in the middle of a pixel, so the 2px stroke fully covers two pixel rows with no partial pixels (and no anti-aliasing needed). Here’s the adjusted code:<svg xmlns="http://www.w3.org/2000/svg"> <polyline points="200 100, 220 120.5, 280 120.5, 300 100" style="stroke:red; stroke-width:2px; fill:none" /> <path d="M200 100 L220 150.5 H280 L300 100" style="stroke:blue;stroke-width:2px; fill:none" /> </svg>Disable anti-aliasing
Use theshape-rendering: crispEdgesCSS property to force the browser to render strokes along pixel boundaries without anti-aliasing. This makes strokes look sharper (though potentially less smooth at angles) and ensures consistent thickness:<svg xmlns="http://www.w3.org/2000/svg"> <polyline points="200 100, 220 120, 280 120, 300 100" style="stroke:red; stroke-width:2px; fill:none; shape-rendering:crispEdges" /> <path d="M200 100 L220 150 H280 L300 100" style="stroke:blue;stroke-width:2px; fill:none; shape-rendering:crispEdges" /> </svg>Use an odd stroke width
If you can adjust the stroke width, switching to an odd number (like 3px) automatically centers the stroke on a half-integer pixel position, avoiding the anti-aliasing issue entirely.
内容的提问来源于stack exchange,提问作者Jay

