Tuesday, August 14, 2012

Everything I Know About SVG


Everything I Know About SVGSVG is arguably going to be the main image format of the modern web. I recently wrote an article for Safari Books Online called SVG Icons for New Devices that covers some of the basics of dealing with SVG. This article tries to focus more on the pain points of using SVG in production and it turns out there are many. Read along to see what I’m talking about.

Plain Old <img> Tags

Here’s how you link to your amazing vector image.
<img src="/images/logo.svg">
This is pretty straightforward and should work very well for most of your cases. You can also specifcy width and height this way or in your CSS.

Vector is XML

SVG files are supposed to be human readable, but XML is terrible, so it’s been slow going for me. That being said I have noticed one strange thing about the content of SVG files, notably the fact that there are width and height attributes:
<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="15px" height="15px" viewBox="0 0 15 15" enable-background="new 0 0 15 15" xml:space="preserve">
Sometimes in Firefox when you scale up SVG images (browser-zoom) you get some weird bluriness. If you change the width and height from px to em this bluriness seems to myseriously dissappear. Because in this case it’s a sqaure 1em and 1em work great. I’m not sure if this is a bug in Firefox or if it’s even still a problem in the newer versions. Your mileage may very.

Basic Icons

It’s pretty easy to use SVG for icons and just make them background images. This is probably your standard use case for SVG anyway.
.icon {
    height: 16px;        
    width: 16px;
    background-size: 16px 16px;
}

.icon-arrow {
    background: url("/images/icon-arrow.svg") no-repeat;
}

<div class="icon icon-arrow"></div>

Relatively Easy EM Icons

EM’s are relative to font-size, so you can easily use them to size your SVG images relative to some text, which can be really helpful in a lot of cases. Here’s an exaple of putting them next to some headings.
h1 {
    font-size: 24px;
}

h2 {
    font-size: 18px;
}

.icon-before {
    background-size: 1em 1em;
    padding-left: 1em;
}

.icon-arrow {
    background: url("/images/icon-arrow.svg") no-repeat;
}

<h1 class="icon-before icon-arrow">Header 1 w/Icon</h1>
<h2 class="icon-before icon-arrow">Header 2 w/Icon</h2>

Fallbacks

If you care about IE8 or Android 2.x or other browsers that don’t support SVG images you can combine some fanciness like this with a simple custom build of modernizr to easily fallback without too much ugliness.
.icon {
    height: 16px;        
    width: 16px;
    background-size: 16px 16px;
    background-repeat: no-repeat;
}

/* only show svg icon */
.svg .icon-arrow {
    background-image: url("/images/icon.svg");
}

/* don't show anything but png */
.no-svg .icon-arrow {
    background-image: url("/images/icon.png");
}    

<div class="icon icon-arrow"></div>
Note: With this approach we do have to wait until modernizr adds our svg or no-svg classes to the pages <body> before the images show up. Other fallback approaches can avoid the wait, but this guarantees the right thing will show up in the right browser.
Another Note: Someone really needs to write a Sass plugin one day to create the PNG images directly from the SVG, so that we don’t have to bug the designer for it.

Data-URIs

Data URI’s are this amazing way to embed binary image content directly into your CSS files. This results in a reduce number of seperate downloads and can improve performance in some situations (hover states, etc).
.icon {
    height: 16px;        
    width: 16px;
    background-size: 16px 16px;
    background-repeat: no-repeat;
}

.icon-arrow {
    background-image: url(data:image/svg+xml;base64,..);
}

<div class="icon icon-arrow"></div>
Compass provides the inline-data() helper to assist with base64ing images and bringing them into your stylesheets. You can also drag and drop your SVG images into the SVG is Rad tool I wrote to get the proper CSS.

Weird Bugs

In some versions of WebKit (Chrome < 18 and Safari < 6) you cannot combine SVG data-URIs and background-repeat: repeat-x. The image turns into a blurry mess! Because of this bug in some cases I had to switch to referencing the SVG from a file and it was fine.

MIME Types

If you try to link to external SVG files for background images and don’t specify the correct mime type they just won’t show up. This happened to us after we switched from base-64 encoded SVGs to linking to files, because the so-called magic mime type detection script in our version of Apache noticed that our SVG files looked like XML and served them up as text/xml.
You can add this to your .htaccess file if Apache is doing the same thing to you (hat tip: this 5 year old article):
AddType image/svg+xml svg svgz
AddEncoding gzip svgz
If you’re on NGINX check out this stackoverflow question about SVG MIME types and NGINX.

Related Research

Other people are doing a lot of interesting things with SVGs at the moment. Here are some topics I don’t know quite enough about at the moment:
  1. Spriting with SVG Images
  2. Styling SVG with CSS
  3. SVG Stacks