With the rise of Retina displays people are looking for resolution independent alternatives to PNG icons. Some fell in love with font-icons, some are shouting “SVG”. But I’m sorry, if you’re looking for a silver bullet, I’m afraid it doesn’t exist. Let’s take a closer look at our options:
Icon fonts are awesome, but..
they are not sharp. I mean really sharp, pixel-perfect kind of sharp. Using font-face for icons has become quite popular. I have been promoting and even started collecting them. But there is a flaw that keeps bugging me. They are still a tiny bit blurry on “non Retina” displays (which are still a huge majority). Try out the size slider in Chris’s demo and take a very close look. It varies at different sizes, but they all have this “half-pixel blurriness” problem. It might be hard to notice, so here a zoomed-in screenshot at 15px (also removed the background noise):
The subpixel anti-aliasing works great on curves, but not on straight lines, there it just doesn’t look sharp. In theory you could use font hinting to snap the icons to whole pixels. But so far I’m not aware of any icon-set doing that. Also I’m guessing it’s a lot more work and the hinting data might increase the file size significantly. Edit: @thijs notes that hinting only works on supported platforms and won’t help on OS X, iOS and Android.
SVG to the rescue?
Well, not really. The big advantage of using SVG icons would be that in their original size (not resized), they look pixel-perfect sharp. But once you start resizing, they have the same subpixel blur problem until you reach multiple of its original size. Notice the inner cross.
In practice using only multiple sizes probably should be ok. You create all your icons in a base size, let’s say 16px and you use a bigger version for action buttons in 32px or 48px.
Edit: @erikdahlstrom + @Marco_Rosella mentioned: shape-rendering:crispEdges. If used on individual rect(angles), they can be forced to pixel-snapping. Might not always be perfect, but keeps it crisp. Test in this jsFidde.
Problem solved? I wish, but there are other issues like:
Here a fiddle to test it out.
You could use inline SVG or SVG as an <img> element, but that makes it hard to be used as a sprite. Maybe with nested elements and overflow:hidden? Anyways.. just not as straight forward and flexible as with background-image.
Edit: David Bushell found a workaround by starting large and only scale down.
Lots of icon fonts also come with a PNG version that you could use instead, but then you need a solution for showing a HiRes version on Retina displays. Using a device-pixel-ratio Media-Query should help you out. Or Apple just implemented -webkit-image-set, which looks promising, but still is gonna take a while.
So what should you do? As I said.. there is no silver bullet, but..
Here a little guide that might help.
There’s just no single image format suitable for everything and probably never will be. So who says you can’t mix them all together? Maybe best is to use PNG served in many different sizes for your high fidelity, multi-color logo and other graphics. SVG icons for your navigation that stays the same size, but also look sharp on Retina displays. Responsive inline SVG for bars and charts and an icon font for all your different button sizes. We’ve mostly been doing that anyways.
A look into the future
Is there a way to get out of this icon-sharpness limbo? Well.. let’s just wait a little.. once we have Retina displays everywhere (ok, could take a couple years), the subpixel problem will be gone and maybe browsers will have fixed the SVG issues and we can truly celebrate our resolution independent icons? But even then, we still would’ve to deal with the problem that details in icons don’t scale. Update: Media Queries in SVG might solve that.