SVG for speed: icons, logos and illustrations
When SVG is the lightest choice, four ways to put it on a page, how to shrink files with SVGO, how to use a sprite, and the mistakes that make SVG heavy.
In this guide
What SVG is good at
MDN describes SVG as an XML-based vector format that stores an image as drawing commands for shapes, lines, colors and filters. It calls SVG ideal for diagrams, icons and other images that can be drawn accurately at any size, and a good choice when the display size is unknown or varies, since SVG scales smoothly. It adds that SVG is not generally useful for bitmap or photographic images, although a bitmap can be placed inside an SVG. An SVG that wraps a photo is the photo's bytes plus extra markup. Use a photo format for that. See image formats.
SVG is text, so it also compresses well on the way to the visitor. MDN notes that SVG can be compressed in transit with HTTP compression. The Web Almanac counts SVG among the text formats that gain from it. See text compression.
SVG is also the usual cure for two heavy habits: PNG logos exported at several sizes, and an icon font that carries hundreds of icons when the page uses a handful. See web fonts and speed.
Four ways to put SVG on a page
| Way | Good for | Watch out for |
|---|---|---|
<img src="logo.svg"> | Logos and illustrations used on many pages | It is an image: MDN says scripts are disabled and external resources, such as stylesheets, are not loaded. The page's CSS does not reach inside |
Inline <svg> in the HTML | A few small icons you want to style or animate | The code travels inside every page's HTML and is not cached on its own. Repeated many times, it grows the DOM |
A sprite: <use href="icons.svg#id"> | Many icons used across the site | The icons appear when the sprite file arrives. MDN says the same-origin policy may apply |
CSS background-image: url(...) | Decorative shapes | The browser finds it only after reading the CSS |
For most sites the best mix is an img for the logo, inline SVG for the two or three icons in the first screen, and a sprite for the rest.
Make the file small
Files exported from vector editors carry leftovers. The README of SVGO, a free Node.js optimizer, says they usually contain a lot of redundant information: editor metadata, comments, hidden elements, and default or suboptimal values that can be removed or converted without changing how the image looks.
npm install -g svgo
svgo logo.svg -o logo.min.svgI ran SVGO 4.1 on a hand-made 1.9 KB file written in the style of an Inkscape export. With the default settings it produced a 0.5 KB file. It removed the XML declaration, the comment, the editor's namespaces and settings, the metadata, an empty group and the "Created with" description. It shortened the path data. It kept the viewBox and the title. Your files will differ, and this one is only an example.
Three things in the defaults deserve a look:
- Ids. The default preset includes
cleanupIds, which its source describes as removing unused ids and minifying used ones. In my test,linearGradient1234becamea. Two inline SVGs on one page that both useacan collide, and any CSS or script that targets an id stops working. Turn that plugin off and addprefixIds, which gave each id a prefix taken from the file name. - Descriptions. The
removeDescplugin removes only empty descriptions and editor boilerplate by default, because a description can serve accessibility. - Units. My file's
width="64mm"came out as a plain number of pixels. Set the size you want yourself.
// svgo.config.mjs
export default {
plugins: [
{ name: 'preset-default', params: { overrides: { cleanupIds: false } } },
'prefixIds',
],
};Run it with svgo logo.svg --config svgo.config.mjs -o logo.min.svg. Keep the original export, and look at the result before you publish it. An optimizer cannot remove detail that you drew, so fewer points in a path and fewer layers in the source still help most.
Size it and place it
- Give it a size. Put
widthandheighton animg, or on the inlinesvg, so the page does not move when it loads. MDN notes that an SVG image has no intrinsic dimensions when its rootsvgelement has nowidthorheight, so animgthat points to one needs the attributes. An inline SVG can take its ratio from theviewBox, which MDN defines as the position and size of the drawing area that is stretched to fit its container. See image width and height. - Lazy-load the ones below the first screen. An
imgthat points to an SVG can useloading="lazy"like any other image. See lazy loading. - Mind the LCP. The elements that can be the Largest Contentful Paint include an
imageinside an SVG, but not drawn shapes. An SVG that wraps a photo can therefore be the LCP element. See Largest Contentful Paint. - Keep inline SVG small. It is part of the HTML, which the visitor must download first.
Use a sprite for many icons
MDN says the symbol element defines graphic templates that a use element draws, and that use can load them from an external file by naming the file and a fragment. Put the icons in one file, and the browser fetches and caches it once:
<!-- /img/icons.svg -->
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="check" viewBox="0 0 24 24"><path fill="currentColor" d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z"/></symbol>
<symbol id="close" viewBox="0 0 24 24"><path fill="currentColor" d="M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z"/></symbol>
</svg>
<!-- in the page -->
<svg class="icon" width="24" height="24" aria-hidden="true"><use href="/img/icons.svg#check"></use></svg>I tested this in headless Chromium: two icons made one request for the sprite, and each icon took the color of its own svg element through currentColor. MDN warns that the copied content is not exposed to CSS, and that styles reach it only through inheritance, so set colors with properties that inherit. Serve the sprite from your own domain, because MDN notes that browsers may apply the same-origin policy to use.
The icons draw when the sprite arrives. For an icon in the first screen, inline that one instead. A decorative icon takes aria-hidden="true". An icon that carries meaning needs a short title as the first child of the svg, which MDN says gives an accessible, short-text description, and role="img", because web.dev's accessibility course says assistive technology skips inline SVG by default. If visible text already describes it, point to that text with aria-labelledby. For an img that points to an SVG file, MDN advises adding role="img" too, because of a VoiceOver bug.
Serve it well
- Compress it. Check that
image/svg+xmlis in your server's list of compressed types. The server examples in the text compression guide include it. - Send the right type. MDN gives the MIME type as
image/svg+xml. - Cache it. A separate SVG file can have a long cache life and its own versioned name. Inline SVG is cached only with the HTML. See HTTP caching headers.
When SVG is the wrong tool
- Photographs and detailed artwork. Use a photo format.
- A diagram with text that relies on your web font, used in an
img. MDN says an SVG used as an image cannot load external resources. Draw the text as shapes, or inline the diagram. - Hundreds of copies of the same inline icon. Use a sprite. See DOM size.
How to check
- List the SVG files. In the Network panel, filter by
mime-type:image/svg+xmland sort by size. A file in the hundreds of kilobytes is worth a look. See the Network panel. - Check the headers of each:
Content-Encoding,Content-TypeandCache-Control. - Do not rely on Lighthouse for this. Its Improve image delivery check skips files of the type
image/svg+xml, so a heavy SVG is never flagged. - See the size that travels. A command such as
gzip -9 -c logo.svg | wc -cshows a close estimate of the compressed size. - View the page source. Count the inline SVGs and look for repeated ids.
Mistakes to avoid
- A photo inside an SVG.
- Files straight from the editor, with metadata and hidden layers.
- Two inline SVGs that share ids after minifying.
- No width and height on the element.
- A sprite from another domain.
- SVG left out of the compression list on the server.
- Traced artwork with thousands of points where a simple shape would do.
Check your own page
Run the free audit and note the largest images. Then filter the Network panel by mime-type:image/svg+xml and sort by size. Optimize the biggest file with SVGO, compare the sizes and confirm that it looks the same.
Sources
- Images in the web.dev accessibility course: inline SVG and assistive technology.
- MDN: the img element, the SVG section of the image file type guide, SVG as an image, the use element, the symbol element, the viewBox attribute and the SVG title element.
- SVGO: the README and the source of the default preset and its
cleanupIds,removeDescandprefixIdsplugins. - Page Weight chapter, Web Almanac 2025: HTTP compression and the text formats that gain from it.
- image-delivery-insight.js in Lighthouse 13.5 and ImageDelivery.ts in the Chrome DevTools frontend: the check that skips SVG.
Start here
Free website audit
Live Google data for any public page: mobile and desktop.
Mobile + desktop · Lighthouse lab test · Real-user Chrome data when Google has it
Rather have this done for you? Speed optimization · Book a call