At the end of my first post about SVG, I told you that today, I would talk about the use of CSS with SVG, but guess what… I lied. Yep!
Do I feel sorry? Not even a bit. Why? Because it’s for your own good.
As I was writing the CSS and SVG article, I realized it was a better idea to tell you about other SVG properties first, so you can see the whole SVG world and use it to its full potential. Being able to understand, draw and use basic SVG shapes is cool, but like I said in the first article, it’s only the tip of the iceberg. Knowing and using only the basic shapes is like having a Tesla car, and only driving it in your driveway.
Let’s imagine you are standing in your living room looking at your Tesla through the window, wishing you could take it on the highway. Your window lets you do that. They are handy things, windows. Their shape and size don’t change. They hang on the same place on the wall all the time. But they are better than pictures. Pictures never change. The scene on the canvas in a picture frame is always the same. But the “canvas” of the real world can show all kinds of things, viewable through your window.
So while you are looking at your Tesla parked in the driveway, you can also see your neighbor across the street, waving at you as he leaves for work. Kids are playing in the street between your two houses. A milkman is delivering milk to your neighbor’s wife, even though she is vegan. You know, everyday stuff.
Here’s the thing, if you move to the left relative to your window, you’ll see stuff on another angle that you couldn’t see from where you were first standing. Say the neighbour who lives next to the vegan wife family, drinking coffee on the porch. Same if you move to the right, and see the neighbour on the other side checking her mailbox.
Moving close to or far from the window will create a zoom effect on what you are looking at. Up close you can see all three houses across the street at once. Back up and you only see the first neighbour.
When you create typical graphics files, they are like a picture. The contents of the frame are fixed. When you create an SVG element in your html document, however, it is more like a window, and the “canvas” is the viewable through that window. The canvas can be bigger and have more on it that you can see through the window, and the cool part is, you can change view. You can dynamically offset view and canvas to create very slick effects.
The window and the canvas in SVG are each defined by one of two coordinate systems. They do a bit of an interesting dance to produce the effects I want to explore with you.
- The “living room window” frame is called the viewport coordinate system. It is your window. Through it you see what is on the SVG canvas, but you may not see 100% of what is on there.
- The second system represents what you see through that window – the contents displayed on the part of the canvas you can view. This is what users actually experience as “the image” or “the graphic” being displayed, and it is called the user coordinate system (or “viewbox”).
These two coordinate systems can overlap completely to create a fairly conventional web graphic. More than this, you can position, stretch and scale one of these coordinate systems within the view defined by the other. That is where things get interesting, and it is possible because you have independent control of the viewport frame and the viewbox canvas.
Let’s dig into the details!
1 – Viewport coordinate system
The viewport, also referred as the viewport coordinate system, is created automatically when you create an SVG element. It’s the area that will display your SVG graphic. Think of it as the window I mentioned earlier. The coordinate system starts at the top left corner, the (0,0) coordinate, and increases as you go right on the X axis, and down on the Y axis.
To specify the viewport dimensions, you just set a width and height to your SVG element. By default, the units are in pixels but they could be in: %, mm, cm, em, pt, pc or in.
2 – Viewbox
The viewbox is what the user sees in the user coordinate system. It is used to position, scale and stretch the graphic within the viewport. It is defined by four properties:
2.1 – The
The viewport and viewbox overlay each other by default, but the viewbox (canvas) can be offset relative to the viewport (window). The offset is defined by the viewbox or the user coordinate system dimensions, specifically the first two of the four viewbox properties
<min-y>. This identifies a point inside the viewport frame, relative to the top left corner of the viewport. This
<min-y> coordinate is the starting point of the viewbox area. By default, the viewport and the viewbox overlap each other perfectly and have the same dimensions. It’s pretty much like having the viewbox
<min-y> coordinates set to 0.
Now, let’s change those viewbox coordinate values to
<min-x> = 15 and
<min-y> = 25 and see how that affects our SVG. The viewbox will be offset 15 units to the right and 25 units from the top of the viewport.
Now something special happens. Remember the viewport is the window through which the user views the viewbox. If the viewbox is offset, the user does not – in this context – see bands of emptiness above and to the left of it. Instead, you can imagine that after the offset is defined, the two coordinate systems “snap” together, so that the (min-x, min-y) coordinate of the viewbox (15,25 in our example) “snaps back” to realign with the the (0,0) coordinate of the viewport.
Now you can see that the viewport is filled, but some of the viewbox is outside the frame of the viewport, and cannot be seen by the user. You can move the viewbox/canvas in any direction relative to the 0,0 viewport coordinate. Negative
<min-y> values move the viewbox left or above the viewport frame, hiding the right side or the bottom of the canvas after the “snap”. Now that you understand how the
<min-y> properties are used to position the canvas/viewbox within the viewport, let see what the
<width> and the
<height> properties are for.
2.2 – the width and height properties
By default, the viewbox and the viewport have the same height and width, e.g:
In the viewbox, what those width values actually do is select an area of the graphic, in this case 200 units of rightwards width and 150 units of downwards height, that starts from the
<min-y> coordinate, and stretches that same area of canvas to fill the entire viewport. You don’t see any difference between frame and content, and life is simple. But what if we set our viewbox to half the size of the viewport? In that case, we are saying that in the 200×150 viewport, only 100×75 of the canvas/viewbox will be viewable. This is implemented by scaling up canvas/viewbox units x2, so 100 viewbox units will fill the 200 unit viewport frame, and 75 viewbox units will fill 150 units of viewport.
To summarize this point mathematically:
- Viewport width / viewbox width
- Viewport height / viewbox height
200 / 100 = 2 and 150 / 75 = 2.
To express the same point yet one more way, in this example, 1 viewport unit = 2 viewbox units, so the graphic is 2 times bigger than its original size.
As we saw, if the ratio of the viewbox is the same as the one of the viewport, the graphic will scale to fit inside the viewport. But what happens if the ratio of both views are not proportional? The graphic would become distorted, right? That’s when preserveAspectRatio comes into play.
3 – PreserveAspectRatio
The preserveAspectRatio attribute defines how the viewbox should display itself within the viewport if their dimensions don’t share the same ratio. It takes two types of values separated by a space:
3.1 – <align>
The align properties tell the viewbox how to align itself inside the viewport by combining two values, an X-alignment and a Y-alignment.
The alignment values are:
- xMin : tells the graphic to be align to the left edges of the viewport
- xMid : tells the graphic to be horizontally aligned in the viewport
- xMax : tells the graphic to be align to the right edges of the viewport
- yMin : tells the graphic to be align to the top edges of the viewport
- yMid : tells the graphic to be aligned vertically in the viewport
- yMax : tells the graphic to be align to the bottom edges of the viewport
To set the alignment value you pick one for each, X and Y, ending up with nine positions possible.
3.2 – <meetOrSlice>
The meetOrSlice property tells the viewbox to meet or to be sliced by the viewport edges.
If you set the preserveAspectRatio to Meet, the graphic preserves its aspect ratio and scales so that the longest dimension of the viewbox, width or height, fits within the viewport edges. In this context, the whole viewbox will be visible and there will be some empty space along of the smallest dimension.
On the other hand, if you set preserveAspectRatio to Slice, the graphic keeps its aspect ratio and scales so that the shortest dimension of the viewbox, width or height, fits inside the viewport. A portion of the viewbox is then hidden beyond the viewport.
By setting the preserveAspectRatio to none, you basically tell the graphic: don’t preserve any ratio and stretch to fill the entire viewport, which will result in a distorted graphic if the proportions of the two viewport and viewbox are different.
Understanding the viewbox and the preserveAspectRatio is not an easy task, but it is very cool. It gives you control over what you show and hide, and hopefully you can imagine how that becomes a very interesting design option to have at your disposal.
I encourage you to do some testing on your own, play with the two coordinate systems, to fully see how everything behaves, depending on the attributes you set.
In the next article, I’ll discuss SVG container elements. I really mean it this time! We will see how to group SVG elements and how to define elements that can be reused in our SVG.
See you next time and until then, take care.
P.S.: your neighbor just noticed that he had forgotten his wallet on the dining table before he left. You might want to take a look through that window again. 😉