Why are SVG coordinates so confusing?
SVGs are incredibly powerful but, if your experience is anything like mine, you’ve found all the viewBox jazz to be extremely “fiddly” and, thus, hard to master.
I thought originally that I’d pick up eventually just by playing around with parameters. This proved frustrating because there are a lot of permutations between the following sets of variables:
- The SVG’s
widthandheightattributes - The SVG’s style attribute’s
widthandheightproperties - The numbers in
viewBox="W X Y Z") - The values taken by the
preserveAspectRatioattribute.
There are lots of tutorials out there, but most don’t go to the lengths necessary to avoid ambiguity and confusion on SVG coordinates. They tend to employ jargon that requires you to first understand what all these parameters mean (‘user space’, ‘view port’, ‘view port space’, ‘visible area’, etc.), and/or make ambiguous assertions along the way like “the ‘view port’ is the visible area of the SVG”.*
I’ve therefore taken it upon myself to provide an orderly account of SVG coordinates and, having researched the matter, I can hopefully help you gain clarity.
Before Continuing
Be warned, having worked my way through this I’ve come to realize that you have to be prepared to give this subject some serious concentration for probably an hour or two; this stuff just can’t be picked through trial and error. The good news though is that it does make good sense once you get your head around it, and it’s a nice feeling when you get there. SVG’s are an incredible skill to have in your toolkit, so dig out the time to get your foundations in solid order.
Let’s also begin by making sure our basic HTML terminology is used with precision. If you’re not clear on the following distinctions, then take a moment to check out these links:
OK, let’s go!
1. The “View Port”
The basic way of setting the size of an HTML element as it appears in the browser† is to set the width and height properties of an element’s style attribute (e.g. <div style="width: 100px;"> ... </div>).‡
Alternatively, in the case of a select few HTML elements,§ you can achieve the same effect — determining the size of the element as it appears in the browser — by setting dedicated width and height attributes on the element instead (e.g. <svg width="100" height="100"> ... </svg>).¶
Choosing between these two ways of determining how much actual screen space the SVG element occupies is something of a matter of taste.# Just be aware that the values of the style’s width/height properties will trump those of the element’s width/height attributes.
In the context of SVGs, the rectangle defined within the browser window by setting either the width/height attributes or the style’s width/height properties is referred to as the “view port“. For example, the following declaration:
<svg width="100" height="100" style="background-color: green;">
would result in an SVG view port coincident with the green square you’d see in the browser.
2. View Port Coordinates
As with any HTML element, the SVG element is associated with a coordinate system whose origin is at the top-left corner, and whose default unit is the pixel. These coordinates could be used to perform standard HTML undertakings, such as the absolute positioning of a child element relative to the upper-left corner of the SVG.
In the context of SVGs, this same coordinate system is referred to as the ‘view-port coordinate system’ (a.k.a “view-port space”). As explained in more detail below, coordinate system will serve as the default coordinate system for drawing shapes.
Note that in the absence of width/height attributes or style properties within the SVG, most browsers will allot the SVG element sides of length 300/150 pixels respectively. Or, to put in other words, the default size of the view port is 300 x 150 pixels.
3. The “View Box”
Let’s forget about the view port for a second and restart our conceptual journey from. afresh angle. Scalable Vector Graphics (SVGs), as the name implies, are all about encoding your image information using real numbers and geometric constructs (circles, rectangles, etc.). So we’ll need a coordinate system in which we can define these paths, circles, etc., and we’ll call this space the “user space” (a.k.a “user-coordinate space” and “user-coordinate system”).††
Now that we’ve defined two spaces — the browser-realized “view-port space” and this putative “user space” — we begin to sense that the nature of the challenge, and the source of much confusion/ambiguity,‡‡ will be to map one to other.
In the absence of a viewBox property on the SVG tag, the user space and view-port space are identical, with the view port acting as the visible part of those coinciding spaces.
This is nice and simple but, as you might well sense, we’ll want to be able to customize the mapping between the user space and the view-port space in order to more finely control transformations, such as stretches. This customized mapping between spaces is achieved by two attributes of the SVG: viewBox and the preserveAspectRatio.
A viewBox attribute defines a rectangular region within user space called the “view box”. In the absence of a preserveAspectRatio attribute, that region will be scaled to fit within the bounds of the view port and then centered.
It’s import to realize that anything drawn outside the view box can still be visible so long as they fit within the view port. Schematic depictions of these relations are shown in Figure 1, where the user-space coordinate system and the view-port coordinate system are drawn together with coinciding origins.

Note: in the absence of a width/height attributes, the view port assumes dimensions equal to that of the viewBox (i.e. the SVG just displays the view box exactly). So if you were to declare <svg viewBox="0 0 10000 10000">...</svg> then the SVG element would be rendered in the browser as a 10k x 10k pixel element. For this reason, it is advised to always ensure that the view port is set explicitly.
4. preserveAspectRatio Attribute
If the view port and view box have the same aspect ratio, then there is nothing more to do. The contents of the view box will simply be scaled, if necessary, to fit the view port.
If however the view port and view box rectangles do not have the same aspect ratio, then you can sense that there are going to be various ways that the view box could be stretched and/or positioned within the view port. This is the scenario we shall be considering from hereon, and where the preserveAspectRatio attribute comes into effect.
When you want the contents of the view box to be stretched to fit the view port, then just set preserveAspectRatio="none". This is similar to setting the css property object-fit: fill; in order to stretch a background image within e.g. a div element.
As the name implies, any other (valid) value given to this attribute will preserve the aspect ratio of the view-box contents. Such values take a string of the form “X Y” where X specifies the direction with which to shift the view box within the view port (if permitted after scaling), and where Y specifies the type of scaling.
Let’s start with Y. This can assume one of two possible values: “meet” or “slice”. These two values correspond closely to setting the css properties object-fit: contain; and object-fit: cover; respectively. Meet will scale the view box to fit within the width or length of the view port, and slice will scale the view box to take up the entire view port whilst preserving aspect ratio.
After scaling the view box to fit the view port in either the up/down or left/right directions, it will be the case that there is freedom to shift the view box in the other direction. This is where the X value comes in. It takes values of the form xMidYMid where “Mid” can be replaced with either “Min” or “Max”, depending on whether you want to shift “negatively” or “positively” along the free direction.
Conclusion
Once you’ve wrapped your head around these concepts, you’ll begin to appreciate how hard it would be to figure out these definitions/relations just by playing around with parameters.
I hope this brought you clarity and lets you enjoy working with SVGs a lot more. If you’re still confused, then I suggest you do what I did: write an article where you research and then try your best to explain these matters to someone else. Docendo discimus.
- *If that statement doesn’t seem ambiguous to you then either you already understand SVG coordinates or you’re a better person than I.
- †I.e. to determine the actual number of pixels on the screen that get taken up by the element.
- ‡Alternatively, of course, one can set these styles using css selectors and declarations within a separate style sheet.
- §These are the “image” elements svg, canvas and img
- ¶The one difference in using width over style.width is that the browser will be able to use the width property to allot space for the element before parsing the css. The motivations for this are somewhat historic in character.
- #See here for one opinion on the matter: https://stackoverflow.com/a/2414940/8620332
- **Technically, this default value is also only applied in the absence of the viewBox parameter as described later.
- ††I think it’s referred to as “user space” because the user has (via the viewBox and preserveAspectRation properties) control over where in the infinite plane the shapes are drawn, stretched, etc.
- ‡‡For example you might come across ambiguous statements like “the view port defines the visible area” without specifying what space this “area” is in.
Leave a Reply