Skip to content

Design

SVG for the Web: When Vectors Beat Pixels — and When They Don't

9 min read

A designer sends a 3 megabyte PNG of a logo that could be an 800 byte SVG file. Every email, every load, every page pays for that download — the recipient's phone decodes it, the mail client caches it, and nobody ever stops to notice that the whole image is a circle, two strokes and a shape. This guide is about understanding what vector graphics actually are, when SVG genuinely beats PNG, when it is a trap, and why you will still need a PNG now and then.

SVG is a recipe, not a painting

A PNG is a bitmap: a grid of colored pixels, each one a stored value. SVG — Scalable Vector Graphics — is XML, plain text that describes shapes with geometry. A rectangle is <rect x="..." y="..." width="..." height="...">; a circle is "center at (12,12) with radius 10"; a path is a sequence of move, line and curve commands. The browser reads those instructions, computes the geometry, and draws — at whatever resolution the screen actually needs. Zoom in on a vector and there is nothing to blur; the browser simply re-runs the math with a bigger scale.

A check-badge icon — a blue circle with a white check — is a complete, real example:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="48" height="48">
  <circle cx="12" cy="12" r="10" fill="#2f6fed"/>
  <path d="M8 12.5l2.5 2.5L16 9.5" stroke="#ffffff" stroke-width="2" fill="none"/>
</svg>

That whole file is under 250 bytes. Exported the same shape as a 2x PNG you get 3–10 kilobytes; scaled up to a 512-pixel site logo, tens of kilobytes. And because SVG is text, it is inspectable and diffable: open it in any editor, grep it, commit it to git and see exactly what changed. A PNG is a wall of pixels; an SVG is source code.

When SVG beats PNG without a fight

SVG wins decisively in a few specific situations. If your image is mostly flat shapes with clean edges, SVG is not a nice-to-have — it is measurably lighter and endlessly sharper:

  • Logos and icons: flat, geometric artwork built from fills, strokes and paths. The canonical SVG use case.
  • Crisp at any zoom: text and edges stay razor sharp on a 4K monitor, in a zoomed corner of a dashboard, or printed on a banner at 300dpi. A PNG blurs the moment it passes its native size.
  • Tiny files for simple shapes: file size follows complexity, not resolution. A typical icon stays a fraction of the same PNG.
  • CSS theming: inline SVG inherits currentColor and reacts to hover, focus and dark-mode states. A PNG is frozen at export time.
  • Animation and interactivity: SVG elements are part of the DOM — you can click them, animate them with CSS or JavaScript, and bind them to data. None of that exists in a static image.

When SVG is the wrong tool

The same logic that makes SVG tiny for icons makes it bloated for photography. A photo is millions of individual color decisions; describing it as vectors means thousands of gradient stops and blurred shapes, and the file balloons past an equivalent JPEG while the browser grind on every frame. Heavily filtered artwork — soft shadows, glows, layered blur — is usually better delivered as a raster.

Rendering is the hidden cost. A PNG is decoded once and blitted to the screen; an SVG is re-rasterized to the target size on every layout pass, every zoom, every animation frame. One complex SVG on a page is fine. Fifty snowflake SVGs, each wrapped in a blur filter, on a scrolling page will visibly jank. Measure performance before you vectorize everything in sight:

SVGPNG
ScalingInfinite — geometry recomputes at any sizeBlurs and aliases past native pixels
Simple shapes~0.3 kB for a typical icon2–10 kB even at 2x
PhotographsBloats and renders slowlyCompressed efficiently, universally supported
TransparencyNative — any shape or holeNative via the alpha channel
Styling & animationCSS, hover, animation, scriptingNone; a new export per change
Where it worksAnything modern, plus the exceptions belowLiterally everywhere

viewBox, width and height: deciding who sets the size

The most confusing part of an SVG file is the difference between the display size and the coordinate system. The width and height attributes (or the CSS properties) say how large the image should be drawn, in CSS pixels. The viewBox says how large the drawing itself is: viewBox="0 0 24 24" means "the artwork is 24 units wide and 24 units tall, starting at 0,0". The browser divides the display size by those units and scales the entire drawing — which is why a 24-unit icon renders perfectly at 200 pixels.

With a viewBox present, the aspect ratio survives by default. preserveAspectRatio="xMidYMid meet" is the default and behaves like object-fit: contain — the artwork fits, centered, with empty space when the box ratio differs; the slice variant behaves like object-fit: cover. One habit worth keeping: do not strip the width and height attributes from the file. With a viewBox present modern browsers let CSS override them cleanly, and keeping the attributes gives the browser intrinsic dimensions before the stylesheet arrives.

