How to Resize SVG Keeping Inner Sizes

17 January 2025

How could it be possible to make an SVG image be rubber and resizable but keep some of its elements having the same size between each other?

I've been looking for a good solution for my Windows Calculator project. Initially, there was only a usual method to make SVG scalable using preserveAspectRatio="none" attribute. It makes the SVG content fill the whole canvas indeed, but it distorts the proportions of the elements.

Here you can see how it was looking while changing the SVGs sizes to fill the window frame:

As you can see, window frames haven't the same size. Some of them are squeezed while others are stretched. Not a good view as I think. The frame border should be the same width whatever window size is, while as the left inner space should be filled by a glass texture.

How to solve?

Unfortunately, SVG itself doesn't allow moving its child lower the top-left zero coordinate for some value, and then use the same value to reduce the percentage width or height. Namely, to place an element lower coordinate, for example, at 5 pixels, then take the whole canvas size, but keep a 5 pixels space from the right-bottom side of the image.

Fortunately, modern CSS can provide a workaround. There is a calc() function to calculate an accurate size using percents and pixels together. This feature allows us to move a rectangle lower the zero coordinate, fill the available size, but reduce the size by some value.

Take a look at the style attribute of the rect elements:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="250" height="250" preserveAspectRatio="none" xml:space="preserve">
    <rect x="0" y="0" width="100%" height="100%" fill="#eee" stroke="#ccc"/>
    <rect x="7" y="7" width="100%" height="100%" style="width: calc(100% - 14px); height: calc(100% - 14px);" stroke="#aaa" stroke-width="1" fill="none"/>
    <rect x="16" y="16" width="100%" height="100%" style="width: calc(100% - 32px); height: calc(100% - 32px);" stroke="#aaa" stroke-width="0.5" fill="#000" fill-opacity="0.1"/>
    <rect x="20" y="20" width="100%" height="100%" style="width: calc(100% - 40px); height: calc(100% - 40px);" fill="#f9ffff"/>
</svg>

As you can see, first rect element is moved right-down at 7 pixels, but to keep 7 pixels from the right-bottom size its size reduced by 7 * 2 = 14 pixels. The element takes the 100% size of the image, but 14 pixel less whatever image size currently is.

The same logic is for the other elements. Here how it looks in a browser now:

A little tricky? Maybe. But it solves the issue.

Editing images

To make it easy to modify such SVGs and thier properties, I've developed a special online tool:

Flexible SVG Editor

By default, it has a window frame image with two glasses. You can upload another SVG using the input at the top of the page.

This tool provides a list of all SVG elements with the possibility to change any property, change their position, clone, and add new elements.

But what about the scalability of the images? The process of keeping elements offset is much simplified with the available settings. First of all, you can place an element at the place you need using X/Y settings. They support percentage and pixel units to cover different use-cases.

Next, set the required element size using Width/Height settings. They also can have a percent or pixel value.

And the most interesting part are Width/Height offset settings to keep some space. These settings just use the same calc() CSS-function. It will use a Width/Height value and reduce the offset value automatically.

You always can test the image scalability with the handle at the right-bottom corner of the canvas. Just resize it to see how the resized image will look like.

Conclusions

Isn't it good? I believe it is. This scalable and rubber SVGs approach allows me to provide the scalable frame SVGs into my Windows Calculator project, while as the edit tool makes it easier to modify or create new images for the customers.

Feel free to use this tool and create good scalable SVGs for your projects!