viewBox

How the SVG ViewBox works

00

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.

01

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.

02

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.

Inline SVG

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.

03

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>
04

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.

Landscape seen through a telescope

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>
05

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.

06

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>
07

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>
08

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>
  );
}
09

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>
Remove
10

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

/myCircle.png
/myCircle.svg
A circle rendered as a raster. Showing pixelationA circle rendered as a vector. Showing no pixelation
/index.html
<body>
	<img alt="Circle" src="
/myCircle.svg
" /> </body>
/myCircle.svg
<?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>
/index.html
<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>
305050606030300102030405060708090100010203040506070809010000100100