Understanding the viewBox in SVGs

Icon designs on a computer screen
Published
5 min read

In this article I’ll try and explain the viewBox attribute for SVGs as they’re an important thing when it comes to making SVGs responsive. Unfortunately, the viewBox is not super intuitive if you’re not too familiar with SVG, but it can be very handy once you’ve got the hang of it.

And because there are so many ways an SVG can be included on a web page, in this article I’ll only be talking about inline SVG. Just to be clear, this is the thing we’re talking about here.

<!-- HTML content -->
<svg>
  <!-- SVG content -->
</svg>
<!-- More HTML -->

But before jumping into the tricky bits, let’s first have a quick look at how sizes and coordinates work in SVG.

SVG’s coordinate system

In traditional math, when looking at a coordinate system, we’re taught that the x-axis is horizontal and increases going from left to right and that the y-axis is vertical and increases upwards. Like so:

020406080100120140160180200050100150200250300350400

However, in SVGs (and many other computer graphics software), the y-axis is inverted meaning the top left corner has the coordinates [0,0].

050100150200250300350400020406080100120140160180200

It’s also important to note that SVGs operate in pixel values. That doesn’t necessarily mean that everything is rendered on the screen according to those values, but we’ll get into that later on. Unless viewBox has been defined, just think of the value 10 inside an SVG means “10 pixels”.

Imagine that we have an SVG with width of 200 pixels and height of 200 pixels.

<svg width="200" height="200"></svg>
020406080100120140160180200020406080100120140160180200SVG Stage

And in that SVG we’d want to draw a 100×100 pixel square.

<svg width="200" height="200">
  <rect width="100" height="100" rx="30"></rect>
</svg>
020406080100120140160180200020406080100120140160180200SVG Stage

We’ll give it a border-radius rx of 30 pixels so that it’ll be easier to notice when it’s scaled.

Remember, unless we specify x and y values for the the <rect> element, it’ll start drawing from its top left corner at [0,0].

Resizing the SVG

The fact that values in SVG represents pixels may sometimes feel frustrating, especially when we’d want to scale a graphics either because it’s too small or too big for the screen it’s viewed on.

Trying to simply increase or decrease the width attribute on the SVG won’t do the job, unfortunately:

<svg width="300" height="200">
  <rect width="100" height="100" rx="30"></rect>
</svg>
020406080100120140160180200220240260280300020406080100120140160180200SVG Stage
<svg width="100" height="200">
  <rect width="100" height="100" rx="30"></rect>
</svg>
020406080100020406080100120140160180200SVG Stage

Changing the width using CSS like other graphics like <img>s won’t work either. The result is similar to when we changed the width attribute: the SVG changes width, but the graphics inside of it remains the same size.

<svg style="width: 100%" height="200">
  <rect width="100" height="100" rx="30"></rect>
</svg>
0100200300400500020406080100120140160180200SVG Stage

Applying viewBox

The viewBox attribute lives on the <svg> element and tells the browser which part of the canvas should be rendered into view. This is the part where numeral values stop representing actual pixels on the screen. It’s still important to think of them as pixel values though, as we’ll see in a bit.

Let’s apply a simple viewBox that matches the size our SVG:

<svg width="200" height="200" viewBox="0 0 200 200">
  <rect width="100" height="100" rx="30"></rect>
</svg>

In the viewBox syntax viewBox="<num> <num> <num> <num>" the first pair of numbers are the x and y coordinates for its top left corner, and the last pair are the width and height values for the viewBox.

In this simple example, the viewBox is exactly the same as the SVG size, so nothing really changes.

020406080100120140160180200020406080100120140160180200SVG StageviewBox

A good way to think of the viewBox is that it’s a telescope which we can use to view the parts of the world (SVG) in greater detail. We can pan around (up, down, right, left) and zoom in or out to get the exact view of the graphics.

Let’s start by changing some of the parameters of the viewBox:

<svg width="200" height="200" viewBox="50 50 100 100">
  <rect width="100" height="100" rx="30"></rect>
</svg>
020406080100120140160180200020406080100120140160180200SVG StageviewBox

The browser will only render what’s inside the viewBox:

020406080100120140160180200020406080100120140160180200SVG StageviewBox

It’s important to remember that everything inside the SVG still respects the width and height values of the SVG.

020406080100120140160180200020406080100120140160180200SVG StageviewBox
01020304050607080901001101201301401500102030405060708090100110120130140150SVG StageviewBox

Nothing prevents us from setting the viewBox to a negative value, and sometimes that’s actually a very useful trick. Let’s set the viewBox to start at [-10,-10] and make it 120 pixels wide and tall.

<svg width="200" height="200" viewBox="-10 -10 120 120">
  <rect width="100" height="100" rx="30"></rect>
</svg>

So this viewBox …

020406080100120140160180200020406080100120140160180200SVG StageviewBox

… renders this view:

020406080100120140160180200020406080100120140160180200SVG StageviewBox

Scaling SVGs with CSS

The thing is that the SVG above is still rendered at the size defined in its width attribute at 200 pixels. Sometimes we’d want the SVG to be at a certain size smaller than what is defined in its “pixel” values, for instance with icons.

In order to set the size if which it’s rendered, we can simply change the width and height attributes directly on the SVG, but leaving the viewBox intact:

<svg width="100" height="100" viewBox="-10 -10 120 120">
  <rect width="100" height="100" rx="30"></rect>
</svg>
020406080100020406080100SVG StageviewBox

Other times we need to fill the available space, let’s say for an illustration, diagram or chart. Luckily, there’s a way we can use CSS to do this. So in our CSS we can do something like:

svg {
  width: 100%;
}

and then remove the width attribute from the SVG element all together:

<svg height="100" viewBox="-10 -10 120 120" style="width: 100%;">
  <rect width="100" height="100" rx="30"></rect>
</svg>

Now the SVG takes up all the available width of its container. I’ve added a grey border around the SVG element here so it’s easier to see where it is.

What we really want is not just to extend the width of it, but to increase the height as well keeping the original aspect ratio. We need to get rid of the height attribute as well. But instead of calculating what the height should be at every breakpoint we’d want the height to be dynamic.

In order to achieve this we just remove the height attribute as well.

<svg viewBox="-10 -10 120 120" style="width: 100%;">
  <rect width="100" height="100" rx="30"></rect>
</svg>

Yay!

Next up

I’m planning on doing a series on responsive data visualisations, please stay tuned for more SVG fun.

You may also be interested in ...