Maintained by: David J. Birnbaum (djbpitt@gmail.com) Last modified: 2022-08-17T19:45:17+0000
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:
The viewport controls your view onto the infinite coordinate space outside. Much as the location and size of a real window in a real wall determines what you can see outside, the viewport determines how much of the infinite SVG coordinate space you can see. If you don’t like the view out the window of your apartment you can’t do much about it because the window cannot easily be moved or resized, but if you could resize the real window you would be able to see more (or less) of the outside. The SVG viewport is your window onto the outside.
You can’t change the location of the SVG viewport (much as you can’t move a
real window from one wall to a different wall), but you can control the size
of the viewport with the @height
and
@width
attributes of the root
<svg>
element. If the viewport is
smaller than your browser window, the SVG you are rendering will be
truncated at the specified @height
and
@width
. If the viewport is larger than
your browser window, the SVG will extend beyond the edges, and whether you
can scroll more of it into view will depend on how you have configured your
scroll (overflow) settings.
Changing the @height
and
@width
of the viewport is like resizing
the window in your wall, but with SVG you can also move and resize what is
outside the window (we’ll call this the coordinate space) by
changing the viewBox settings. You can think of changing the
viewBox settings as similar to moving and resizing the outside world. Moving
the outside world means that a different portion of it is visible through
your window (the viewport). Resizing the outside world means stretching or
shrinking it so that more or less of it is visible through that window.
Note that viewBox is spelled with an uppercase B
in the
middle. Because XML is case-sensitive, if you misspell the word when you use
it as an attribute name in your SVG, the values you specify won’t have the
desired effect on how your image is rendered.
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.
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:
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>
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!
@viewBox
attributeThe 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 valuesThe @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>
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:
We could draw the rectangle in visible space, with no negative
@y
values, but we aren’t going to do
that.
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.
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>
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>
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>
Now all is well again and our viewBox and viewport are exactly aligned.
@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>
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>
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
.
@viewBox
attribute on the
<svg>
root element.@viewBox
takes four values: the minimum
(leftmost) X value, the minimum (topmost) Y value, the width, and the height.
Values always appear in that order and are separated by spaces or commas, e.g.,
viewBox="0 0 50 100"
.@height
and
@width
attributes of
<svg>
. By default, the ratio of the
dimensions are preserved, so that the image does not appear stretched. There are
ways to change this, which we won’t go into here.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.