HTML SVG scale to fit

An SVG scales to fit when it has a viewBox and no fixed width or height attribute. Everything else about SVG sizing follows from those two facts.

An SVG will scale to fit its container in HTML when it has a viewBox and no fixed width or height attribute. Add the viewBox, strip the size attributes, size it in CSS instead.

<!-- before: fixed at 512 by 512 -->
<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg"> ... </svg>

<!-- after: scales to whatever contains it -->
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"> ... </svg>
svg { width: 100%; height: auto; display: block; }
Two panels side by side. The left SVG overflows its narrow container, the right one fits it exactly.
Two panels side by side. The left SVG overflows its narrow container, the right one fits it exactly.

What viewBox actually declares

Four numbers, in order: min-x min-y width height. They describe a window onto the drawing's own coordinate space.

viewBox="0 0 512 512" says the interesting part of this drawing runs from 0 to 512 on both axes. The browser then maps that square onto however many real pixels the element occupies.

Without a viewBox, coordinates are read as CSS pixels. The drawing has a fixed intrinsic size and stretching the element just adds empty space around it.

The attributes that fight you

What is on the svg tag Result
viewBox only Scales to the container, keeps its ratio
viewBox plus width and height Fixed size, unless CSS overrides both
width and height only Fixed size, no scaling at all
Neither Defaults to 300 by 150, drawing clipped

The last row catches people who deleted the size attributes without adding a viewBox. The SVG does not disappear, it collapses into a 300 by 150 box and cuts the drawing off.

Getting the viewBox from a file that lacks one

Design exports usually include it. Hand written SVG often does not.

  1. Open the file and find the largest coordinates used by any shape.
  2. Or open it in a browser and read the intrinsic size from dev tools.
  3. Write viewBox="0 0 W H" using the original width and height values, then delete those two attributes.

Step three is the common case. If the tag said width="240" height="96", the viewBox is 0 0 240 96 and the drawing is unchanged.

Dev tools with the svg element selected, showing the viewBox attribute and the computed box it now fills.
Dev tools with the svg element selected, showing the viewBox attribute and the computed box it now fills.

preserveAspectRatio: fit inside or cover

This attribute decides what happens when the container's ratio differs from the viewBox's.

<!-- default: whole drawing visible, empty space on one axis -->
<svg viewBox="0 0 16 9" preserveAspectRatio="xMidYMid meet"> ... </svg>

<!-- cover the box, crop the excess -->
<svg viewBox="0 0 16 9" preserveAspectRatio="xMidYMid slice"> ... </svg>

<!-- stretch, ignore the ratio -->
<svg viewBox="0 0 16 9" preserveAspectRatio="none"> ... </svg>
  • meet is the default and behaves like object-fit: contain.
  • slice behaves like object-fit: cover and is what you want for a decorative banner.
  • none distorts. It is acceptable for a full width gradient or wave, and wrong for anything with text or circles in it.

The xMidYMid part is alignment. Change it to xMinYMin to pin the drawing to the top left instead of centring it.

The same wide SVG in a tall box twice, once with meet showing letterboxing and once with slice filling the box.
The same wide SVG in a tall box twice, once with meet showing letterboxing and once with slice filling the box.

Three sizing recipes that cover most cases

Full width banner, height follows.

.banner svg { width: 100%; height: auto; display: block; }

Icon at a fixed size, colour from the text. Icons are the one case where fixed dimensions are correct. See SVG icons for the set level view.

.icon { width: 1em; height: 1em; fill: currentColor; vertical-align: -0.125em; }

Fill a fixed panel and crop.

.panel { aspect-ratio: 21 / 9; }
.panel svg { width: 100%; height: 100%; }

with preserveAspectRatio="xMidYMid slice" on the SVG itself.

Gaps and overflow

Two problems show up after the scaling works.

A few pixels of space below the SVG. It is an inline element sitting on the text baseline. display: block on the svg removes it.

Shapes spilling past the edge. Something is drawn outside the viewBox window. SVG clips to the viewBox by default, but overflow: visible in a stylesheet turns that off. Check for a blanket * { overflow: visible } rule.

Reserving the space before it loads

An SVG with a viewBox has an intrinsic ratio, so the browser can reserve the right height before the file arrives. That only holds for inline SVG and for an <img> whose file carries the viewBox.

For anything loaded late, state the ratio yourself so the page does not jump when it lands.

.figure svg, .figure img { width: 100%; height: auto; aspect-ratio: 16 / 9; }

The same line prevents the layout shift that shows up as content moving under the reader's cursor a second after the page appears.

Scaling inside a canvas or an image

If the SVG is loaded with <img>, the same viewBox rule applies, and you size the img like any picture with object-fit. You lose CSS access to the shapes, which matters if you also want to change the colour.

For a favicon the viewBox is what lets one file serve 16px and 180px without a second export.

Checking it at more than one width

Resize the window. That catches most of it. The rest shows up when the page is opened somewhere other than your editor, usually because the stylesheet did not travel and the SVG fell back to its attribute size.

The page pasted into a NOS document, resized narrow. The SVG follows the column width.
The page pasted into a NOS document, resized narrow. The SVG follows the column width.

Paste the HTML into a NOS document and open the link on a phone. The markup renders as written, so what you see there is what the reader gets.

A wrong viewBox is obvious in one glance at a narrow width. Fixing it is an edit to the same page, and the link you already sent points at the fix.

Quick reference

Symptom Cause Fix
Stuck at one size width and height attributes Remove them, size in CSS
Collapses to a small box No viewBox Add viewBox="0 0 W H"
Letterboxed inside its container Ratio mismatch, meet Use slice, or match the ratio
Distorted preserveAspectRatio="none" Remove it
Small gap underneath Inline element baseline display: block
Shapes spill outside overflow: visible inherited Remove the blanket rule

Questions people ask

Why is my SVG stuck at one size?

It has width and height attributes on the svg tag, and those win until CSS overrides them. Remove them or set width to 100 percent in CSS. If it still refuses to scale, the svg has no viewBox, so the browser has no coordinate system to stretch.

What does viewBox do exactly?

It declares the coordinate window of the drawing, written as min-x min-y width height. The browser maps that window onto whatever size the element ends up being. Without it, the coordinates are treated as pixels and nothing rescales.

How do I make an SVG fill a box and crop the overflow?

Set preserveAspectRatio to a slice value, for example xMidYMid slice, and the drawing covers the box with the excess cut off. The default is meet, which fits the whole drawing inside and leaves empty space.

Does scaling an SVG lose quality?

No. The shapes are recalculated at the rendered size, so edges stay sharp at any scale. Only embedded raster images inside the SVG will soften, since those are still pixels.

Keep reading