Tips for using SVGs in web projects

| 12 replies | Short URL: http://benfra.in/1zd

A brief Twitter exchange with Adam Bradley (of Focal Point, CDN Connect and Foresight.js fame) prompted this post.

SVGs have shown real promise for a few years. Plenty of folks have been evangelising their use and their benefits and these arguments are now more relevant than ever (their small file size and resolution independence is a perfect match for mobile high-resolution devices). Despite this, when trying to utilise them in large web projects there are a few pitfalls I’ve come across that I haven’t found to be documented (apologies in advance for when someone invariably points out they have and I just didn’t find it). This post therefore serves as a few pointers if you are looking to employ them in a web project.

Tools

The main tools for creating, editing and optimising SVGs are:

  • Illustrator – expensive but designers are happy there, exported SVG is a little ‘flabby’.
  • SVG Edit – browser based but rather capable. Designers hate it though so good luck getting anyone to use it.
  • Sketch – inexpensive but the SVG support is pretty basic. Shame, if they went for the SVG side of things in a big way I think they could make big waves. Nice for basic shapes but little use otherwise.
  • Inkscape – free but looks like a dogs back wheels so designers tend to gag on sight. However, it’s currently the gold standard in terms of its optimisation of SVGs from directly within a project. Despite this, I favour getting the vectors drawn (or re-drawn) in Illustrator and then optimising elsewhere. More details on that shortly.

SVG versions (beware Tiny 1.2 with MS browsers)

There are a number of different SVG formats available. The Adobe Illustrator help pages have a great overview:

SVG 1.0 and SVG 1.1 Suitable for SVG files that will be viewed on a desktop computer. SVG 1.1 is the full version of the SVG specification, of which SVG Tiny 1.1, SVG Tiny 1.1 Plus, and SVG Basic 1.1 are subsets.

SVG Basic 1.1 Suitable for SVG files that will be viewed on medium powered devices, such as handheld devices. Keep in mind that not all handhelds support the SVG Basic profile. As a result, selecting this option does not guarantee that the SVG file will be viewable on all handhelds. SVG Basic does not support nonrectangular clipping and some SVG filter effects.

SVG Tiny 1.1 and SVG Tiny 1.1+ Suitable for SVG files that will be viewed on small devices, such as mobile phones. Keep in mind that not all mobile phones support the SVG Tiny and SVG Tiny Plus profiles. As a result, selecting either of these options does not guarantee that the SVG file will be viewable on all small devices.

SVG Tiny 1.2 Suitable for SVG files that will be viewed on a variety of devices ranging from PDAs and mobile phones to laptops and desktop computers.

SVG Tiny does not support gradients, transparency, clipping, masks, symbols, patterns, underline text, strike through text, vertical text, or SVG filter effects. SVG Tiny Plus includes the ability to display gradients and transparency, but does not support clipping, masks, symbols, or SVG filter effects.

Furthermore, whilst ‘Tiny 1.2′ is widely supported on mobile devices (including iOS) good ol’ Microsoft don’t support it. Even IE10 on Surface does NOT support SVG Tiny 1.2 profile. Therefore if you need to support the 3 people that will own an MS Surface (that number will probably drop to 2 after a particularly disgruntled customer convinces a store manager to offer a full refund), you’ll need to avoid ‘Tiny 1.2′ format. Instead opt for SVG Basic 1.1 or SVG 1.1.

Not possible to convert SVGZ to data URIs

I got a little excited believing I could optimise SVG delivery by not only converting small SVGs to data URIs but also converting them to SVGZ files first (SVGZ being the gzipped version of an SVG). This simply fails. For example if creating an inline-image with Compass (for example, use background-image: inline-image("file.svg");), it dutifully makes the conversion but the result fails to render.

Responsive SVGs need proportional dimensions (or CSS overrides)

One of the many benefits of SVGs is their ability to look pin sharp when zoomed (except as background CSS images in Firefox and IE, more of which shortly). However, most of the mainstream SVG capable editors export the SVGs with fixed dimensions. For example, open up an SVG in your text editor of choice. At the top you’ll see something like this:

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="96px" height="25px" viewBox="0 122.5 96 25" enable-background="new 0 122.5 96 25"
     xml:space="preserve">
</svg>

If you want the SVG to scale to its containing element (for example the div it lives in) with no additional help, simply change the width and height values to %:

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="100%" height="100%" viewBox="0 122.5 96 25" enable-background="new 0 122.5 96 25"
     xml:space="preserve">
