Transforms
On This Page
- Introduction
- The Group Tag
- Translate
- Rotate
- Scale
- Scaling with Width and Height
- Multiple Transforms and Order of Operation
- Skew
- When Not to Use Transforms
Introduction
Now that we have shapes, paths, and styling under our belts, it would be quite ideal to learn how they can all be moved around, rotated, and scaled after creating them. That's where SVG transforms come into play.
Transforms do not change the original coordinates of a shape. They are applied at render time, meaning the shape's underlying x, y, and path values remain the same. This is why multiple transforms can be stacked and reordered without rewriting the drawing itself. This is a really powerful feature of SVG that can save a ton of time and reduce headache potential overall when needing to tweak different shapes or whole sections of your drawings.
The Group Tag
The Group tag, represented as <g> in SVG code, allows you to wrap shapes up into groups so that you can keep them organized and also perform actions to all of the grouped shapes all at once.
Groups can even be used to apply CSS styling to all the shapes within them at once. Here's an example of some grouped shapes:
<g stroke="green" stroke-width="4" fill="gold">
<rect x="10" y="10" width="100" height="100"/>
<circle cx="170" cy="60" r="50"/>
<path d="M 230, 110
H 330
L 280, 10 Z"/>
</g>
Here we have opened the group using the <g> tag and added some styling to give the shapes in the group a green outline and a gold infill. The styling is applied just as you have been doing with any other shape.
We have a square, circle, and a triangle drawn in a row using <rect>, <circle>, and <path> shapes respectively. Note how none of the shapes have any styling added. The styling in the group tag is applied to everything within the group, and the final line closes the group.
This is very useful if you want to apply uniform styling to a lot of shapes or parts of your drawing, and greatly reduces the amount of code you'll need to write per shape. With this feature of groups in mind, we can also consider how they can be used to move or transform whole groups of shapes at once.
Translate
To move a shape or a group about the canvas, we use the translate transform attribute. This takes an x and y value separated by whitespace, and the values are relative to the original position of the shape or group.
<rect x="0" y="0" width="100" height="100" fill="green" transform="translate(30 40)"/>
Note the syntax of the transform attribute and how the translate parameter is added into it. Our green square starts off in the top left corner of the canvas, but the translate values move it over 30 units on x and 40 units down on y.
When adjusting or tweaking your drawings, adding translate can help you quickly nudge a shape into the right position without having to redraw it or alter a bunch of path numbers or shape attributes.
If you don't add a y value, it gets interpreted as 0 on y. So translate(30) will only move a shape 30 units over on x but leave the y value alone.
Rotate
The rotate parameter lets you set how much a shape is rotated by degrees. It's very important to note that if only the degrees are entered, the shape will be rotated as if from the top-left origin corner of the canvas, so it's a good idea to add in x and y coordinates after the degrees to specify the pivot point around which the shape is being rotated.
<rect x="50" y="50" width="50" height="50" transform="rotate(45, 75, 75)"/>
Here we are drawing a 50x50 square which is starting out with its top-left corner at 50, 50 on the canvas. This means that the direct center of the square is at 75, 75.
Knowing this, we can add that to the rotate parameter. The first value is the amount of degrees to rotate the shape, and the following numbers separated by a comma are the x and y pivot coordinates which the shape is rotating around.
In this instance, a 45 degree rotation around the 75, 75 point will rotate the square around its center, making it look like a diamond instead of a square.
Scale
The scale parameter increases or decreases the overall size of a shape or group, but it's extremely important to note that the scale origin is always set to the top-left corner of the canvas.This means the shape will appear to slide toward or away from the top-left corner depending on the scale value. A translate transform is then used to reposition the scaled shape back into place. The amount to translate will be the inverse of however much you scale a shape. Check out this example:
<rect x="100" y="100" width="100" height="100" transform="scale(0.5)"/>
This 100x100 square is being scaled down by 0.5 units, or by half. This means that the square will turn into a 50x50 square and that its top-left corner/position will move towards the top-left corner of the canvas by 50 units on both x and y.
To move the square back to its original position, we have to do a little math to get the coordinates just right. Subtract the product of the original position and the scale value from the original position number, and then divide that result by the scale value.
<path id="original" d="M 100, 100
L 200, 100
L 200, 30 Z" fill="green"/>
<path id="mirror" d="M 100, 100
L 200, 100
L 200, 30 Z" fill="green" transform="translate(200 0) scale(-1,1)"/>
In our example, this looks like: (100 - (100 * 0.5))/0.5. You end up with 50/0.5, which turns out to be 100, so the translate values we'd use are translate(100, 100). This will work when either increasing or decreasing the size, just plug in your position value and scale and off you go! Just remember to do this for both x and y positions if they are different values.
If you mirror a group tag, note that the origin of the group is still 0, 0. If the first point of a path in a group is 100 units on X, scaling the group by -1 on X will put the mirror point at -100 on X, or way off the canvas to the left.
In these instances, the math is easier as you just have to double the original X value and use that for the x coordinate in the translate value to shift the mirror back into the visible part of the canvas, then adjust your positioning from there. Note that in the transform attribute, the translate function should appear before the scale function when mirroring.
Scaling with Width and Height
Let's say you've built your entire drawing but realize that you want to play with the entire scale overall for output. Rather than using the scale transform, you can accomplish this task using a combination of the viewBox, the SVG tag width and height attributes, and nesting one SVG tag within another!
The viewBox Returns
Yes, this is a callback to the Setup page where we discussed the viewBox attribute. This attribute takes 4 values, the first being the x and y coordinate of the canvas origin (top-left corner of the canvas), and the last two values are the width and height of the viewBox. Here's code for a 100x100 unit viewBox:
<svg viewBox="0 0 100 100"...>
The viewBox designates the actual canvas borders for your drawing, so anything drawn outside of that 100x100 box will be cut off. Now, let's say you make a great drawing within that 100x100 space but want to blow it up to 500x500 units. You use the width and height parameters to do this, altering the output size of the SVG file itself without messing up any of the values in your drawing.
<svg viewBox="0 0 100 100" width="500" height="500"...>
Note: Pay careful attention to the width and height values as compared to the size set in the viewBox. You need to make sure that the ratio of the values is maintained, otherwise your drawing will get squashed or stretched!
For example, if your viewBox is set to "0 0 100 200", you would multiply the viewBox width and height values by 2 if you wanted to double the size of the drawing. Those values would go in the SVG canvas width and height attributes, like so:
<svg viewBox="0 0 100 200" width="200" height="400"...>
Our previous 500x500 example is easy since the drawing and the scaled output are squares, but if your drawing is set within a viewBox rectangle, make sure your final width and height output values are correct.
Use scale() when you want to change the proportions of shapes inside the drawing, and use width, height, and viewBox when you want to change the size of the drawing as a whole.
Nesting SVGs
Nice, but now you want to center this blown up drawing on a sheet of letter paper. This is where we can use SVG nesting in our files. We can wrap our original SVG tags within another set of SVG tags, set the outer SVG width and height to 850x1100 to make it letter paper sized, and use a translate group transform to center the drawing SVG, like so:
&svg id="finalOutput" width="850" height="1100" ... >
<g transform="translate(175, 300)">
<svg id="drawing" viewBox="0 0 100 100" width="500" height="500"...>
...all your SVG drawing code...
</svg>
</g>
</svg>
We do have to do a little math here to center our drawing SVG within the finalOutput SVG. Remember that half of 850x1100 is 425x550. Half of 500 for our drawing is 250. We subtract 250 from the 425x550 values to find the values we need to put into the group translate attribute.
425 minus 250 is 175 for x, and 550 minus 250 is 300 for y. The drawing SVG is wrapped in a group tag that has the translate transform all set up with those values, so translate(175, 300).
This centers our 500x500 drawing right in the middle of our letter paper. Pretty spiffy! Remember to account for different sizes of the canvas if your drawing is not a perfect square.
Multiple Transforms and Order of Operation
Note that we used two transforms within the transform attribute. You can add multiple attributes here within the transform quotes separated by a space.
Order of operations is important, and SVG will perform transforms on the shape in the order in which they appear within the transform attribute. Scaling first and then translating will look different than translating first and then scaling.
A common use case for this is building a shape and then duplicating and flipping it for symmetry, such as making legs and arms for a character. This would involve translating the shape and then "mirroring" the shape by flipping it across the Y axis.
If only mirroring across the X axis for horizontal symmetry, make sure to use scale(-1, 1) so that the Y axis scale is not affected. Adding this transform to a shape will make it disappear from the canvas since the x position value has been made negative. For example, a shape 300 units over on x will have its mirrored duplicate at -300 units.
Knowing this, a translate transform would have to be added before the scale transform to prepare and shift the shape into a position where mirroring it would put it back into the visible canvas. This is done by doubling the x value of the original shape. So transform=" translate(600)scale(-1, 1)" would mirror the original shape that was at 300 units on x and bring the mirrored copy next to it.
If flipping/mirroring a shape vertically across the X axis, just perform the same operation and account for the x values not being affected, such as transform="translate(0 600) scale(1, -1)".
Skew
Skewing is a transform that shifts the top part of the shape away from the bottom of the shape at a specified angle on the X axis, or shifts the sides of the shape away from each other along the Y axis.
Imagine that you have a Slinky in front of you. If you held the bottom of the Slinky in place and slid the top of the Slinky to the left or right, you are essentially Skewing the shape of the Slinky. The top and bottom remain parallel to each other, but the sides shift and stretch the further apart you move the top from the bottom.
The x or y values of the shape do not change uniformly when skewing; instead, points are shifted proportionally based on their distance from the opposite edge.
To skew a shape along the x axis, or left and right, we use the skewX() transform. We use skewY() for the y axis, or skewing up and down. Place the amount you want to skew a shape within the parentheses in the form of a number which represents an angle in degrees.
<rect x="10" y="10" width="100" height="100" fill="green" transform="skewX(15)"/>
<rect x="130" y="10" width="100" height="100" fill="gold" transform="skewY(15)"/>
The green box is slightly skewed to the right, with the top of the box being slid over so that the sides of the box make a 15° angle between the bottom and top edges.
The gold box is skewing on the y axis, with the right side of the box sliding lower than the left, creating a 15° slope with the top and bottom edges.
Note that this will distort anything within the shape or the group that you are skewing. Remember that the edges being skewed don't get closer or farther apart but are just sliding along an axis, so everything between them will stretch at the skewing angle.
When Not to Use Transforms
While transforms are a powerful feature of SVG, they are not always the best tool for every situation. Knowing when not to use transforms can make your drawings easier to understand, easier to maintain, and more predictable for output. As Uncle Ben said in Spiderman, "with great power comes great responsibility."
If the exact geometry of a shape matters, such as in diagrams, grids, charts, or tactile layouts where spacing and alignment carry meaning, it is often better to define the shape directly using coordinates rather than relying on transforms.
Transforms should also be avoided as a substitute for constructing shapes properly. Scaling, rotating, or skewing a shape can change its appearance, but it does not change the underlying geometry. When precision or consistency is important, it is usually clearer to build the shape with the correct dimensions and coordinates from the start.
When the goal is to change the overall output size of a drawing, transforms are usually the wrong approach. In these cases, using the viewBox along with the width and height attributes of the SVG tag is more reliable and avoids distorting the drawing.
Finally, excessive use of transforms can make SVG files harder to read and reason about later, especially when multiple transforms are stacked or nested. If a drawing becomes difficult to understand without mentally undoing transforms, that is often a sign that explicit coordinates would be the better choice. From experience, nothing is worse than having to backtrack across multiple transforms on a shape when trying to undo a mistake or when doing very finite tweaks.
As a general rule, use transforms to reposition, reuse, or adjust existing shapes, but rely on coordinates and viewBox-based scaling to define the structure and size of the drawing itself.