Digital humanities


Maintained by: David J. Birnbaum (djbpitt@gmail.com) [Creative Commons BY-NC-SA 3.0 Unported License] Last modified: 2022-08-17T19:45:17+0000


Viewbox tutorial: an introduction to the SVG coordinate space

Terminology

What gets shown when an SVG image is rendered depends on values that may seem counter-intuitive at first. For example, if you embed an SVG image in your HTML and look at the result in a browser, the image may be truncated horizontally or vertically. The SVG coordinate space is infinite (you can specify X and Y values as large or as small as you want), so it isn’t surprising that the browser window does not show the entire infinite space. What may be surprising, though, is that changing the values of the @width and @height attributes on the root <svg> element is unlikely to fix the problem because what gets rendered in the browser window is determined by the interplay of two sets of spatial coordinates:

Getting the browser to display what you want at the size you want involves coordinating the settings you specify for the viewport and the viewBox. The default behavior if you don’t specify those values yourself will rarely be what you want, so learning how to render SVG in a browser requires learning how the viewport and viewBox cooperate to render that image. The purpose of this tutorial is to provide a basic introduction, with examples, into managing your SVG display.

Quadrants in the SVG coordinate space

SVG operates on a quadrant system, but by default only the lower right quadrant is visible in the viewport—the portion of the coordinate space that is visible when the SVG is rendered. The coordinate space (all four quadrants) looks like the following, except that it extends infinitely in all four directions:

Lower Right Quadrant 0 50 100 150 200 Lower Left Quadrant -50 -100 -150 -200 50 100 150 200 Upper Right Quadrant -50 -100 -150 -200 Upper Left Quadrant

The upper left corner of the viewport is always at the origin (0, 0) and extends down (according to the value of the @height attribute) and to the right (according to the value of the @width attribute). You can’t move the upper left corner of the viewport, so if you want to render anything that you’ve drawn in any of the other quadrants you have to move the reality that is outside your window—that is, you have to move the coordinate space (and therefore the image you have drawn in that space) to bring some other part of it into the viewport. That movement is the role of the viewBox.

We find drawing in the lower right quadrant challenging because Y values get larger as we travel down the Y axis, and that Y behavior is the opposite of what we expect from our prior experience with graphing. The solution to this problem that we favor in our own work is to draw in the upper right quadrant because that makes the arithmetic more intuitive. The Y values in the upper right are negative, and they become larger negative numbers (that is, they move from 0 to -∞) as you move up the Y axis, as you can see in the illustration below. If we draw in the upper right quadrant, then, we can think of an object with a height of 200px as growing down from a Y position of -200 to a Y position of 0. If we simply draw in this quadrant, though, it won’t be visible in the browser window because by default the browser window shows only the lower left quadrant. We can remedy that by using viewBox settings to move the upper right quadrant into our viewport, that is, by specifying that some position other than the default (0, 0) should be in the upper left corner of the viewport.

Let’s say we want to draw a rectangle with a width of 100 px and a height of 200 px in the upper right quadrant, and we want the left edge of the rectangle to start 50px from the left. The values of the @x, @width, and @height values on the rectangle are what you would expect, but the @y value will be negative instead of positive:

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300">
    <rect x="50" y="-200" width="100" height="200" opacity=".5" fill="blue"/>
</svg>
Upper Right Quadrant 0 50 100 150 200 -50 -100 -150 -200

If, though, you were to save the code above as an SVG document and open it in a browser you wouldn’t see anything because it is drawing in the upper right quadrant and by default all we see in the browser is the (empty) lower right quadrant! We somehow need to make the upper right quadrant visible, and since we can’t move the viewport, we need to move the image down so bring the upper right quadrant into the viewport. That’s a job for our viewBox!

Using the @viewBox attribute

The viewport coordinate system—that is, the coordinate system that determines the size of the window that frames the part of the infinite coordinate space that we can see—defaults to showing only (part of) the lower right quadrant. The upper left corner of the viewport is at position (0, 0) of our image by default, and we define the dimensions of the viewport by using the @height (how far down it reaches) and @width (how far to the right it reaches) attributes. If the viewport is the window that lets us see part of the SVG canvas, the viewBox lets us move and resize our image so that the portion of the canvas that contains the image we care about is visible through that window.

@viewBox attribute values

The @viewBox attribute takes four numbers (in order and separated by either spaces or commas) as its value: the minimum X value (the smallest X value that will be visible, at the far left edge of the viewport), the minimum Y value (the Y value at the very top of the viewport), the width, and the height. Consider the following SVG, which draws a rectangle that—perhaps surprisingly—isn’t shown in the rendering:

<svg xmlns="http://www.w3.org/2000/svg" height="200" width="150">
    <rect x="50" y="-200" width="100" height="200" fill="blue"/>
</svg>
0

