SVG (Scalable Vector Graphics) stores an image as drawing instructions: a rectangle here, a circle there, a path with these curves, filled with this colour. PNG, JPG and WebP store a grid of pixels. That one difference explains almost everything below: when SVG is tiny and sharp, when it is the wrong tool, and why it needs more care than a PNG when you accept it from strangers.
A real measurement: one logo, four sizes
Claims like "SVG is smaller" are easy to make and rarely shown, so here is a test I ran on a Mac while writing this.
I wrote a simple logo by hand: a blue rounded square, a white ring and a white check mark. Three shapes, 256 by 256 units. I padded it the way design tools tend to (an XML declaration, a comment, a group with a layer id, coordinates written as 128.000), then:
- rasterised it to PNG at 256, 512 and 1024 pixels square with macOS
sips(sips -s format png -z 512 512 logo.svg --out logo_512.png) - converted each PNG to lossless WebP with
cwebp -lossless -z 9(libwebp 1.6.0) - ran the SVG through SVGO 4.0.0 with its default settings
- measured gzip size with
gzip -9 -c file | wc -c, because web servers normally compress SVG (it is text) but not PNG or WebP (already compressed)
| File | Bytes |
|---|---|
| SVG as written | 703 |
| SVG as written, gzipped | 393 |
| SVG after SVGO | 386 |
| SVG after SVGO, gzipped | 248 |
| PNG 256 x 256 | 11,066 |
| PNG 512 x 512 (2x) | 26,131 |
| PNG 1024 x 1024 (4x) | 65,446 |
| Lossless WebP 256 x 256 | 2,778 |
| Lossless WebP 512 x 512 | 6,356 |
| Lossless WebP 1024 x 1024 | 12,970 |
So for this logo, the optimised, gzipped SVG is 248 bytes and covers every size. The 2x PNG you would ship for high-density screens is about 100 times bigger, and even lossless WebP, which is very good at flat colour, is around 25 times bigger at 2x. The PNGs came straight out of sips without a PNG optimiser, so a tool like oxipng would shave some off them, but not two orders of magnitude.
Two caveats so you do not over-read this. A logo with three shapes is the best case for SVG. And at these sizes all the files are small in absolute terms; the difference matters most when you have dozens of icons, or when the logo is the biggest thing above the fold.
When SVG is the right choice
- Logos, icons and simple illustrations. Flat shapes and a handful of colours. This is what the format was made for.
- Anything shown at more than one size. One SVG replaces the 1x, 2x and 3x PNG set, and stays sharp when someone zooms the page.
- Graphics that need to change colour. Dark mode, hover states and themes can be handled in CSS (see
currentColorbelow) instead of exporting a variant for each. - Charts, diagrams and UI decoration. These are often generated by code anyway, and text inside an SVG stays real text that can be selected and found with Ctrl+F.
- Simple animation. Inline SVG can be animated with CSS or JavaScript, for example a check mark drawing itself.
When SVG is the wrong choice
- Photographs. A photo has no clean edges, just millions of slightly different pixels. Use JPG, WebP or AVIF. Tracing a photo into SVG produces a large file that looks posterised, and an SVG that simply wraps an embedded JPG (a
<image href="data:image/jpeg;base64,...">) is just the JPG plus about 33% base64 overhead. - Very complex artwork. Detailed illustrations with thousands of paths, gradients, blurs and filters cost CPU every time they are drawn. File size can still be fine. As a stress test I generated an SVG of 5,000 randomly placed, randomly coloured circles: 267,991 bytes raw and 60,147 gzipped, against 476,769 bytes for a 512 pixel PNG and 320,658 for lossless WebP. Random dots are a worst case for PNG too, so this does not mean complex SVG is always small. The practical point is to look at render cost as well: if a large, detailed SVG makes scrolling janky on a mid-range phone, a raster export at the size you actually display may be the better trade.
- Email. Support for SVG in email clients is poor (Gmail, for one, does not display it). Use PNG in newsletters and signatures.
- Social preview images. Open Graph and X card images should be PNG or JPG. Platforms generally do not render an SVG
og:image.
If you need a PNG of an SVG for one of those cases, the SVG Code to Image tool renders SVG markup to PNG, JPG or WebP at the size you pick, in your browser. For moving between raster formats there is the Image Converter.
Exporting a clean SVG
Most bloated SVGs come from export settings rather than from the artwork. Before exporting from Figma, Illustrator, Inkscape or Affinity:
- Convert text to outlines if the font will not be available where the SVG is used. Otherwise the browser substitutes a fallback font.
- Flatten what you can. Merge shapes that share a fill, remove hidden layers and empty groups.
- Avoid embedding raster images unless the design needs one. A single pasted bitmap defeats the purpose.
- Keep the
viewBox. It is what lets the SVG scale. You can drop fixedwidthandheightattributes and size it with CSS instead. - Use "presentation attributes" or inline styles rather than a
<style>block if the SVG will be inlined into a page, because class names in a<style>block apply to the whole page and can clash between two inlined icons.
If you are starting from a raster logo and have no vector original, the SVG Converter traces it into paths. Tracing works well on high-contrast, flat artwork and poorly on photos. Note that it uploads the image to our server, where the potrace engine does the tracing.
Optimising with SVGO
SVGO is the standard optimiser. It removes editor metadata and comments, rounds numbers, merges paths and shortens path data. On my test logo it went from 703 to 386 bytes. You can see what it did in the output:
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256"><title>Fix42 test logo</title><rect width="256" height="256" fill="#2563eb" rx="48" ry="48"/><circle cx="128" cy="128" r="76" fill="none" stroke="#fff" stroke-width="16"/><path fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="18" d="m96 128 24 24 44-48"/></svg>
The path M 96.000 128.000 L 120.000 152.000 L 164.000 104.000 became m96 128 24 24 44-48, #FFFFFF became #fff, the comment, XML declaration, unused xlink namespace and the layer group are gone.
Run it with npx svgo input.svg -o output.svg, or set it up in your build. Two things to check after optimising:
- The
viewBoxsurvived. SVGO 4 no longer removes it by default, but older versions and some custom configs do, and without it the image stops scaling. - The
<title>survived if you rely on it for accessibility. SVGO 4 keeps it by default; older presets removed it.
Always look at the result before committing it. Aggressive precision settings can visibly distort small curves.
Three ways to put an SVG on a page
1. <img src="logo.svg" alt="Fix42">
The simplest option. The browser caches the file, scripts inside it do not run, and you give it alt text like any image. The downside is that page CSS cannot reach inside it, so you cannot recolour it on hover or in dark mode.
2. Inline <svg> in the HTML
The markup sits directly in the page. You can style and animate every part with CSS, and it costs no extra request. The downsides: it is not cached separately, it repeats on every page that uses it, and a large inline SVG bloats your HTML. Good for small icons that need theming, poor for a 50KB illustration.
3. CSS background-image: url(pattern.svg)
Fine for decoration such as patterns and dividers. It is invisible to screen readers, which is correct for decoration and wrong for anything meaningful. Like <img>, it cannot be restyled from the page.
A common middle ground for icon sets is an SVG sprite: one file of <symbol> elements, referenced with <svg><use href="/icons.svg#search"/></svg>. You get caching and you can still set colour from CSS.
Theming with currentColor
In an inline SVG (or a <use> reference), set fills and strokes to currentColor:
<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
<path fill="none" stroke="currentColor" stroke-width="2" d="M5 13l4 4L19 7"/>
</svg>
The icon now takes the CSS color of its parent. Put it inside a link and it changes colour on hover with the text. Switch to dark mode and it follows. This does not work for SVGs loaded through <img> or background-image, because those are isolated documents that do not inherit page styles.
Accessibility
<img>: give it a properalt, oralt=""if it is decorative.- Inline SVG that means something: add
role="img"and a<title>as the first child, and point to it witharia-labelledby:
<svg role="img" aria-labelledby="logo-title" viewBox="0 0 256 256">
<title id="logo-title">Fix42</title>
...
</svg>
- Inline SVG that is decorative, such as an icon next to a text label: add
aria-hidden="true"so screen readers skip it. - Icon-only buttons: put the label on the button (
aria-label="Search") and hide the icon.
Also check contrast. A light grey icon on white fails the same way light grey text does.
Security: be careful with SVGs you did not make
Because SVG is XML that browsers treat as a document, it can contain <script> elements, event handler attributes like onload, javascript: links and <foreignObject> with embedded HTML. If your site lets users upload SVGs, for avatars or attachments for example, and then serves them from your own domain, someone can upload a file that runs JavaScript in your users' sessions when the file is opened directly. That is stored cross-site scripting (XSS).
What helps:
- Sanitise on upload. Run uploaded SVGs through a sanitiser built for SVG, such as DOMPurify with its SVG profile, which strips scripts, event handlers and dangerous elements. Do not write your own regex filter.
- Display user SVGs with
<img>, not inline. Scripts in an SVG loaded through<img>do not run. Inlining user-supplied markup into your page is the dangerous case. - Serve uploads from a separate domain (a different origin from your app, so no access to its cookies), and consider a strict
Content-Security-Policyon those responses, orContent-Disposition: attachmentso the file downloads instead of opening. - Or convert to PNG on upload if you do not need vectors. Rasterising removes the problem entirely.
None of this applies to SVGs your own team exports and commits. It applies to files from people you do not control.
Browser support
Every current browser supports SVG in <img>, inline in HTML, and as a CSS background. Internet Explorer 9, released in 2011, was the last major browser to add basic support, so there is no realistic need for PNG fallbacks on websites today. Support gaps are in places other than browsers: email clients, social preview images, and some older desktop software that imports images. For favicons, browsers have supported SVG for some years, but keep a PNG or ICO fallback alongside it because support is not universal.
Quick checklist
- Logo, icon, diagram, flat illustration: SVG, optimised with SVGO, gzip enabled on the server.
- Photo: JPG, WebP or AVIF.
- Needs to change colour with the theme: inline SVG or sprite with
currentColor. - Large decorative illustration used on many pages:
<img>so it caches. - Email or social preview: PNG.
- Accepting uploads from users: sanitise, display with
<img>, serve from a separate origin, or rasterise.
If you want to check what your current images weigh, open your browser's developer tools, go to the Network tab, filter by "Img" and reload. The Webpage Size Checker gives a similar breakdown for any URL.
Kingsley Michael
FounderCreator of Fix42, building free tools that solve everyday digital friction. Passionate about making powerful utilities accessible to everyone without subscriptions or data harvesting.
Share this article
Related Articles
The Great Format Wars: How GIF, JPG, PNG, WebP and AVIF Got Here
A short, dated history of web image formats: patents, browser holdouts and the support milestones that decide which format you can safely use today.
CSV Edge Cases That Break Imports (and How to Handle Them)
Quoted line breaks, byte order marks, semicolon delimiters, lost leading zeros, 15-digit precision and formula injection: the CSV problems that actually cause bad data, with fixes.
10 Habits That Make Online Tools Faster and Safer to Use
How to check whether a tool uploads your file, paste without formatting, verify a download with a checksum, name files so they sort, and other habits that save real time.
The Ultimate Guide to Image Format Conversion
Everything you need to know about converting between image formats, optimizing file sizes, and maintaining quality for web and print.