Understanding and Manually Improving SVG Optimization

Avatar of Raymond Schwartz
Raymond Schwartz on (Updated on )

📣 Freelancers, Developers, and Part-Time Agency Owners: Kickstart Your Own Digital Agency with UACADEMY Launch by UGURUS 📣

The following is a guest post by Raymond Schwartz. Like it’s raster brethren, SVG should be optimized before being used on production sites. There are several great tools for that, but as Raymond is about to show you, the best results come from a deeper understanding and a little manual work. For instance, decimal precision is a big factor in SVG optimization, but it’s a rather arbitrary metric depending on the coordinate system of SVG. Alter that system, get different results. Here’s Raymond.

Three factors determine the optimized file size of an SVG: physical dimension, viewBox, and decimal precision. Arbitrarily setting any one of them can cost you valuable bytes—even kilobytes. Each SVG has a specific combination of these three properties that will yield the smallest possible file size. By understanding how each impacts the articulation of vector paths, you can discover how to adjust them to achieve the optimal optimization.

1) Physical dimension: debunking the “Scalable” in SVG (sort of)

To create an SVG, fire up your favorite vector graphics editor, setup the document, and make something visually engaging. Part of the document setup is defining physical dimensions. This may not seem critical since, by definition, vector graphics are scalable and visual dimension will vary depending on its context. While that’s true of the visual representation, the same is not true of the code representation—that remains constant. The code representation is derived, in part, from the container’s dimension (or “artboard” in Illustrator) which is described by discrete measures. By setting the dimensions, you’ve already partially determined what the file size will be.

2) viewBox and micro optimization

Dimensions, in addition to guiding path articulation, also determine the viewBox attribute’s values.

A viewBox could look like this:

viewBox="-351.7474061, 2051.85204372, 2520.3925946, 2520.13473217"

This is much too long considering we can perform a micro optimization in a lossless way—without changing the image visually. First, set the top-left corner to 0,0:

viewBox="0, 0, 2872.1400007, 468.28268845"

This saves 23 bytes since one character equals one byte. Next, round width and height to whole numbers—scaling artwork if needed:

viewBox="0, 0, 2872, 468"

That saves another 17 bytes. Finally, scale the artboard down to reduce the number of digits:

viewBox="0, 0, 252, 252"

Adding another two for an overall savings of 42 bytes. Even though the savings are small, this optimization is easy to do and has no negative effects. And now that you know, you’ll set up your files this way from the start—this should be built-in to your file setup. But more importantly, as we shall see, this method has a much greater impact saving bytes in paths.

3) Decimal precision: which one is best?

When you save an SVG, you’ll need to indicate a decimal precision—usually an integer between one and eight. It defines the number of digits after the decimal point for all numeric values. Remember, characters equal bytes and the less we have, the smaller the file will be. As decimal precision is reduced, so are the amount of bytes—potentially seven less bytes per number.

But as precision decreases, SVGs can visually break because there may not be enough numeric data to accurately describe them. As precision increases, more detail is present, but beyond a certain point, may not increase fidelity—wasting bytes. Our goal is to balance file size and visual fidelity and know precisely where that balance is perfect.

What isn’t addressed by this setting is how many significant digits we have to the left of the decimal point. That’s where adjusting dimensions and viewBox come into play. Next, we’ll examine paths—what defines the drawing—and how dimension, viewBox, and decimal precision affect the number of characters they contain.


What does a path look like?

Our example is based on the kiwi bird from Chris Coyier’s Using SVG and has two paths: one is an ellipse, the other is a kiwi. Its dimensions are 100px width by 82px height, viewBox is 0 0 100 82, and decimal precision is seven—the highest Illustrator allows.

Visual representation of the Kiwi bird SVG from Chris Coyier’s Using SVG.

Basic shapes have their own tags: circle, ellipse, line, polygon, polyline, and rect. Since these shapes are well-defined, the amount of code needed to describe them is minimal—all you need are some attribute/value pairs. Here’s what the code of our example’s ellipse looks like:

<ellipse fill="#C6C6C6" cx="46.3267326" cy="68.9376144" rx="42.3298607" ry="13.0623865"/>

To describe anything other than basic shapes, the path tag is required. Here’s the kiwi’s path—the first bit, and the last value:

