Making Sense of SVG viewBox's Madness
Madness was the only thing I could call viewBox's behaviour during the first few hours I spent researching and playing with examples. After finally figuring it out by reading way more of the W3 spec than I had planned, I decided to write a more user-friendly introduction to viewBox here.
I encourage you to follow along and play with different possible viewBox set ups as we go. Open up my viewBox sandbox (source code) and try out the examples in this article for yourself, or just use your browser's dev tools directly on the SVGs below.
What is viewBox and why should I use it?
viewBox is a powerful tool for scaling, stretching, positioning, and/or dividing up parts of an SVG object. It basically positions a child element of the parent SVG, defines a distinct coordinate system for it, and stretches or crops the child to fit the parent. This is useful for SVG image design itself such as when applying filters or masks, but it becomes especially useful for a web developer that wants to position an SVG within some parent, especially dynamically.
Defining this child view makes use of two parameters: viewBox and preserveAspectRatio. viewBox is set with four parameters, like this:
<svg viewBox="<min-x>, <min-y>, <width>, <height>"></svg>
Where <min-x> and <min-y> define the origin of the viewBox within the parent, and <width> and <height> map the area of the parent element to a coordinate system unique to the viewBox. I told you, viewBox is madness. We'll look at an example below, but for now just understand that these four parameters are not defining a rectangle inside of the parent in regular coordinates, they are basically defining a coordinate system for the viewBox. Let's see how to set preserveAspectRatio.
<svg preserveAspectRatio="<align> <meetOrSlice>"></svg>
This attribute is a bit more intuitive. When used together with the viewBox attribute, preserveAspectRatio specifies whether or not the child should keep its native aspect ratio after being placed in the viewBox, how it should be positioned within the viewBox if so, and whether it should be scaled or cropped. MDN does a great job of listing out the potential values of this attribute, so I won't try to replicate that here. You can also see the effects of all of these in a very thorough example from the W3.
Stretch Example
Let's take a look at the simplest case for preserveAspectRatio as our first viewBox example. If we set preserveAspectRatio="none" on our parent, then the content will simply stretch to fit the parent, without preserving the aspect ratio of the child.
This example is from the W3 at www.w3.org/TR/SVG/images/coords/ViewBox.svg
Go ahead and open up this SVG in your developer tools and mess with the width and height attributes. You'll see that whatever you set them to, the content stretches itself to fit inside of the parent and completely fill it.
So what is the viewBox="0 0 1500 1000" attribute doing? If you try messing with the first two parameters, <min-x> and <min-y>, you'll see that any non-zero value simply translates the child image, which is also cropped at the boundaries of the parent. This makes sense, as these parameters are simply the origin of our viewBox. Changing the <width> and <height> parameters makes things complicated.
Before you do mess with them, notice something about their relation to the child image. I said above that <width> and <height> define the coordinate system used in the child image. So looking at this example, our coordinate system inside our parent element is from 0-1500 in the x direction, and from 0-1000 in the y direction. These aren't real pixels on your screen, this is just a coordinate system defined and mapped into the parent element, which in this case is actually 500px by 100px. Looking at the path of the red triangle, you can see that it is made of points (750,100), (250,900), and (1250, 900) in this new coordinate system. If you compare that to the image you see on the screen, well golly doesn't it look like it fits as expected in the viewBox going from 0-1500 and 0-1000.
Now, playing with these <width> and <height> values should produce an intuitive result.
This may have seemed like the simplest of examples, but if you understood that, you already know by far the hardest parts of viewBox. By changing the value of preserveAspectRatio to some of the more interesting values that it can take, all you are doing is manipulating the position of the child within the parent and scaling/cropping. Let's illustrate this with another example.
Preserving the Aspect Ratio Example
This example is from the W3 at http://www.w3.org/TR/SVG/images/coords/PreserveAspectRatio.svg
Now that you understand how all of these nice smiley faces are fitting inside their containers, understanding how to position them inside their parent is a small step. When we set preserveAspectRatio to anything but "none", the child is fit inside the parent by scaling, not by stretching. If the parent isn't also the same aspect ratio as the child, we're going to have either some extra space or some overflow. Using these attributes, you can align the child image however you want it to appear inside the viewbox.
Don't forget that you can combine these x and y options in any way you want, too. Again see the MDN list of all possible values if this example isn't enough!
A bit of geometrical excercise for your brain, but that is the gist of SVG's viewBox. Madness? Easy to conclude at first when you're used to dealing with the more everyday world of HTML layout, but once understood viewBox is a powerful tool. I'm currently using it to scale a dynamic SVG in my soon-to-be announced Multitasq project, and I hope to share more soon.
Update: Check out my project Multitasq to see an example of using viewBox to zoom a complex SVG. Source code here.