When we produce a PNG image, we use an <img>
tag or a CSS background, and that’s about it. It is dead simple and guaranteed to work.
Unfortunately, the same cannot be said for SVG, despite its many advantages. Although you’re spoiled for choices when using SVG in HTML, it really boils down to inline
, <object>
and <img>
, all with serious gotchas and trade-offs.
Problems with inline SVG
If you’re inlining SVG, you lose the ability to use browser cache, Gzip compression between servers and browsers, and search engine image indexing (inline SVG is not considered as an image). Even though your image may not have changed one bit, they are always reloaded and this causes slower loading times for your website, a trade-off that most are not willing to tolerate.
In addition, inlining SVG also causes complex dependency problems where you cannot easily insert images into HTML and have to resort to scripts (PHP or otherwise). When you have more than a few images, this becomes a huge problem when it comes to maintaining your site, because essentially you can’t use the <img>
tag anymore.
No doubt, there are areas where inlining SVG shines — that is, if you want your images to display quickly, without waiting for other resources to load. Apart from that, clearly, you just can’t inline everything.
Problems with object tag
SVG is well known for its excellent quality when displayed on devices of all resolutions and its ability to refer to external resources — like CSS and fonts — while keeping the file size very small. The idea is to have many SVGs that all share a single CSS or a single font file, to reduce the amount of resources you have to download.
The myth of resource sharing
Unknown to many, sharing external resources for SVG only applies to inline SVG. Because usage of <object>
tags allow access to these resources, the perception is that the browser will download a single copy of your CSS, even though you have many <object>
tags referring to the same CSS file.
This however, is not true at all:
Compounding the problem is the fact that <object>
tags are not recognized as an image, and therefore image search indexing is not possible.
Further compounding the problem are dependency issues. For example, let’s say you have 100 images, and 25 of them use a Roboto font, another 25 use Lato, 25 use Open Sans, while the rest use a combination of the three fonts. Your CSS would need to refer to all three fonts because it is quite impossible to keep track of which file is using which fonts, meaning you may be loading fonts you may not require on certain pages.
The image tag
That leaves us with the <img>
tag, which has a lot going for it. Because it’s the same tag used for other image formats, you get familiarity, browser caching, Gzip compression and image search. Each image is self-contained, with no dependency issues.
The only problem is you will lose your fonts. To be more precise, if you have any text in your SVG, unless you embed fonts, your text will be displayed with system fonts, typically Times New Roman. You’ve spent hours selecting a beautiful font but the moment you use the <img>
tag to embed SVG, all that is lost. How can this be acceptable?
Investigating font rasterization
Our first reaction is to see if we can perform font rasterization. It is a commonly used technique to convert fonts into paths, so it’ll render well on all devices and maintain zero dependencies. On the surface, this works very well, and on the editor, everything looks perfect.
Although the rasterized SVG came in at a whopping 137 KB compared to 15.7 KB before rasterization, we were optimistic because, after optimizing our SVG using Gzip compression, the rasterized file is reduced to 11 KB, slightly smaller than the equivalent PNG at 11.9 KB.
Original | Font rasterization | Font rasterization (.svgz) |
---|---|---|
15.7 KB | 137 KB | 11.0 KB |
PNG @ 1x | PNG @ 2x | PNG @ 3x |
---|---|---|
11.9 KB | 26.5 KB | 42.6 KB |
Alas, once we embed the rasterized SVG into HTML, we found our optimism to be premature. Although it might look great on high-resolution displays, the quality on low-resolution displays is unacceptable.
The bottom of the image is the original, with clearly displayed fonts while, on top, fonts are pixelated with font rasterization.
What’s happening is that most operating systems will optimize fonts to ensure they are shown clearly and sharp on all screens. On Windows, this is called ClearType, and since we rasterized our fonts, no optimizations will be applied, resulting in blurred text, particularly visible on low-resolution screens.
Obviously, a reduction in quality is unacceptable, so back to the drawing board.
Font embedding to the rescue
Initially, we were extremely skeptical about font embedding, mainly because of the complicated workflow.
To embed fonts in SVG, you first have to know what font families are used. Then you need to find these font files and download them. Once downloaded, you have to convert regular, bold, italics and bold italics to Base64 encoding. If you’re doing it manually, it is quite impossible, over a large number of files, to know which file uses bold and which ones does not. Then you have to copy all four Base64 encoded strings into your SVG.
Surely, there has to be a better way. And that’s why we built Nano. Nano scans SVG automatically and inserts only the fonts that are used. For example, if bold is not used or if no text exists, then no fonts will be embedded.
Still, the resulting file is huge and is not competitive with the PNG equivalent, so we plugged away and built our own SVG optimizer (Nano) that will reduce SVG file sizes to a trickle. (See how Nano compresses SVG.) In addition, we also optimized how we embed fonts into SVG, resulting in very small file sizes.
Comparing file sizes and bandwidth savings
Original | Font rasterization | Unoptimized font embedding | Nano font embedding | |
---|---|---|---|---|
Size | 15.7 KB | 137 KB | 65.2 KB | 22.0 KB |
Gzip | 3.57 KB | 11.0 KB | 44.5 KB | 11.7 KB |
PNG @ 1x | PNG @ 2x | PNG @ 3x | |
---|---|---|---|
Size | 11.9 KB | 26.5 KB | 42.6 KB |
Gzip | 12.1 KB | 26.1 KB | 41.7 KB |
From the above, we can see that Nano produces an SVG that is extremely lightweight even with embedded fonts, coming in at 11.7 KB (Gzipped) compared with the equivalent PNG @1x at 11.9 KB. While this may seem insignificant, the total bandwidth saved on your site will surely be significant.
Let’s assume that 50% of your traffic is low resolution, 40% is 2X resolution and the remaining 10% is 3X resolution. If your website has 10,000 hits on a single image:
(5,000 * 11.9 KB) + (4,000 * 26.5 KB) + (1,000 * 42.6 KB) = 208.1 MB
If you use Nano, compressed SVG with GZip:
10,000 * 11.7 KB = 117.0 MB
This will result in: 208.1 MB – 117.0 MB = 91.1 MB
savings, or 43.7%, bandwidth savings, a significant amount by any measure.
In addition to the bandwidth savings, you get a far simpler workflow without resorting to multiple PNG images with multiple srcset
, with much better quality, including operating system font enhancement to ensure your images stay crisp and sharp on devices of all resolutions. Best of all, better user experience for your users, since your site will load faster — especially so on devices with high resolution.
Thoroughly testing Nano
Not satisfied with all the savings, we began to look for SVG images to thoroughly test Nano. A total 2,571 SVG files of various sizes and designs were used, totaling up 16.3 MB
. And after Nano optimization, resulting in 6.2 MB
, an astonishing 61.8% savings in size.
Showing a visual difference
Because of the sheer number of files that we were testing, and it increases from time to time, we have to build an automated test, including automatically highlighting pixel differences before and after optimization. One of the complaints on other SVG optimizers is the fact that minifying SVG may break your image, causing it to render differently compared to the original.
To this end, we carry over the pixel differentiation in our automated test into Nano itself. That is, Nano will warn you if it detects that the SVG it optimizes has a pixel difference of more than 1% when compared to the original, therefore ensuring Nano’s optimization will never break an SVG.
Because fonts are embedded and preserved, plus SVG being a vector graphics format, rendering quality on all resolution is incomparable to other raster formats.
What’s next?
We hope our work will make SVG easier to use everywhere. We’re now working on producing even smaller file sizes, porting our codes to work on Node.js so you can automate your production builds with Nano, among others.
Do you think you’ll find Nano helpful in your projects? Let me know in the comments!
If the W3C wasn’t ruled by corporate CSS fanatics then SVG fonts would not have been deprecated. SVG fonts solve all your problems, but you can’t use them. Thank Google, Apple and the NSA.
Thank you for this article. It seems that if you only had a few places where a font would appear in the SVG, then simply converting the text to Paths could also be an option. This assumes a few things like a “lightweight” (not many points) font, and only a few characters. Then the paths would remain as SVG vector and NOT rasterized. The image caption reads, “Converting fonts into paths” but then goes on to discuss rasterization without mentioning more about using path converted fonts. I’m confused.
Hi Kel, thanks for that feedback. We call converting fonts to paths as rasterization, essentially you just rasterize the fonts into paths. Even for “lightweight” text, we DO NOT recommend converting to paths as the output quality will degrade as these paths may not show up crisp and clear. On the other hand, we recommend Nano, which will automatically ensure font embedding are as lightweight as can be, resulting in crisp fonts that get optimized by OS and very small SVG file sizes.
Thanks Thomas. Was confused only because most other applications I’ve encountered use the word “rasterize” to denote conversion into a raster image, whiile convert to paths was still lighter weight code representing, well.. paths :)
Thank you. I like SVG on the WEB and this is great news for me.
Any chance of making this into a Sketch plugin?
@smlombardi, no plans at the moment, but it is already a plugin in vecta.io. Do google it, as drawings done with vecta will have an option to get compressed or minified with embedded fonts when you export SVG. Hopes that helps.
Forgot to mention that a node.js module to help you automatically “nanofy” your svg is in the works, which makes it much easier to include in your build processes.
I don’t agree with the downsides you’ve listed for SVGs in this article. You can easily enable gzip for SVGs in nginx, browser cache is also not an issue and even if it were, your service worker could cache it for you.
Hey AJ, You can surely enable gzip on your server, but if you’re inlining SVG, they would NOT be recognized as SVG, hence no transport encoding and no cache busting. Hope that clear things up.
The article would probably benefit from a more fitting example. The images show examples of simple controls containing of an icon and text. That’s something that is usually handled with an SVG icon and regular (HTML) text, which can then be easily set to a custom font via CSS. Why would there be a need to embed the text in SVG as well? I assume, a better example would be an SVG infographic or chart.
@Sime, you are right on all counts. In our example, we wanted to show part of the dashboard, and the easiest way is to draw them together with the text and treat the entire thing as an image. Infographic or charts would surely be a better example. The separation of image into an icon and HTML text would probably be far more difficult to implement. Even the best of teams make these mistakes, see https://cloud.google.com/storage/, single api image and again in their pricing comparison with AWS. Chances are they have Roboto installed and it looks great on their systems, but for the rest of us, we would probably prefer not to default to Times New Roman.
Why not dynamically inline an external SVG to the DOM (caching), then destroy / recreate all your current SVG USE refs? Bam. Cached inline SVGs with font support all the way back to IE.
@Chris LaChance, that’s a pretty cool idea, albeit with some draw backs.
By embedding fonts, you treat images just like any other images and let the browser do the heavy lifting. Still a great idea and has it uses. Cheers!
Yeah, it would require a DOM ready for sure in that case, at least for browsers without external ref support. I do love that text can be embedded. Makes managing a design system way easier.
The final img using Nano optimization showing no visual difference looks great… in Chrome, Safari and Opera. But in Firefox Quantum 60.0.2, the outlined text has lost its hinting and is not readable at all. It must be having a problem with how WebRender works.
Hey Sandy, Thanks a million for that feedback.
For the final image mentioned, it is a Quantum bug where the browser fails to render USE elements fonts without strokes but funny enough the original is rendered properly. We shall submit a bug report to them. We’ll replace the image and remove the USE element as for now, thanks again for telling us!
In addition, our tests show that Quantum has a bug that refuses to accept SVG attribute values that does not have units, specifically the font-size attribute. According to SVG specifications, if there are no units, the default “px” will be applied, therefore if your SVG has font-size=”45″, then it is understood as font-size=”45px”.
Nano being an SVG minifier, obviously strips out the extra “px”, causing Quantum to mark font-size=”45″ as an invalid attribute, therefore causing rendering problems. We will submit a bug report to the Quantum team.
If you face any other problems, please do let us know as we are keen to have Nano work on all platforms without problems. Thank you!
Hey guys, great article and tool – thanks a lot. However, maybe I’m just being stupid – but I tried embedding a font into my svg with nano, but the output file does not include any embedded fonts (hence lots of Times New Roman :-(
I’ve tried uploading an svg with the font already included as base64 css (gets stripped by nano), with a linked web-font (no effect at all) and just the plain output from Sketch or Illustrator (also no font embedded in the nanofied end result).
I must be missing something really obvious here, but can you help me along? How does the original svg file have to include the font for nano to be able to work its magic?
Any help appreciated!