</svg>

This way, whether it’s employed inline within an <img> tag or as a background image in CSS, it will scale on zoom. However, be aware that both Firefox and Internet Explorer 9 and 10 (and IE Mobile) fail to re-render the SVG in CSS based backgrounds. If the user zooms into them they look terrible. Boo!

Careful with background positioning 100% SVGs

It’s also worth knowing that when an SVG with width and height set to 100% is used as a background image in CSS the background-position property does not work consistently. While WebKit uses the top of the containing element to position the background, both IE10 and Opera use the centre. Not great by any means. In this instance it’s necessary to either define width and height in the SVG or use the background-size property to explicitly set the size.

Hat tip to Jeremie in the comments, who provided this concise overview of the way SVGs get rendered by the browser:

Using SVG-as-image (meaning with an HTML img tag or as a CSS background) is always a bit complex but the width and height attributes can always be overwritten with CSS.

For an HTML img tag, the width and height attribute are always overwritten by the width and height CSS properties.

For a CSS background, the width and height attribute from the SVG file can be overwritten with the background-size property. This means it is possible to create SVG sprites that scale in a responsive way.

Despite that, as noted in the comment section, and alluded to above, I have found some minor inconsistency with the position of SVG image sprites across different browsers. Therefore I tend to prefer converting each SVG image to a data URI instead (creates pretty much the same size asset but means that the background image sprite doesn’t need to be moved around).

Comparative sizing

Using Illustrator (CS6), if you want graphics to appear at different sizes relative to one another, place them all in the same view box/canvas (opening an SVG in Illustrator usually places it in a default 960 x 560 canvas which will become the viewbox size).

Image sprite issues. I’ve not found a way to create an SVG image sprite that moves proportionately and fills its container and works perfectly across all browsers. Image sprites can break down (functionally) when the screen is zoomed and SVG based ones are no different. Even when using ems as the background position unit in CSS certain browsers (generally Opera) tend to position the background oddly. Instead my experience thus far has been that creating a separate background image as a data URI for each item needed produces similar benefits (single file for both CSS and image) with no positional drawbacks.

SVG Optimisation

When using a lot of SVGs in a project (say 50+) its important to consider their optimisation. This is especially important if you intend to convert them to data URIs. Extraneous information in the SVGs will result in extraneous information in the CSS. What should we be looking for?

Soon there will be, arguably more effective techniques (than image sprites): fragments and stacks in SVGs. Those with an enquiring mind should have a read of: http://simurai.com/post/20251013889/svg-stacks and http://www.broken-links.com/2012/08/14/better-svg-sprites-with-fragment-identifiers. Update 5th March 2013seems that SVG stacks are no go.

Image optimisation falls into two camps, visual optimisations and things that can be taken care of automagically. First the visual optimisations that should be done by the designer.

Can it be flatter?

Certain ‘things’ are expensive in KB terms with SVGs. For example, it stands to reason that as they are vector based, the more vector points a graphic contains, the larger the resultant SVG will be in KB terms. However, also pay attention to gradients and blurs. The more gradients can be replaced with flat colours, the smaller the resultant file is likely to be.

Remove hidden vector points

Remove any vector points that aren’t visually relevant. For example if only the tip of a star is showing behind something else, remove all the vector points that’s aren’t visible on the star. Less vector points == less file size. This kind of thing can really save KB across multiple SVGs.

Automagic optimisations

For some time I used Inkscape and its command line utilities to perform the SVG optimisation. However, I have now found that the quickest workflow comes from using a utility called SVGO. Doubled up with Grunticon (a fantastic tool the smart folks over at Filament Group put together) and Grunt (in case you don’t know Grunt is a JavaScript automated task runner) this enables typing one command ‘grunt’ to optimise any number of SVGs and then produce fallback PNG files, and data URI equivalent CSS files.

Anyway, that probably sounds more difficult than it actually is. If you want to try the little ‘mashup’ tool (I called it SVG-Gruntenstein) that I use go and grab it (full instructions there too) it here: https://github.com/benfrain/SVG-Gruntenstein

What difference does all this SVG optimisation make I hear you cry? Well, let’s take a look and see.

Example of optimisation savings

