How to render responsive SVGs on all browsers

Devin Beliveau
8 min readFeb 17, 2021

As developers, we’ll be familiar with SVGs — they’re one of the easiest things to implement for frontend optimization. Replacing assets with SVGs not only reduces file size, but inline SVGs don’t require HTTP requests, making immediate, positive impacts on website performance and load times. While SVGs are an obvious solution, especially because maintaining crisp quality is important as screen resolutions get better, there can be a lot of frustration when it comes to loading SVGs consistently across all browsers. SVGs are supported on all modern browsers (even all the way back to IE9!), however, the rendering is not consistent between them (see caniuse.com/svg for technical specifications). When we take into account SVGs can export differently from each design program, the end result is that not all SVGs are created equal. In this article, we’ll discuss the basics needed to render something as simple as an SVG logo consistently across all browsers.

Your designer gave you an SVG, now what?

Let’s take a look at the code from the exact same design, exported from two of the most widely used design programs: Figma and Illustrator.

Figma:

<svg id=”figma” width=”504" height=”161" viewBox=”0 0 504 161" fill=”none” xmlns=”http://www.w3.org/2000/svg">
<rect width=”504" height=”161" fill=”#000000"/>
</svg>

Illustrator:

<svg id="illustrator" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 504 161">
<title>illustrator</title>
<rect width="504" height="161" fill="#000000"/>
</svg>

As we can see, the SVG produced by Figma comes with the width, height, and viewbox attributes, while Illustrator’s SVG comes with just the viewbox attribute, as well as a title element. The viewbox is the most important attribute, as this is what allows the SVG to be responsive on a website — so it’s not surprising that it’s included in both exports.

So which export is correct? Generally speaking, we want to omit the width and height attributes. This is because they can actually cause responsive issues in certain situations — or in certain browsers — and the point here is to maintain consistency with how the SVG behaves. Let’s load them in a browser without changing anything to see how they look.

We have some lovely black boxes with borders and a width of 20% added through CSS. We can clearly see these SVGs are behaving differently on the page. Figma’s SVG, with a red border, is taking up more space with the width and height attributes set, whereas Illustrator’s SVG, with a blue border, is contained to the space it actually needs to occupy. We would need to remove the width and height attributes from Figma’s SVG to get the same result as Illustrator’s. Well that’s it then, removing the attributes solves all the problems! Well, not exactly. The photo above was taken on an actual modern browser, Chrome. Let’s look at the same code in Internet Explorer 11.

Here we have the opposite problem: Figma’s SVG is maintaining a fairly consistent issue, while Illustrator’s SVG is having some serious problems. As noted on the caniuse page in the introduction, this is because Internet Explorer requires width and height attributes to render SVGs properly. So what can be done? This post on Stack Overflow offers a variety of ways to solve this problem, though it appears not every solution offered in the comments works for everyone. This is why we’re going to look at a way to approach this without using hacks like implementing, then hiding extra elements, or forcing the SVG to render as an image, which requires an HTTP request and minimizes the control a developer has over the SVG.

Containing the SVG in a parent element

We can put an elegant solution in place by adding a container, an extra SVG attribute, plus some cleverly crafted CSS. We’ll continue to use Illustrator’s SVG moving forward, since it already eliminates the unwanted attributes, as well as provides us with the accessibility friendly title element for screen readers. Let’s first wrap the SVG in a div element. We’ll move the 20% width that’s been set on the SVG to the container and we’ll simply set the SVG’s width to be 100%. This will allow the container to control the width, and the SVG can scale according to its parent. The HTML and CSS should look like this (note the SVG has an id of “illustrator”):

//HTML
<div id="container">
<svg id="illustrator" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 504 161">
<title>illustrator</title>
<rect width="504" height="161" fill="#000000"/>
</svg>
</div>
//CSS
#container {
width: 20%;
border: 2px solid blue;
}
#illustrator {
width: 100%;
}

There will be no visible difference in the way the SVGs are rendering yet.

SVG’s preserve aspect ratio attribute

Now let’s take a look at SVG’s preserveAspectRatio attribute. Described as the “partner in crime of the SVG viewbox” by DigitalOcean, preserveAspectRatio allows us to further control how the SVG scales. The preserveAspectRatio has thirteen variations, of which I won’t go into detail here, but the MDN web docs goes over each of them. We’ll be using the xMidYmin slice variation. The biggest concept to understand here is that slice acts a lot like CSS’s background-size: cover;. When we implement it, our SVG now looks different in Internet Explorer.

