Digital humanities


Maintained by: David J. Birnbaum (djbpitt@gmail.com) [Creative Commons BY-NC-SA 3.0 Unported License] Last modified: 2022-04-06T01:24:25+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 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 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

As you already know, the lower right quadrant can be difficult to work with because Y values get larger as you 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 draw in this quadrant, however, we need to make our work visible when the SVG is rendered, since by default SVG will not render anything that isn’t drawn in the lower right quadrant.

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. The @x, @width, and @height values on the rectangle all stay the same, 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

Note, though, that if 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.

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 by default, and the user defines the dimensions of the viewport by using the @height (how far down it reaches) and @width (how far to the right it reaches) attributes. We can define our own coordinate system, however, using the @viewBox attribute, which overrides the viewport defaults. If the viewport is the window that lets us see part of the SVG canvas, the viewbox lets us move that window and expand and shrink its contents to override the default of showing only the lower left quadrant and instead show the part of the infinite coordinate space that we care about.

@viewBox attribute values

The @viewBox attributes 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 it 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 browser window over the part of the infinite coordinate space where we drew our rectangle instead of over the lower left quadrant, where it is located by default. 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 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

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 <xml> 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