We are drawing the rectangle correctly, but we don’t see it because we are drawing it above the top of the viewport. Here’s why: The @y value for the rectangle is -200 and the @height is 200px, so every part of the rectangle has a negative Y position between -200 and 0. Since by default everything with a negative Y position is located above the top of the viewport, we are drawing the entire rectangle outside the portion of the coordinate space that we can see, that is, outside the viewport. There are three ways to fix this problem:

  1. We could draw the rectangle in visible space, with no negative @y values, but we aren’t going to do that.

  2. We could draw the rectangle in invisible space, as we do now, and then move just the rectangle down into visible space. It is possible to do this with SVG, but we aren’t going to take this approach either.

  3. We can move the entire infinite coordinate space where we drew our rectangle down so that the portion of it where our rectangle is located moves into the viewport. In other words, because we can’t see what we want to see through the window in the wall of our apartment, we can move the entire outside world to bring the part we care about into what we can see through our window.

We’re going to use this third method, and the feature of SVG that lets us do that is the @viewBox attribute:

<svg xmlns="http://www.w3.org/2000/svg" height="200" width="150" viewBox="0 -200 150 200">
    <rect x="50" y="-200" width="100" height="200" fill="blue" opacity=".5"/>
</svg>
0

The viewBox defines what is visible inside our window as the portion of the infinite coordinate space that starts at X position 0 (the first of the four values in the @viewBox attribute) and extends 150px to the right (the third @viewBox value). Vertically the visible space starts at Y position -200 and extends down for a height of 200px. Since the leftmost X position of the viewBox is 0 and the rectangle starts at an X position of 50, there is a 50px margin between the left edge of the viewport and the left edge of the rectangle. The rectangle exactly fits the height of the viewport because the viewBox and viewport have the same height (200px). There is no blank space to the right of the rectangle because the @viewBox values say that we can see only X positions between 0 and 150, so a rectangle that begins at X position 50 and has a width of 100px reaches exactly to the right edge of the visible space.

If we want to center our rectangle horizontally in the visible space with equally sized blank space to the left and the right we can make the visible area wider by increasing the width setting (the third item) in the @viewBox:

<svg xmlns="http://www.w3.org/2000/svg" height="200" width="150" viewBox="0 -200 200 200">
    <rect x="50" y="-200" width="100" height="200" fill="blue" opacity=".5"/>
</svg>
0

Uh oh! We drew the rectangle in both instances with the same dimensions, and we managed to center it horizontally, but what’s going vertically? Why does it no longer fix the viewport exactly vertically, the way it did before? We haven’t changed any of the vertical values for either the rectangle or the viewBox.

The reason our rectangle is now smaller vertically within the visible space is that although we created a wider window, the dimensions of the viewport (defined by the @height and @width attributes on the root <svg> element) remained the same. Initially the viewBox and viewport had the same dimensions: both specified a width of 150px and a height of 200px. When the height and width of the viewBox are different from those of the viewport, though, the viewBox is scaled to fit inside the viewport, and the only way to fit the 200px viewBox width inside the 150px viewport width is to shrink everything. Although that behavior is confusing at first, we’ll see below why it ultimately makes your life easier.

To preserve the rectangle’s size on the page, let’s adjust the viewport dimensions (the @height and @width attribute values) to match those of the viewBox:

<svg xmlns="http://www.w3.org/2000/svg" height="200" width="200" viewBox="0 -200 200 200">
    <rect x="50" y="-200" width="100" height="200" fill="blue" opacity=".5"/>
</svg>
0

Now all is well again and our viewBox and viewport are exactly aligned.

Using the @viewBox to control scaling

As we’ve just seen, the reason the viewport and viewBox are allowed to disagree is that controlling them separately allows us to control the scaling of our SVG, which is especially useful when we embed SVG inside HTML, and we often do in our project websites. To see how this works let’s create some very small text (setting the @font-size property to 5 and not initially specifying a @viewBox). The viewport is described by the @height and @width attributes on the root <svg> element, and it specifies the height and width allocated to hold the image. We’ve drawn a rectangle of that size to make the borders easier to see:

<svg xmlns="http://www.w3.org/2000/svg" height="40" width="200">
    <rect x="0" y="0" height="40" width="200" stroke="black" 
        stroke-width="0.5" fill="transparent"/>
    <text x="20" y="20" font-size="5">I ❤ SVG!</text>
</svg>
I ❤ SVG!

If we add a @viewBox that starts at the X and Y positions of the <text> element and is tall enough to match the size of the text (the text size is 5 and we’ve specified a viewBox height of 6), the SVG is now scaled up:

<svg xmlns="http://www.w3.org/2000/svg" height="40" width="200" viewBox="20 15 20 6">
    <rect x="0" y="0" height="40" width="200" stroke="black" 
        stroke-width="0.5" fill="transparent"/>
    <text x="20" y="20" font-size="5">I ❤ SVG!</text>
</svg>
I ❤ SVG!

The rectangle is still being drawn, but we can no longer see it because the @viewBox only renders content drawn at X positions bewteen 20 and 40 and Y positions between 15 and 21.

Conclusions

If you’re interested in learning more about the viewBox, including how to stretch images, we recommend Sara Soueidan’s Understanding SVG coordinate systems. You can also experiment with viewBox settings at her interactive demo page.