Fixed stroke width in SVG

SvgVisualization

Svg Problem Overview


I would like to be able to set the stroke-width on an SVG element to be "pixel-aware", that is always be 1px wide regardless of the current scaling transformations applied. I am aware that this may well be impossible, since the whole point of SVG is to be pixel independent.

Context follows:

I have an SVG element with its viewBox and preserveAspectRatio attributes set. It looks something like this

<svg version="1.1" baseProfile="full"
    viewBox="-100 -100 200 200" preserveAspectRatio="xMidYMid meet"
    xmlns="http://www.w3.org/2000/svg" >
</svg>

This means that when I scale that element, the actual shapes inside it scale accordingly (so far so good).

As you can see, I have set up the viewBox so that the origin is in the center. I would like to draw an x- and a y-axis within that element, which I do thus:

<line x1="-1000" x2="1000" y1="0" y2="0" />

Again, this works fine. Ideally, though, this axis would always be only 1px wide. I have no interest in the axes getting fatter when i scale the parent svg element.

So am I screwed?

Svg Solutions


Solution 1 - Svg

You can use the vector-effect property set to non-scaling-stroke, see the docs. Another way is to use transform(ref).

That will work in browsers that support those parts from SVG Tiny 1.2, for example Opera 10. The fallback includes writing a small script to do the same, basically inverting the CTM and applying it on the elements that shouldn't scale.

If you want sharper lines you can also disable antialiasing (shape-rendering=optimizeSpeed or shape-rendering=crispEdges) and/or play with the positioning.

Solution 2 - Svg

Here is a more concise answer based on Erik's answer to help you get started quickly.

<div style="background: blue; width: 100%; height: 130px;">
            <svg xml:id="root" viewBox="0 0 100 100" width="100%" height="100%" preserveAspectRatio="none">
                <rect xml:id="r" vector-effect="non-scaling-stroke" x="0" y="0" width="100" height="100" fill="none" stroke="#88CE02"
                      stroke-linecap="square" stroke-width="10" stroke-miterlimit="30"/>
            </svg>
        </div>

Adding the vector-effect="non-scaling-stroke" to the SVG rect makes the border size (or stroke size) fixed.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionwxsView Question on Stackoverflow
Solution 1 - SvgErik DahlströmView Answer on Stackoverflow
Solution 2 - SvgsupersanView Answer on Stackoverflow