<div id="container">
<svg id="illustrator" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 504 161" preserveAspectRatio="xMidYMin slice">
<title>illustrator</title>
<rect width="504" height="161" fill="#000000"/>
</svg>
</div>

It’s still broken in Internet Explorer, but now it’s broken differently, and that’s a start. The rest we’ll tackle with that cleverly crafted CSS, which, unfortunately will involve some math. Don’t worry, all the numbers are already provided by the SVG, and the calculator can do all the heavy lifting on this one. Let’s tackle the basic CSS before we get to the math.

Note: the SVG is still behaving perfectly normal in modern browsers like Chrome and Safari.

Controlling size with basic CSS

#container {
width: 20%;
border: 2px solid blue;
}
#illustrator {
display: block;
width: 100%;
box-sizing: content-box;
height: 1px;
overflow: visible;
}

By default, an SVG is an inline element. By setting it to display: block;, we’re forcing the SVG and container to share a height. We’ll also add box-sizing: content-box; to ensure that padding is not accounted for when calculating size, which will be important in the next section. Ultimately, we do need a height to be associated with the SVG. We already know we can’t add it to the SVG directly as an attribute, so we need to add the height through CSS. The tricky bit to get around here is that an SVG needs a height, or width, explicitly set in pixels to maintain responsiveness. We’ll do something a little unusual and set the SVG to height: 1px;. This does something interesting. We can see in the above photo that even though the height is on the SVG element, it’s changing the height of the container element. It’s also snapping the SVG to the correct width, no longer flowing outside of the container. This is due to the preserveAspectRatio attribute we added to the SVG earlier. Lastly, the overflow: visible; property allows the SVG to flow outside the 1px height of the parent container.

If we take away the border, we could leave the code like this — the SVG is now taking up the proper size across all browsers. However, this feels incomplete, messy and, well, dirty. Doing some math will help us fix the container’s height to be in proportion with the SVG.

Setting height using existing attributes — and a little math

Padding-bottom to the rescue! By leveraging padding-bottom on the SVG, we can add the height we need to force the container to take up the same space. Since the box-sizing property has been set to not include padding, when we add a padding-bottom property, we should expect the height to change. We know from the SVG’s viewbox attribute that the height is 161. So how do we figure out what we need to render this responsively? If we take the height of the SVG and divide by the width, we can get an aspect ratio. In this case, 161 divided by the width, 504, is 0.3194. If we multiply this by 100, we get 31.94 — which is a number we can input into our CSS as a percentage. We can round up to 32%, since decimal behavior in browsers is not always consistent.

#container {
width: 20%;
border: 2px solid blue;
}
#illustrator {
display: block;
width: 100%;
box-sizing: content-box;
height: 1px;
overflow: visible;
padding-bottom: 32%;
}

Now, if we look at our SVG in any browser, we get consistent sizing of the SVG and container. There’s a little white space on the bottom, due to rounding the percentage up — which any perfectionist can certainly use decimals to fix. Though it may end up slightly different in every browser with decimals — here is a test page by Alex Kilgour that shows inconsistent decimal rendering.

Conclusion

SVGs can seem like a fast way to optimize a site’s performance, and they are, but because browsers treat them differently, SVGs need to be tested across all browsers to ensure consistent behavior. And yes, mainstream support officially ended for Internet Explorer in October 2020, but we can’t discount it wholly quite yet. While not as complex as some other problems developers will have to solve, SVG rendering and behavior are important parts of modern websites. Solving these issues requires out-of-the-box logic and lots of testing. After you’ve mastered the ability to render SVGs, then you can start exploring the vast amount of fun you can have with SVG animations!

The final code:

//HTML
<div id="container">
<svg id="illustrator" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 504 161" preserveAspectRatio="xMidYMin slice">
<title>illustrator</title>
<rect width="504" height="161" fill="#000000"/>
</svg>
</div>
//CSS
#container {
width: 20%;
}
#illustrator {
display: block;
width: 100%;
box-sizing: content-box;
height: 1px;
overflow: visible;
padding-bottom: 32%;
}

--

--

Devin Beliveau

Once a developer, now a tech writer. Always a traveler.