Responsive svg with percentage and pixel values

Viewed 1944

I can create a svg with line at any given percentage "0%-100%" so that the rounded borders (in pixels) are not included in the "percentage width" with the help of calc calc(100% - 25px)

<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="50">
<rect fill="lightblue" y="0" x="0" width="100%" height="50" rx="25" ry="25"></rect>
<g class="percentage">
    <line class="100pct" x1="calc(100% - 25px)" x2="calc(100% - 25px)" y1="0" y2="50" stroke="red" stroke-width="4"></line>
</g>
</svg>

But the question is, can this same svg be created without calc for legacy browsers?

I can use transform and translate to take one rounded side into account, but I can't figure out how to limit the width / add some kind of margin.

The percentage change, so one shared translate gets me only halfway there, here the red 100% line is out of bounds:

<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="50">
<rect fill="lightblue" y="0" x="0" width="100%" height="50" rx="25" ry="25"></rect>
<g class="percentage" transform="translate(25, 0)">
    <line class="0pct" x1="0%" x2="0%" y1="0" y2="50"  stroke="blue" stroke-width="4"></line>
    <line class="100pct" x1="100%" x2="100%" y1="0" y2="50" stroke="red" stroke-width="4"></line>
</g>
</svg>

1 Answers

Is there really any browser supporting the above syntax? If yes, it is in violation of even the SVG2 spec:

A future specification may convert the ‘x1’, ‘y1’, ‘x2’, and ‘y2’ attributes to geometric properties. Currently, they can only be specified via element attributes, and not CSS.

(And since calc() is a CSS function, it can only be used in CSS contexts.)

What will work in all browsers supporting SVG is to combine x/y values with transforms; unitless = px values go to the transform attribute, units (percentages) go to the x/y attribute.

<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="50">
    <rect fill="lightblue" y="0" x="0" width="100%" height="50" rx="25" ry="25"></rect>
    <g class="percentage" >
        <line class="0pct" x1="100%" x2="100%" y1="0" y2="50" transform="translate(-25, 0)" stroke="red" stroke-width="4"></line>
    </g>
</svg>

In addition to the SVG 1.1 transform attribute, there is also the CSS transform property and its 2D functions which are implemented quite fairly (exeption: IE and Edge < 17). They must use unit identifiers, and should also support nested calc() functions. I have no compatibility data for that combination, but there are also no bug reports mentioned in caniuse.com.

What currently does not work is using the CSS transform syntax as a presentation attribute (CSS transform spec is not yet implemented in that regard), so you need to use them in style attributes.

<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="50">
    <rect fill="lightblue" y="0" x="0" width="100%" height="50" rx="25" ry="25"></rect>
    <g class="percentage" stroke="red" stroke-width="4" >
        <line class="0pct" x1="0" x2="0" y1="0" y2="50"
              style="transform:translate(calc(0 * (100% - 50px) + 25px))" />
        <line class="50pct" x1="0" x2="0" y1="0" y2="50"
              style="transform:translate(calc(0.5 * (100% - 50px) + 25px))" />
        <line class="100pct" x1="0" x2="0" y1="0" y2="50"
              style="transform:translate(calc(1 * (100% - 50px) + 25px))" />
    </g>
</svg>

As you can see, the positional value is no longer a percentage (multiplying pixels with percentages does not work), but a fraction of 1. I hope that works for you.

Related