The coordinate system
Every SVG element is positioned within a user coordinate system. By default, the origin (0, 0) is at the top-left corner of the SVG viewport. The positive X axis points right, and — unlike a standard math coordinate system — the positive Y axis points down. This is the same convention used by HTML's Canvas API and most 2D drawing systems.
Coordinates are measured in user units. Without a viewBox, one user unit equals one CSS pixel when the SVG is rendered at its intrinsic size. But this 1:1 mapping is just a default — viewBox lets you change the scale and origin freely.
Visualizing the default coordinate space
The point at (100, 50) is 100 units to the right and 50 units down from the origin. If you are used to math graphs where positive Y goes up, remember: in SVG (and most screen coordinate systems) increasing Y moves you toward the bottom of the viewport.
viewBox="min-x min-y width height"
The viewBox attribute maps a rectangular region of user space onto the rendered viewport. Think of it as a camera: it defines which portion of the infinite user coordinate plane gets shown, and the SVG stretches or compresses that region to fill the rendered size.
The four numbers are: the left edge of the window (min-x), the top edge (min-y), the width of the window in user units, and the height of the window in user units. A smaller width/height means you are zooming in on a smaller region — the same content appears larger on screen.
Same content, two different viewBoxes
The two SVGs below contain identical content — a circle at (50, 50) with radius 30, plus a label. The only difference is the viewBox. The first uses 0 0 100 100 (the whole 100×100 space), the second uses 25 25 50 50 (a cropped 50×50 window centered on the circle). Both SVGs are rendered at the same screen size, so the second appears twice as large.
The circle and its label share identical SVG coordinates in both cases. Only the viewBox changed — but that is enough to zoom in by 2×. This is the key insight: viewBox separates "what the drawing looks like in user space" from "how large it appears on screen".
Panning with min-x and min-y
Non-zero min-x and min-y shift the visible window within user space — effectively panning the camera. A viewBox="50 0 100 80" would show the region starting 50 units from the left, cutting off the leftmost content and showing what is further right.
Responsive SVG
By default, an SVG with explicit width and height attributes renders at a fixed pixel size — it does not scale with its container. To make an SVG fluid, you have two options:
- Remove the
widthandheightattributes entirely — the SVG will try to fill its container. - Set
width="100%"on the SVG element (and optionallyheight="auto"in CSS), relying onviewBoxto maintain the aspect ratio.
In both cases, viewBox is required to preserve the aspect ratio. Without a viewBox, the browser has no idea what proportions to maintain when it scales the SVG.
A full-width responsive SVG
This SVG has no fixed width or height attributes — instead it relies on viewBox="0 0 400 100" to establish a 4:1 aspect ratio. The inline style="width:100%;height:auto" tells the browser to match the container width and compute the height proportionally. Text and shapes remain perfectly sharp at any scale because SVG is vector — unlike a raster image, there is no pixel grid to worry about.
preserveAspectRatio
When the aspect ratio of the viewBox does not match the aspect ratio of the rendered width/height, SVG needs to decide what to do with the extra space. The preserveAspectRatio attribute controls this behavior.
It takes two parts: an alignment keyword (e.g. xMidYMid) and a meet-or-slice keyword:
meet(default) — scale the viewBox uniformly to fit entirely within the viewport (letterboxing). The drawing is never cropped.slice— scale the viewBox uniformly to fill the entire viewport (no letterboxing). Content outside the viewport is cropped.none— stretch the viewBox non-uniformly to fill the viewport exactly. The drawing is distorted.
The alignment keyword controls where the scaled content is placed when there is leftover space (with meet) or which part is centered when content overflows (with slice). The most common values are xMidYMid (center on both axes — the default), xMinYMin (top-left align), and xMaxYMax (bottom-right align).
Same graphic, three different preserveAspectRatio values
Each SVG below has a square viewBox="0 0 100 100" but a wide rectangular rendered size (160px × 100px). The graphic is a circle with a cross — intentionally reaching all four edges so the effect of cropping vs. letterboxing is clearly visible.
xMidYMid meet — fit (letterbox)xMidYMid slice — fill (crop)none — stretch (distort)
In the meet case the circle fits completely within the frame — the gray background shows the letterbox bars on either side. In the slice case the circle is scaled up until it fills the width, and the top and bottom of the circle are cropped by the viewport. In the none case the circle is stretched horizontally into an ellipse to fill the 160×100 rectangle — the aspect ratio is destroyed entirely.
In practice you will almost always want xMidYMid meet (the default) or xMidYMid slice. The none value is rarely intentional — it is the equivalent of setting object-fit: fill on an <img>.