If you’re down with the SVG, you know how to make it load fast. Minify it, gzip it, and maybe some more aggressive optimizations.

That’s awesome. But download time isn’t the whole story. Users like pages that scroll smoothly and respond to input. And devs’re excited about animation lately. (Users don’t seem to share that excitement.)

But here’s a fact that’s funny, depressing, or both: browsers kind of suck at SVG. It’s only “recently” popular, and there was no incentive to optimize it when it was rare.

That’s the bad news. The good news is there’s every expectation SVG will get faster. But in the meantime, how do we bring the benefits of SVG to users while mitigating the drawbacks?

Download time is still important

Receiving and decoding data from the network takes CPU. The less of that, the more cycles left over for rendering.

Plus, parse time increases linearly with uncompressed filesize, so sending SVGs through SVGO is a doubly-good idea.

Draw the SVG faster

You have to “rasterize” (paint the pixels) at least once, and usually more often than that. Okay, but how?

1. Minify

Minification is good for filesize and for rendering! If you remove unnecessary whitespace, omit default attributes, and combine paths, the browser has less to parse and build into the DOM.

SVGOMG’s “Convert shapes to paths” and “Merge paths” options will combine multiple elements for you. It doesn’t catch them all, so you may have to reorder the ones it failed to combine so they’re next to each other.

2. Simplify

Graphics editors can show how many nodes make up a shape. The less of those, the faster the shape draws.

The “Simplify” command in those editors purports to do this, but it doesn’t always do the best job. Sometimes you have to manually delete the points yourself and readjust the curves to look good.

3. Round to whole numbers

One of the truisms of computer performance is that integers are faster than fractional numbers — “floating-point numbers”, officially. The <canvas> folks have known this trick for years.

This is usually fixed by taking all the numbers in the SVG — viewBox coordinates, <path> data, height and width attributes — and rounding/multiplying them until they stop having decimals.

Simpler images are faster

For all flat design’s flaws, it has an undeniable strength: it’s fast. Solid blocks of color are child’s play for computers.

Decreasing the visual complexity of an SVG speeds up rasterization. I doubt you’ll need to worry about stuff like stroke or dash-array much unless you've got something absurd going on.

However, there are known performance criminals that you should be… cautious about.

<filter>

The performance crimes kingpin. Browsers are starting to hardware-accelerate filters, but inconsistently. Chrome accelerates some, Firefox accelerates others, and some Android hardware can’t accelerate any. Safari does alright as long as you stick to CSS’s filter shorthands and not SVG’s <filter>. (That is, only the boring filters.)

<mask>

Try <clipPath> instead. Browsers are implementing hardware-accelerated clipping paths.

<use>

I’m sorry. I’ll give you a minute.

Complex <text>

Complicated text layout; a webfont on a <textPath> gets punishing if you overuse it

Try not to lay out a lot of text. If you do, text-rendering="optimizeSpeed" it, and break it up with <tspan>s and other hackery instead of <textPath>.

color-rendering, text-rendering, and shape-rendering

SVG has a smattering of performance properties, and they all end with -rendering.

shape-rendering: optimizeSpeed

This turns off antialiasing, which is fast, but looks like 1999 all over again:

It’s good for shapes you don’t want smooth, like QR codes and pixel art. For SVGs made of sharp angles, there’s no drawback. And it’s less noticeable on high-density screens, so you might get away with something like this:

  @media (min-resolution: 2ddpx) {
  svg {
    shape-rendering: optimizeSpeed;
  }
}

text-rendering: optimizeSpeed

text-rendering: optimizeLegibility is terrible for performance. But did you know it has another value, optimizeSpeed?

Turn off the kerning! No ligatures! Grid those pixels wherever’s easiest!

The Catch-22 of text-rendering is that as font size increases, grid-fitting and subpixel antialiasing become less important, but the lack of kerning and ligatures become more obvious.

color-rendering: optimizeSpeed

Just kidding, no browser supports this.

Using SVG efficiently

Even if your SVG code is lean and mean, you can still torpedo performance by misusing it.

Inline <svg>, <object>, <img>, or background-image?

From speedy to sluggy:

  1. background-image
  2. <img> (nearly as fast, though)
  3. <svg>
  4. <object> & friends

The inline and <object>tified methods invoke the full power of SVG: scripting, external resources, a DOM tree, CSS inheritance, etc. SVG as a plain image doesn’t, so browsers skip that work. It’s a significant boost, as Brian Birtles found when optimizing animations:

Browser <iframe src="*.svg"> <img src="*.svg">
Firefox 34 1.9 fps 49.1 fps
Chrome 36 11.18 fps 13.0 fps
IE 11 5.8 fps 15.5 fps

These exact numbers are old, but the trend remains the same today.

background-image and <img> may be the best performers, but at a price: they’re just images. If your SVGs are pure decoration, groovy. But if you need interactivity or accessibility, you need the other two methods.

Inline <svg> clutters up the page DOM, slowing style recalculation/reflow and inflating memory usage. It also hecks up Chrome’s GPU-rendering pipeline.

<object>, <embed>, and <iframe> need a new frame/browsing context to display in, and that has significant overhead.

Here's a trick. If only some parts need to be interactive/accessible, you can improve overall performance by putting the rest inside <image>:

  <svg>
  <style>
    rect:hover { fill: red }
  </style>

  <rect width="100%" height="100%"/>

  <image xlink:href="/non-interactive-stuff.svg" width="100%" height="100%"/>
</svg>

To animate SVG, give it a <div> parent and animate that instead

SVG transforms are NOT hardware accelerated in all browsers (yet). Even if you set them with CSS.

Make compositor layers

If anything flies over or under your SVG, to reduce expensive rasterizations.

Avoid subpixel layout

It makes everything harder and the SVG gets blurry. This usually happens if you leave the SVG's position up to the document flow.

Use DOM interfaces instead of getting and setting attributes

This is because when you use setAttribute, the browser has to parse it. Using the built-in methods and properties like element.x.animVal is ugly and tricky to remember, but can eke out a few more FPS.


Sources