<path id="bird" d="M34.363224,0.0008523C17.0553761,0.1314738-2.0175736,13.9286251,0.1724619,34.4692345c0.7027745,6.5964966,3.0235648,10.4009247,8.5313501,12.8991089c5.9327183,2.6941185,9.315836,8.915081,8.2371655,18.4506187 … 72.8360062,22.4844837z"/>

The entire value is about twenty times longer. With so many characters, non-standard shapes offer the greatest opportunity for optimization. Note all numbers have a decimal precision of seven. An optimization tool can’t add detail so if you save at a lower precision, you’re limiting your options. Always save at the highest decimal precision allowed by your editor.

How dimension and decimal precision affect paths

The first value in the kiwi’s path is: M34.363224,0.0008523

This defines where the path starts. M, means move to a spot. The comma-delimited numbers are the x and y coordinates of that spot respectively. They’re derived from the top-left corner’s coordinates (viewBox), the scale of your dimensions, and the decimal precision you’ve chosen.

From our example file, I made four more files by multiplying and dividing width and height by ten. Here’s what the first and last values of the kiwi’s path look like in each:

Dimension First value Last value
1×1 M0.3436333,0.0000095 0.7283611,0.2248458z
10×8.2 M3.4363234,0.0000861 7.2836018,2.2484493z
100×82 M34.363224,0.0008523 72.8360062,22.4844837z
1,000×820 M343.6322327,0.0085142 728.3600464,224.8448334z
10,000×8,200 M3436.3222656,0.0851329 7283.6005859,2248.4482422z

The lower limit of the length of a coordinate, with a decimal precision of seven, is nine characters—a decimal point, a leading zero, and seven decimals—or, at most, two more than your decimal precision. It can be less if you had something like 0.1479000—that would be reduced to 0.1479—but the nature of non-standard shapes makes values like these very unlikely.

The upper limit of the length of a coordinate is restricted only by the size of your editor’s artboard. Notice that each time dimension was multiplied by ten, another significant digit was added to the left of the decimal for each coordinate. And remember, more characters equals larger file size.

How does dimension affect file size?

See how each of our five files fared being optimized with SVGO-GUI—a port of SVGO but with a drag-and-drop GUI interface. While drag-and-drop is convenient, this convenience comes at a price. SVGO-GUI only optimizes with a decimal precision of three. This is perfect, however, to demonstrate the impact of dimension exclusively. Here are the results:

The take-away from this table is that profit (percentage of file decrease) increases as dimension decreases—the smaller your dimensions are, the smaller an optimizer will be able to make your file. Also note file size decreases before optimization as well.

I’m using SVGO-GUI to illustrate a point. It’s great for bulk optimization, super convenient, and great if you don’t have a lot of time. If you want to get the smallest file though, you’re going to need a decimal precision below three—which means we’ll have to use another tool.

Finding the best combination of dimension and decimal precision

Looking at the feedback from SVGO-GUI, there’s an incredible 50% drop in the “after” file size going from kiwi-10 to kiwi-1. And while that looks good on paper, it doesn’t look good on screen. In the next figure, kiwi-10 is on the left and looks like the original. In the middle, is kiwi-1, and you can see an overall loss of detail. On the right is kiwi-10 with its decimal precision reduced from three to one—and also not usable.

From left to right: kiwi-10, kiwi-10 with reduced dimension, and kiwi-10 with reduced decimal precision.

As dimension is reduced, so is the detail paths contain. Imagine a coordinate of 5.5555555. Every time dimension is reduced by a factor of 10, you lose the last digit—0.5555555, 0.0555555, 0.0055555, etc. At some point, so much detail is lost that an SVG breaks visually. Similarly, an SVG can also break as decimal precision is reduced—although in a different way. Our challenge is to find the perfect combination of dimension and decimal precision that maintains visual fidelity while yielding the smallest number of characters.

To that end, we’ll start by making a group of files, based on the kiwi, with dimensions based on powers of 2—1, 2, 4, 8, etc. The easiest way I’ve found to do this in Illustrator is to select all artwork, copy it to the clipboard, make a new document, set the dimensions, and paste. With the transform palette open and all paths selected, set x and y coordinates to 0 and set the larger of width or height to the corresponding dimension of the artboard. Be sure to select the transform pallet’s link icon to maintain aspect ratio. Keep going until you’ve reached 1024px or 2048px.