Here’s an example of the kind of economies that can be made, 91 SVG images, inlined into CSS:

  1. Prior to any optimisation, the CSS file including data URIs of all images was 436KB (Physical 620KB). Minified and gzipped (how large it would be ‘over the wire’) the CSS came out at 192KB.
  2. Next was a stage of expert ‘designer’ (in this instance it was a privilege to have someone far better than I with Illustrator clean up the SVGs by hand) optimisation. This involved removing unneeded vector points and general cleaning up (the SVGs originated from Fireworks and became SVGs thanks to Aaron Bealls excellent extension). This brought the size down to: 314KB (Physical 467KB).
  3. Finally, there was a stage of optimisation with Inkscape using the methods above. This took the size to: 257KB (Physical 420KB). Raw minified CSS was 472KB and gzipped it came out at 113KB. The optimisation process took the file size down to 58% of the un-optimised version.

Optimise with SVGO

As already mentioned, SVGO is a tool that can automate the optimisation of SVG files. It can be run from a GUI application, command line, or integrated into a grunt.js task (like SVG-Gruntenstein). If you want to rock it direct from the command line, here are a few pointers.

First of all you will need to install it (it’s node.js based so you will need that too – go to nodejs.org and click download and then clicky-clicky through the install). Now, once Node is installed, from the Terminal/iTerm2:

sudo npm install -g svgo

OK, now we are ready to optimise things.

From Terminal, assuming you have a folder full of SVGs, move to the folder above those SVGs. Then run the following command:

svgo -f YOUR-FOLDER --disable removeViewBox

-f flag is notifying SVGO that the thing we want optimising is a folder full of SVGs).

The --disable removeViewBox part is disabling one of the default SVGO plugins (the remove ViewBox plugin).

With that command SVGO will automagically optimise all the SVGOs (and fast) and give nice feedback in the terminal about the savings for each SVG.

That’s all there is to it. Can’t recommend SVGO enough!

On SVG rendering and paint times

What difference does it make if the SVG in question has size set with the width and height attributes and yet is displayed differently?

I was curious if making the browser resize the SVG prior to rendering it would cause a significant increase in paint times.

For example, an SVG with width: 960px height: 560px within that was actually being rendered to screen by the browser at 53px x 30px (using background-size in the CSS).

These tests were run in Chrome Canary 27.0.1435.0 using the ‘Enable continuous page repainting’ option in dev tools.

There were 72 SVG images as CSS backgrounds that the browser was rendering to screen at a size of 53px x 30px.

The test was to run page repainting option for 20 seconds from clicking refresh and compare results. Results are in ms (milliseconds):

Test 1: SVGs at 960px x 560px (large resize down).

Result: 6.8 – 7.7

Test 2: SVGs at 60px x 35px (minor resize down).

Result: 6.6 – 8

Test 3: SVGs at 53px x 30px (actual size).

Result: 6.4 – 7.9

At this sort of speed I think it’s fairly safe to say there isn’t enough difference in paint times (if any) to be worth spending any time over. However, devices with more limited resource (mobile) may produce visible differences.

It’s interesting to note however how much faster things are with identical images saved out as PNGs and the test re-run:

Test 4: PNGs saved at 47px x 27px (minor resize needed)

Result: 2.3 – 3.7

That’s some difference. All things being equal, using PNGs instead of SVGs more than halves the paint time (presumably as there is no need for Chrome to rasterise the SVG prior to resizing).

Whether opting for SVG or PNG for performance, these results must be tempered against the fact that both these render times (SVG and PNG based) are still acceptable. Personally, if they were 10ms plus in Chrome desktop I would start to get concerned.

Summary

Hopefully this little report from the front-line will be helpful for any others looking to employ and optimise SVGs in web projects.

About The Author