Putting an SVG on a page: img, inline, or background

Where you place the SVG decides what it is allowed to do. Four common containers:

MethodCacheableTheme & animateScripts insideBest for
<img src="logo.svg">YesNoNever runLogos, icons, page images
Inline <svg>…</svg>NoYesYesIcons you need to style or move
background-image: url(logo.svg)YesLimitedNever runDecorative textures, masks
<object> or <iframe>YesNoYesLegacy interactive widgets

The <img> tag is the workhorse: static, cacheable and parallel-loading. It is also deliberately inert — the moment you need hover states, currentColor or animation, you have to inline the SVG and accept the extra HTML weight. Background images suit decorative, repeated art that the accessibility tree should never see. <object> still executes scripts and external resources, which is exactly why it has become mostly obsolete for icons.

External SVG pitfalls: CSP, cookies and scripts

An SVG is text, so it can carry a <script> inside it. What happens next depends entirely on where you load it. Inside <img src> the SVG is treated as a static image: scripts never execute, and external references — fonts, stylesheets, other images — are ignored for security. That is the safe container. Inside <object>, an inline <iframe>, or a directly navigated document, an SVG is a full document: scripts run and cookies are sent. A third-party .svg in that position is active code on your page.

Content-Security-Policy assigns each container. img-src governs <img> and background images; object-src governs <object> and <embed>; inline SVG inside HTML falls under the page's own script-src and style-src. And a strict policy that does not list an SVG's host will refuse the file outright — one more reason to self-host what you embed instead of hotlinking.

Inlining foreign SVG is code injection

A minified SVG downloaded from an icon site can hide a <script> or a fetch to a tracking domain; a thumbnail preview never shows it. Validate anything you did not author, or rasterize it to PNG before embedding. Inlining untrusted SVG is a classic route to stored XSS.

Accessibility: title, desc and label

An SVG carries no meaning to a screen reader until you attach one. Give the element role="img", a <title> for its name, a <desc> for the longer description, and wire them together with aria-labelledby:

<svg role="img" aria-labelledby="badgeTitle badgeDesc" viewBox="0 0 24 24">
  <title id="badgeTitle">Verified badge</title>
  <desc id="badgeDesc">A blue circle containing a white check mark</desc>
  <circle cx="12" cy="12" r="10" fill="#2f6fed"/>
  <path d="M8 12.5l2.5 2.5L16 9.5" stroke="#fff" stroke-width="2" fill="none"/>
</svg>

Two more habits pay off. Use real <text> elements instead of converting text to outlined paths — screen readers read real text, and it stays selectable and searchable. And if an SVG is purely decorative, add aria-hidden="true" (or keep it as a background image) so assistive technology skips it entirely.

When you still must rasterize to PNG

Vector is not universal. Plenty of real delivery channels refuse or mangle SVG, and the only safe answer is a PNG at the right size:

  • Email clients: Outlook — especially the Windows renderer — does not render SVG reliably; transactional email still ships PNG because a bitmap is the one safe bet.
  • Social preview cards: Open Graph and Twitter Card scrapers fetch your og:image, and most render a raster reliably; SVG previews are often refused or come back blank.
  • Favicons: modern browsers accept .svg favicons, but Apple touch icons and older tooling want PNG (apple-touch-icon.png) — you ship both.
  • Old browsers and WebViews: anything pre-2017, some embedded WebViews and legacy kiosks have no SVG support at all.
  • Upload forms: CMS, marketplace and stock-design platforms reject .svg by extension because it can contain scripts; PNG passes every validator.

Rasterize SVG to PNG — in your browser, on Convrs

The cleanest workflow keeps the SVG as the source of truth and rasterizes only for the delivery channel that demands it. Convrs' SVG to PNG converter turns any SVG into a crisp PNG inside your browser: paste or drop the file, choose the pixel size (256, 512 or 1024 for a retina icon, for instance), and download the result. The conversion runs entirely on the Canvas API in your own tab — the file is never uploaded and no server ever sees it. No sign-up, no queue, nothing to trust beyond the browser you already have.

Keep the vector. Rasterize where the world demands it. And the next time a designer ships you a 3 megabyte logo, you know exactly what to say.

Buy me a coffee