How to use SVG in HTML: inline, img or CSS background

Three main ways to put an SVG in a web page: an img tag, inline svg markup, or a CSS background. What each allows, with code, sizing and common faults.

Published

There are three main ways to use an SVG in HTML. Link to the file with <img src="logo.svg">, paste the <svg> markup straight into the page (inline SVG), or set it as a CSS background-image. Use <img> for pictures that only need showing, inline SVG when CSS or JavaScript must change the drawing, and a background for decoration.

The methods compared

<img>Inline <svg>CSS background<object>
Cached as its own fileYesNoYesYes
Page CSS can restyle the shapesNoYesNoNo
Page JavaScript can reach the shapesNoYesNoYes, on the same origin
Scripts inside the SVG runNoYesNoYes
Links inside the SVG workNoYesNoYes
Alternative textalt<title> or aria-labelNoneFallback content

1. The img tag

<img src="logo.svg" alt="Plotcaster" width="200" height="60">

This treats the SVG like any other image. The file is cached by the browser, the markup stays short, and alt gives it a text alternative. Setting width and height reserves the space before the file arrives, so the page does not jump.

The browser draws an SVG in an <img> in a restricted mode. Scripts in the file do not run, links in it cannot be clicked, and it cannot load anything else: an external font, stylesheet or picture that the SVG refers to is ignored. Styles and animations written inside the file itself still work.

2. Inline SVG

<svg viewBox="0 0 24 24" width="24" height="24" role="img" aria-label="Warning">
  <path d="M12 2 2 22h20z" fill="currentColor"/>
</svg>

The SVG becomes part of the page. Every shape is an element that CSS can style and JavaScript can change, hover and click included. fill="currentColor" makes the shape take the colour of the surrounding text, which is how to change an SVG’s colour with CSS.

Three things to know:

  • In an HTML page the xmlns attribute is not needed on an inline <svg>. In a separate .svg file it is required.
  • Inline SVG is not cached on its own. An icon pasted into fifty pages is downloaded fifty times, so keep inline SVG for small drawings.
  • If the same SVG is pasted in twice, any id inside it (for a gradient or clipping path) is duplicated, and both copies will use the first one. Give them different ids.

For a decorative icon beside text that already says the same thing, hide it from screen readers with aria-hidden="true" in place of the role and label.

3. CSS background

.hero {
  background: url(waves.svg) no-repeat center / cover;
}

Good for patterns and decoration, which do not belong in the content. The image stays sharp at any background-size. It has the same limits as <img> and no text alternative, so do not use it for anything a reader needs.

Small SVGs can be written into the stylesheet itself as a data URI, which saves a request. SVG to data URI produces one with the characters escaped correctly.

Other ways

<object> loads the SVG as a document of its own, with its scripts and links working:

<object type="image/svg+xml" data="chart.svg">A chart of sales by month</object>

Use it for an interactive SVG that should stay in a separate file. The text inside is shown if the file cannot be loaded. <iframe> and <embed> do much the same and are rarely the better choice.

<use> draws a shape that is defined elsewhere, usually a <symbol> in a sprite file holding many icons:

<svg width="24" height="24"><use href="/icons.svg#search"/></svg>

The sprite is cached once, and an icon drawn with currentColor still takes its colour from the page. The file must come from the same origin as the page: the same scheme, host and port.

Setting the size

An SVG scales cleanly only if its root element has a viewBox. With one, set the size however you like:

.logo { width: 12rem; height: auto; }

Without a viewBox an inline SVG has a fixed size and a smaller box crops it; in an <img> or a background the browser stretches it to the box without keeping its proportions. With neither a size nor a viewBox, browsers draw it at 300 by 150 pixels. SVG viewBox explained shows how to add one.

An inline <svg> is laid out like text, so it sits on the baseline and leaves a small gap beneath when it stands alone. display: block or vertical-align: middle removes the gap.

Which to choose

  • Logo or illustration that never changes: <img>.
  • Icons that change colour with the text or on hover: inline SVG, or a sprite with <use>.
  • Animation driven by page CSS or JavaScript, charts, maps: inline SVG.
  • Patterns and decorative shapes: CSS background.
  • Email: none of these. Most email programs do not show SVG, so convert it to PNG.

Common problems

What you seeCauseFix
Broken image iconThe .svg file lacks xmlns="http://www.w3.org/2000/svg", or the path is wrongAdd the attribute to the root <svg>; check the address
Works on your computer, broken on the serverThe server sends the file with the wrong typeServe .svg as image/svg+xml
Shown at the wrong size, often 300 by 150No size and no viewBoxAdd a viewBox, then set a width
Cropped (inline) or stretched (<img>) when resizedNo viewBoxAdd viewBox="0 0 W H" with the original size
Text in the wrong fontAn SVG in an <img> cannot load web fontsConvert the text to paths in a vector editor
CSS colour has no effectThe SVG is in an <img> or a backgroundInline it, or use a mask
Gap under the imageInline SVG sits on the text baselinedisplay: block
An upload form refuses the fileSVG can carry scripts, so many sites block itUpload a PNG copy

Questions

Is inline SVG bad for page speed? Not for a few small icons: it saves requests. Large drawings repeated on many pages are better as files, which the browser caches.

Do all browsers support SVG? Every current browser supports all the methods here.

Can an SVG be a favicon? Chrome, Edge and Firefox accept one, with <link rel="icon" href="/icon.svg" type="image/svg+xml">. Keep an .ico file as the fallback, since not every browser version still in use takes an SVG icon.

What is inside the markup? Shapes, paths and groups, described in What is an SVG file.