Raster vs. Vector
On a web page, we can render different types of images. The most common are .jpg, .png, .webp and .svg. SVG is unique because it is a vector image. While the others are raster. A raster image is pixel based. A vector is math equation based. One advantage of vectors is they never have jagged edges. Even when rendered larger than the original asset.
Render Image
We can render an .svg just like any other image type.
Using the img
element.
However, there is another way that opens up creative possibilities.
Click the .svg file name to open it.
Inline SVG
We see it contains XML-based markup code. We can copy the SVG element from that file and paste it into a .html page.
This is called inlining an svg. The image will render the same as before. But, now we can access the elements that make up the image. In this example, a circle. We can manipulate it and make it interactive using CSS and JavaScript.
Performance Tip: When you enter a web page URL in the browser, it makes
a request for a HTML file. If the file contains an img
element, the
browser will make another request. To get the image file.
With an inline SVG. The image loads at the same time as the HTML code. There
is no need to make the additional request. Providing a faster UX (User Experience).
This does come with a cost. It increases the size of the .html
file. It might
not be ideal for every .svg
image. But could be a good option for images positioned
above-the-fold.
Coordinates
A SVG element provides a 2D canvas of infinite size.
Its children (our circle) are positioned using an xy coordinate system.
The centre of our circle is positioned at x: 50, y: 50
and has a radius of 30
.
<svg viewbox="0 0 100 100">
<circle
\t\tcx="50"
\t\tcy="50"
\t\tr="30"
/>
</svg>
View Box
The viewBox
determines what part of the canvas the user will see.
Think of the canvas as a landscape and the viewBox a telescope.
The user can only see part of the landscape.
The area the telescope is pointing at.

The viewBox
is made up of four numbers.
The first two are the x, y
coordinate of its top-left corner.
The last two are its width and height.
<svg viewbox="0 0 100 100">
<circle
\t\tcx="50"
\t\tcy="50"
\t\tr="30"
/>
</svg>
Pan & Zoom
<svg viewbox="0 0 100 100">
<circle
\t\tcx="50"
\t\tcy="50"
\t\tr="30"
/>
</svg>
If we change the x
value. The telescope will move horizontally.
If we change the y
value. The telescope will move vertically.
Changing the width
and height
zooms in or out.
Zoom to Square
By default, the telescope will zoom the top-left corner.
We can zoom anywhere on the canvas by selecting a rectangular space.
Then moving the current viewBox
values towards its values.
In this example, we selected x:60, y: 60, width:30, height: 30
.
<svg viewbox="0 0 100 100">
<circle
\t\tcx="50"
\t\tcy="50"
\t\tr="30"
/>
</svg>
Animate
We can also animate the zoom using the animate
element.
An SVG element that provides a way to animate an attribute.
Move your mouse over the image to start the animation.
One advantage of animating this way is it requires no JavaScript.
<svg viewbox="0 0 100 100" id="mySvg">
<circle
\t\tcx="50"
\t\tcy="50"
\t\tr="30"
/>
<animate
attributeName="viewBox"
to="60 60 30 30"
dur="1s"
fill="freeze"
begin="mySvg.mouseenter"
/>
</svg>
React Spring
For animating in a React environment. We can use an animation library like react-spring.
const viewBox = {
initial: [0, 0, 100, 100],
zoom: [30, 30, 60, 60]
}
function MyComponent() {
const [coords, setCoords] = useState(viewBox.initial);
const { wxyz } = useSpring({
wxyz: coords
});
const viewBoxStr = wxyz.to(
(w, x, y, z) => `${w} ${x} ${y} ${z}`
);
return (
<animated.svg
viewBox={viewBoxStr}
onMouseEnter={() => setCoords(viewBox.zoom)}
onMouseLeave={() => setCoords(viewBox.initial)}
>
<circle cx="50" cy="50" r="10" />
</animated.svg>
);
}
Scaling Stroke
One thing to note.
If the viewBox width or height doesn't match the SVG element, children stroke widths' will scale.
This could be a problem when zooming.
We can prevent this by adding vector-effect="non-scaling-stroke"
to each child.
Preventing stroke scale.
The circle's stroke is set to 4px
.
Remove the vector-effect
property to see it scale bigger than 4px
.
If you reduce the size of the SVG element to 100px
.
The stroke will return to 4px
.
<svg viewbox="0 0 100 100">
<circle
\t\tcx="50"
\t\tcy="50"
\t\tr="30"
fill="none"
\t\tstroke="#424242"
\t\tstroke-width="4"
vector-effect="non-scaling-stroke"
/>
</svg>
Use Case
One use case for manipulating the viewBox
is navigating around a 2D map.
Instead of showing the whole map at once.
We can use the viewBox
to reveal only part of the map.
visible viewBox: 300 200 300 200
<body>
<img alt="Circle" src=" " />
</body>
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<circle
cx="50"
\t\tcy="50"
\t\tr="30"
\t\tfill="none"
\t\tstroke="#424242"
\t\tstroke-width="4"
\t\tvector-effect="non-scaling-stroke"
/>
</svg>
<body>
<svg viewBox="0 0 100 100">
<circle
cx="50"
\t\t\tcy="50"
\t\t\tr="30"
\t\t\tfill="none"
\t\t\tstroke="#424242"
\t\t\tstroke-width="4"
\t\t\tvector-effect="non-scaling-stroke"
/>
</svg>
</body>