12 Responses to “Tips for using SVGs in web projects”

  1. Peter

    Hello, great article!

    Just a ‘quick’ question, possible long answer ;-)

    I would like to create a website with an svg logo, but for browsers that don’t support it create a png fallback. What is the best possible solution today?

    Thanks!

  2. Sérgio Lopes

    Great article!

    There is a very smart python script to create SVG sprites. It creates normal sprites, not those clever futuristic sprites with hash ids.
    https://github.com/astraw/svg_stack

    I also use Scour to optimize the final files. And Inkscape can be used on command line to export the file to a PNG fallback (i find it better than other rasterization tools).

    I have here a very simple bash script that runs svg_stack + scour + inkscape and generates an optimized SVG sprite, PNG fallbacks and custom CSS.

    Live example:

    – SVG sprite: http://www.caelum.com.br/imagens/base/sp-base.sprite/sprite.1341568153.svg

    – PNG fallbacks – 1x: http://www.caelum.com.br/imagens/base/sp-base.sprite/sprite_1x.1341568153.png and 2x: http://www.caelum.com.br/imagens/base/sp-base.sprite/sprite_2x.1341568153.png

    – Generated CSS: http://www.caelum.com.br/imagens/base/sp-base.sprite/sprite.css

  3. Tweet Parade (no.06 Feb 2013) | gonzoblog

    [...] Tips for using SVGs in web projects – When trying to utilise them in large web projects there are a few pitfalls I’ve come across that I haven’t found to be documented. This post therefore serves as a few pointers if you are looking to employ them in a web project. [...]

  4. Nicolas Hoizey

    A few comments about this:

    1. It’s false that you need to use % for width and height in your SVG if you want it to scale to its container. On my blog ( http://gasteroprod.com/ ), the logo is an SVG generated by Illustrator with width=”342.78px” and height=”88.217px” and it scales perfectly.

    2. Where did you read that “it’s not possible to create an image sprite with [SVG] yet”? The 3 icons in the top right of my blog (when seen on desktop) are sprites from the same SVG.

  5. Ben Frain

    Hi Nicolas,

    Small point but looking at your logo SVG in Dev Tools shows it is currently 518 x 133px.

    Regardless, I think we are talking at cross purposes. An SVG with an explicit width and height in pixels won’t scale to fill a larger container when set as a background image in CSS. Similarly, it won’t scale to fill a larger container if used as with an img tag unless told to with CSS (in your example you are using width: 100%).

    Regarding sprites, an SVG sprite can’t work unless it has set dimensions (e.g. pixels) as the browser can’t shift the background a set number of pixels when the SVG itself has no explicit px based dimensions. If the SVG sprite has set dimensions obviously it can be used that way but it then has all the same limitations of size that bitmap image has. This problem is evident in some browsers with your social links. Try zooming your blog 100% in Opera and look at those icons. The image SVG sprite doesn’t work as you intended. It’s all out of place.

    Does, that clarify my meaning? I’ll perhaps try and add a few sections to make my points clearer.

  6. Jeremie

    Hi

    Using SVG-as-image (meaning with an HTML img tag or as a CSS background) is always a bit complex but the width and height attributes can always be overwritten with CSS.

    For an HTML img tag, the width and height attribute are always overwritten by the width and height CSS properties

    For a CSS background, the width and height attribute from the SVG file can be overwritten with the background-size property. This means it is possible to create SVG sprites that scale in a responsive way ;)

  7. Ben Frain

    Hi Jeremie, yes, I don’t think anything you have said there is contrary to what I have written. However, I think you have said it clearer! Also the fact that the background SVG will always favour the CSS dimensions (even if a smaller px dimension is defined in the SVG) is a great tip.

    That way users that want the SVG background to scale to container size have the option of creating the SVG sans width and height and just setting background image and position (as already explained in the post) or create the SVG with dimensions defined and set background size to 100% in the CSS. I’ll add a paragraph later on this.

    However, I still see a problem using SVG sprites. As an example, look at the site referenced above (gasteroprod.com) in Opera and zoom in 100%. See how the social icons go screwy? That would be avoided by embedding the background SVG (on each one) as a data URI instead as the browser doesn’t (incorrectly) shift the sprite about. Similar file size for the assets but more uniform cross browser rendering. Or do you have any tricks to solve that issue?

    That said, at present that problem only seems bad in Opera (which will soon be WebKit based anyway).

    Thanks for the input.

  8. Klaus

    Hi Ben

    I agree with you that using SVGO with the command line provides more flexibility in terms of options. First I tried svgo-gui but that’s silly. No way to use something like –disable removeViewBox and that’s so essential.

    But I’m struggling a bit to find some guidance on options (or plugins as you call them) in general. What else can I use? I.e. how can I process a single svg-file instead of an entire folder. I web-searched this and tried the terminal window too with ‘help svgo’, ‘info svgo’ and so on. Can’t find any useful overview.

    Please, Could you give some advise? Any help, even the shortest hint, will be appreciated.

  9. Ben Frain

    Klaus, I’m really sorry, I’ve only just seen this comment as I’ve been updating the post. I’ve actually just liked to a little tool I put together with Grunt that would server your purpose if you are still looking for something. Again, my apologies.

Leave a Reply

Notify me of followup comments via e-mail. You can also subscribe without commenting.

441Days
441 days since this post was last revised. Specific details are likely out of date.
2387 words
MENU