Now, it’s time to use Jake Archibald’s online optimizer, SVGOMG! It’s a fantastic, comprehensive optimizer that can be used both on and offline. Although SVGOMG! has built-in zoom capability, at smaller sizes, you’re going to have to edit the width attribute to something reasonable so you can see images clearly (500px should do it). Open the first image (1×1). Make sure “Compare gzipped,” “Prettifycode,” and “Multipass” are off. Toggle “Show original” to compare the un-optimized image with the optimized one. We’re going to start zeroing in on the best file by adjusting decimal precision. Find the lowest decimal precision you’re comfortable with before visual breakage happens, and make note of it. Here are my results after doing this for each image:

Dimension
(square in px)
Lowest Decimal Precision
w/o breaking
Optimized file size
(K)
1 4 1.4
2 3 1.25
4 3 1.28
8 3 1.29
16 3 1.31
32 3 1.39
64 2 1.22
128 2 1.34
256 1 1.11
512 1 1.18
1024 1 1.28

Some of the patterns present in this chart we’ve already discussed—at smaller sizes, more decimal precision is needed to avoid visually breaking; at larger sizes, less decimal precision is acceptable; the larger the dimensions, the larger the file size.

One new pattern has emerged—a decimal precision of one will produce the smallest file. File size gets considerably smaller at each “leap” to the next smaller decimal precision. The smallest file at decimal precision 4 is 1.4k; the smallest at 3 is 1.25k; the smallest at 2 is 1.22k; and the smallest at 1 is 1.11k. What still isn’t known is the smallest dimension at which a decimal precision of one will not break.

Note the range of our targeted variations is almost .3k, or over 20% of the highest value. The range would be larger if we hadn’t selected specific values. This gives you some idea of how much arbitrary decisions can affect file size.

To find exactly what dimension/decimal precision combination yields the smallest file size, focus on the leaps in decimal precision. We can eliminate the two leaps—from 4 to 3, and from 3 to 2—since there’s a smaller file size (in the leap from 2 to 1) and any points within those leaps would be larger. This leaves only the first leap from 2 to 1 to examine.

Make a file with a width of the mid-point of the first leap—192. At a decimal precision of 1, it’s 1.06k and looks acceptable. Remember, these differences are almost imperceptible and only apparent when toggling views between original and optimized in SVGOMG!. The next mid-point—between 128 and 192—is 160. This one doesn’t look good and went up a bit to 1.07k—file size can plateau, going against the established pattern. To check, I looked at 200, which was at 1.08k—as expected, upwards again. And 190 and 194 were both 1.07k. So the best size is achieved at 192px width and a decimal precision of 1. How amazing is it that we actually know that?

More micro-optimizing

Here’s the optimized code from SVGOMG! of our winner, 192×192:

<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 192 192"><ellipse cx="88.9" cy="132.4" fill="#C6C6C6" rx="81.3" ry="25.1"/><path d="M66 0C32.7.3-4 26.7.3 66.2 1.7 78.8 6 86.2 16.7 91c11.4 5 18 17 15.8 35.4-3 1.5-5.4 3.4-6 6.2 2.4 0 4.7 0 7 1.4 6.5 4 10 8.6 13.6 16.2.7 1 2.7 1 2.7-1 0-2.6-.6-5.5-1.6-8.4-1-2.6 1-2.5 2.3-2 2 1 5 3 9.5 4.2 1.7.4 2-1.2 1.6-2.2-.6-2.4-3.4-3.4-7.7-6-1.5-1-.2-3 1.7-2.7l6.3 1c1 0 1.5-2 .3-2.6-4.5-2-9-3-17-2.4-3.6-9.2-9.3-19.3-4.8-25.6 4-5.6 9.7-6.5 12.2 13.6-1.5 1-3.5 1.6-3.5 4 2-.8 3.4-.4 4.5 0 5.6 2.3 11.2 7 16.7 11.8 1 1 2.6-.6 2-2-.5-2-2.4-3.3-4.5-6.2-1-1.4 1.6-2.2 3.4-2 4.5 0 7.3 2.5 11.2 3.4 1.4.3 3-.7 2-2.2-1-2-4-2.8-6-4.2-1.3-1-.8-2.2 1-2 1.2 0 2.6.7 4.3.5 3-.2 2.4-2.2-.3-3-6-1.6-12.5-2-19.3-1.5-14-2.7-10-26.7 0-28.4C73 82.6 83.5 80 95 74c10.3-1.7 20.4-4 29.2-10.6 15-4.5 35 5 64 47 1.3 1.7 5 3 3-2-5-13-21.4-29.3-29-41.5C155 54.4 158 47.6 150 38.2c-6.7-7.8-15-8-24.3-5.4-7.3 2-12.3-2.3-16.6-10C100 7 83.5 0 66 0zm73.8 43.2c2 0 3.5 1.5 3.5 3.4 0 2-1.5 3.5-3.5 3.5s-3.4-1.5-3.4-3.4c0-2 1.5-3.4 3.4-3.4z"/></svg>

