Relative units

Just like HTML/CSS, SVG supports relative units. In fact, SVG 2 supports the same units HTML/CSS does. So the logic can overlap between SVG and HTML.

And while absolute units (like mm) are pretty simple - just a multiplication factor based on the DPI, relative require a much more complex logic.

Percent units

While percent units may look simple, after all, % can be treated just as a factor (e.g. 200% is the same as 2x). But in reality, they are quite complicated. And mainly because of the base value they are relative to.

Let's take opacity for example: opacity="50%". What is it relative to? Technically, to itself. Or more specifically to 1. So 50% equals 0.5 and 100% equals 1. And values outside the 0..1 range are clamped.

What about the rectangle's width? It's relative to the parent SVG element's viewBox (parent, not the root one, and viewBox, not width/height). So in the case of:

<svg width="100" viewBox="0 0 50 50">
    <rect width="50%" height="20"/>
</svg>

our width is 25.

And it gets weirder since a use element can enforce the svg viewbox as well when no viewBox was set. So in the case of:

<svg id="svg1" width="100">
    <rect width="50%" height="20"/>
</svg>
<use xlink:href="#svg1" width="50">

our width is again 25. Because we have to use the width from the use element. You can find more about it in the use to svg size resolving chapter.


What about stroke-width? Well, it's relative to the diagonal length of the current viewbox. Aka sqrt((width^2 + height^2) / 2). So in the case of:

<svg viewBox="0 0 50 25">
    <rect stroke-width="50%"/>
</svg>

it will be sqrt((50^2 + 25^2) / 2) = 39.5.


What about font-size? It's relative to the parent font-size. So in the case of:

<g font-size="20">
    <text font-size="50%"/>
</g>

our font size is 10.

Font units

font-size and font units (em and ex) make our lives even worse.

First, font-size can have named values, like larger or medium. It can also have percent units, which are relative to the parent font-size and not the current viewbox.

Second, font relative units have to be resolved from the root element to the current one and not the other way around, like with other relative units. So in the case of:

<svg>
    <g font-size="20">
        <g font-size="200%">
            <g font-size="larger">
                <rect width="0.5em" height="0.5ex"/>
            </g>
        </g>
    </g>
</svg>

our width and height are 24 and 12 respectively. Why? Because of the following steps (from top to bottom):

  • 20
  • 20 * 200% = 40
  • 40 * 1.2 = 48 (larger has a scaling factor of 1.2, don't ask why...)
  • width: 48 * 0.5 = 24
  • height: (48 * 0.5) / 2 = 12