The end of sprites; the rise of SVG

The end of sprites; the rise of SVG

SVG markup

About a year ago, Ned proposed the idea of switching our method of displaying icons and other small graphics in websites that didn’t use sprites. He suggested we used individual SVGs instead.

At the time we were making sprites and had become become quite adept at building them; though they were a constant source of frustration. In the middle of 2012 Apple released the Mac Book Pro with a Retina screen, which added new impetus to seek out ways of making sprites appear sharp on high resolution screens. Our first solution was to make double size sprite files and resize them with CSS for high resolution screens. This solved the problem; but gave us more problems. Now we had two sprites to maintain and more frustration.

So an SVG solution was worth seeking out.

At first I was sceptical about Ned’s idea. My scepticism was founded in at least 8 years of making sprites; it seemed like a constant convention of the internet. Ned said he’d found something in Compass that might help.

In the meantime I’d experimented with SVG sprites; made by saving out the Illustrator file into an SVG and a PNG file for browsers that don’t support SVG. And at first it seemed to work. But it quickly became apparent that it was causing serious processor usage by the web browser to display it; worse the more icons on a page. So I switched back to double size PNGs.

Ned then clued me into a method he was using. Embedding the SVGs into the CSS and linking to a PNG file for web browsers that don’t support SVGs with a helped by a bit of SASS magic. He’d worked out that the vast majority of web browsers that support SVG also support BASE 64 encoding. And in an instant I was a convert. Gone where the days of laying out icons in a PSD or AI file, trying to space things out so you won’t get multiple icons showing when you didn’t need. Gone was the frustration of adding another icon to the sprite. Gone was the worry of Retina and even higher resolution displays of the future. Now for each icon all you need to do is make an SVG and a PNG and place them in your images folder. New icon, new SVG and PNG. So quick, so easy.

The first step was to create a SASS mixin:

@mixin svg-bg-with-fallback($file_name) {
  background-repeat: no-repeat;
  background-image: inline-image('#{$file_name}.svg', image/svg\+xml);
  html.no-svg & {
    background-image: image-url('#{$file_name}.png');
  }
}

And then use a Compass compiler to embed that SVG (I use Scout). The “no-svg” class is put in place using Modernizr.

For our Ruby on Rails apps, I modified this mixin to use a Rails helpers to embed and link the images:

@mixin svg-bg-with-fallback($file_name) {
  background-repeat: no-repeat;
  background-image: asset-data-url('svg/#{$file_name}.svg');
  html.no-svg & {
    background-image: asset-url('png/#{$file_name}.png');
  }
}

And then when you want to use an icon:

.ext { 
  @include svg-bg-with-fallback("icon_external");
  background-position: 0 50%;
  padding-left: 30px;
}

I combine this method with a couple of other mixins, for image replacement elements:

%hide_text {
  font: 0/0 a;
  color: transparent;
  text-shadow: none;
}

@mixin image-replacement($file_name,$width,$height) {
  @extend %hide_text;
  @include svg-bg-with-fallback($file_name);
  display: block;
  width: $width+px;
  height: $height+px;
}

This adds a placeholder class to hide the text, uses the svg bg mixin to add a background image and then sets a size of the element.

So what are the pros and cons of this method?

Pros:

  • much quicker and easier to get icons into a site
  • much quicker to add new icons into a site
  • less requests as only the CSS needs to download

Cons:

  • BASE64 encoding an SVG isn’t as efficient as binary encoding and so your CSS can bloat
  • there are a couple of (obscure) browsers that do support SVG and don’t support BASE64 encoding
  • the fall back creates lots of file requests

Of these cons, the first is the most concerning to us. Making sure that you don’t load too many icons and trying to keep those icons reasonably simple will help. Gzipping will further compress the CSS. If you have lots of icons, then these can be loaded in in separate CSS files after the initial page load as not to slow down the page render.

Optimising

I’ve previously mentioned optimising PNGs with ImageOptim and ImageAlpha. So how about optimising the SVGs?

Well it turns out, there is quite a lot we can do here. The first is to be very careful when making the SVGs in the first place:

  • no groups
  • no masks as browsers can have problem with them
  • no embedded images as they end up as huge BASE64 embeds
  • no embedded PSDs as they end up as even bigger BASE64 embeds
  • outline any type or the font won’t be honored
  • make the art board the size of the graphic
  • align the graphic top left of the art board
  • no hidden layers in the illustrator file, only the layers needed should be in the file

Otherwise, what appears to be an innocent SVG for a twitter icon looks like this:



]>




	
		
	



	
		
	


	
		
	



When is should look like:



]>


  

This is an innocent mistake: in the Illustrator file, all looked well. But Illustrator has a habit of exporting everything in file into the SVG. This makes sense, as hidden layers maybe be shown or otherwise manipulated later on with JavaScript. So that file originally had embedded images, PSDs and all sorts of unneeded layers. Also, the icon ended up being positioned off the canvas and so once in the CSS the position of the icon was hard to predict.

That got rid of a lot of file size. But there is a little more file size we can shift, every little helps. So with a little more fiddling; first in illustrator and then manually editing the SVG file in a text editor, you end up with:



Which is, I believe, the smallest valid SVG file that will render in a web browser. In practice I usually leave a few more things in the opening SVG tag:

...

This was to help IE10 render the SVGs correctly and help when editing the SVGs in Illustrator.

In anecdotal testing on the Facebook Stories rebuild the final gzipped CSS weighs in a 40kb with embedded SVGs and the old site had a non retina sprite of 35kb and a 20kb gzipped CSS. Optimising the SVGs knocked off around 5kb on the gzipped CSS.

I did my SVG optimising manually, I like big dumb solutions and sitewide search and replaces. But many people like automation tools. SVGO is a Nodejs based tool to remove the redundant code that SVG editors put into the files.

The Future

If you embed the SVG directly into your HTML document you can style it with CSS. If you use the SVG as a background, you can’t. Which means simple variations of an icon, say for hover states, aren’t so straight forward. Currently I use tricks like using a black version of an icon and control its opacity or embed two separate versions of an icon in 2 colours. Neither are ideal. Hopefully in the future we’ll have a way to control the SVG background images.

Or maybe we’ll come up with something better.