SVGOMG! does a fantastic job at optimizing the path and removing the junk your editor injects. It also tells you the file size of the original—in this case 3.92k vs. 1.06k for a savings of 72.96%! In what’s left there are more optimization opportunities to take advantage of.

You can safely remove the xmlns attribute if you’re supporting only HTML5-compliant browsers. Within the context of an HTML document, xmlns is implied for SVG elements. For backwards compatibility of XHTML or for treating your markup like valid XML, leave this in. If removed, savings is 35 bytes.

If your image can be visually edited, rounding all attribute values of the ellipse to the nearest whole number will remove a few more bytes but reposition it slightly. Changing the color to something similar but repeating like #ccc that’s similar will cut that value in half. You could also target the SVG’s container element with CSS and remove this attribute entirely. Savings from these micro-optimizations is 23 bytes for a total savings of 58 bytes and a final file size of 1.025k—a savings of 73.85%.

Removing width and height attributes would optimize our file even further. Especially if in a responsive context, why set width and height explicitly in pixels? Responsive SVGs are accomplished with CSS which will override width and height attributes anyway. The benefits to leaving them, however, outweigh any optimization benefits removing them may have. They may remain, however, if fluidity is still desired.

Why width and height attributes should remain

If following the principle of progressive enhancement, you’ll want to test your pages with CSS missing. CSS is what made SVGs responsive and will no longer apply. What happens when an SVG without width and height attributes is rendered sans CSS? It fills up the width of the entire viewport. This may not be what you intended and can make for a difficult to read and broken looking page.

The next figure shows CSS-Tricks without said tricks. The masthead looks fine across the entire width so width and height attributes have been retained, but the search icon doesn’t. It separates the search label from the search box, is too visually prominent, and causes excessive vertical scrolling.

Here’s what happens when a width attribute with a value of 16 is added to the search icon:

This fits more closely with how the icon looked with CSS applied, makes the page more readable, and reestablishes appropriate visual hierarchy.

Be mindful of how it’s filled

In another view, this is what the top of the page looks like with CSS in effect at a mid-level media query.

Notice both “CSS-TRICKS” and “treehouse” SVGs are white on a black background, but, in the previous figure, “CSS-TRICKS” switches to black while “treehouse” remains white—and therefore invisible against the white background. Adding color can be done either through CSS or the fill attribute. In the case of the Treehouse logo (most likely supplied by Treehouse), the fill attribute was used to add fill color. When CSS is missing, the fill attribute still applies, so the Treehouse logo remained white.

It’s probably safer and more intuitive to have presentation reside in CSS rather than controlled by an attribute. If style needs to be packaged together with an SVG, use a style attribute so it’s treated the same as other CSS.

These same display issues also extend to print. Test how print style sheets handle SVGs and, if they are displayed at all, make sure they’re visible and in the right proportion. If printed, the search icon would be large and out of proportion the same as it was in our web page example—wasting paper and hurting readability.


Conclusion

Now you can choose any SVG, take it through this process, and know that you’ve come up with a version that has the smallest file size possible—given where you started. There may be a better method, I may have missed something, and the landscape will most assuredly change, but I offer this as a possible solution, and, at a minimum, hope it sparks some discussion and nudges you to create your own method.

Even if you don’t follow this method to the letter, consideration of the principles can help guide your process and workflow. Visual inspection is subjective and deciding the right balance between visual fidelity and file size savings—and how much effort you put into it—is up to you. There are many advantages to making websites performant and slimming down SVGs can contribute substantially towards that effort—most critically with inline SVG.

An automated tool would be helpful and it would most likely be best if something like SVGOMG!—that’s already in heavy use and actively under competent development—added this sort of functionality to their bag of tricks. In the meantime, I hope you determine to get the most bang for the buck out of your SVGs.