How SVG Non-Scaling-Stroke Maintains Line Width

This article explains how the vector-effect="non-scaling-stroke" property functions in Scalable Vector Graphics (SVG) to maintain consistent line thicknesses. By default, geometric transformations that scale an SVG element will also scale its stroke width proportionally. Applying non-scaling-stroke overrides this behavior, ensuring that lines retain their exact defined pixel or unit width regardless of element scaling, coordinate transformations, or user zoom interactions.

The Default Scaling Problem in SVG

In standard SVG rendering, elements exist within a user coordinate system. When a transformation—such as a transform="scale(...)", a changing viewBox, or a responsive container resize—is applied to an SVG shape, the coordinate space itself expands or contracts.

Because stroke thickness is defined within this local coordinate system, it scales directly with the geometry. For example, a path with stroke-width="2" inside an SVG that is scaled up by a factor of 4 will visually render with an effective stroke width of 8 pixels. While this is mathematically correct for proportional vector scaling, it is often undesirable for user interface icons, responsive borders, and interactive mapping systems.

How non-scaling-stroke Works Internally

The vector-effect attribute modifies how the SVG rendering engine calculates stroke geometry relative to the Current Transformation Matrix (CTM).

When vector-effect="non-scaling-stroke" is declared on an SVG element:

  1. Geometry Transformation: The shape’s underlying path, vertices, and fill boundaries are transformed according to the local matrix and parent transformations as usual.
  2. Stroke Decoupling: Before rasterizing the outline, the rendering engine decouples the stroke width from the local coordinate space. It references the host viewport coordinate system (device space) rather than the local user space.
  3. Inverse Transformation: Mathematically, the renderer calculates the scale component of the combined transformation matrix and applies its inverse to the stroke width. If the shape is scaled by \(S_x\) and \(S_y\), the stroke width is adjusted by \(1 / S\) before rendering.
  4. Final Rasterization: The stroke is drawn along the transformed path using the original, unscaled measurement defined in the stroke-width attribute.

As a result, zooming into the graphic makes the shapes larger, but the borders and paths remain sharp, crisp, and visually identical in thickness.

Implementation Methods

The non-scaling behavior can be applied directly within the SVG markup or through CSS.

SVG Attribute

<svg viewBox="0 0 100 100" width="400" height="400">
  <circle cx="50" cy="50" r="40" 
          stroke="black" 
          stroke-width="2" 
          fill="none" 
          vector-effect="non-scaling-stroke" />
</svg>

CSS Property

.uniform-stroke {
  vector-effect: non-scaling-stroke;
}
<path class="uniform-stroke" d="M10 10 H 90 V 90 H 10 Z" stroke="blue" stroke-width="1.5" />

Primary Use Cases