Using SVG graphics today

SVG is a vector format which can be used on the web. They often have smaller file sizes than their rasterised equivalent and more importantly are completely resolution independent. This means they’ll automatically look even better on a retina MacBook, any recent iPhone or any higher resolution device yet to be imagined.

However, there are a few additional steps involved if you want to use SVG graphics today. I’m just going to talk through the steps for using SVG graphics inline here. Most of these steps can be used for CSS background images too.

Step 1: Exporting from Fireworks

At Clearleft we tend to create graphics in Fireworks. Illustrator has the capability of exporting out of the box, although it can increase the file sizes unnecessarily.

Fireworks can also export directly, with the help of a little plugin, simply called Export. Once you’ve downloaded and installed that plugin, create a new document containing just the vector you wish to export, select it and click Commands > Export > Export SVG. As SVG files are actually ASCII files, you can open them in a text editor and look under the hood! Here you will see the paths, fills and possibly gradients used to generate the SVG file.

To further reduce the file size, you should compress it. On Mac, open the terminal and type gzip (followed by a space) and drag in your SVG file. Press enter and your file will be replaced with a gzipped version. Rename it from .svg.gz to .svgz and you are done.

Step 2: Using the SVG file on an HTML page

By using an object to display an SVG file, we can also supply a fallback image for older browsers.

<object data="/i/logo.svgz" type="image/svg+xml" width="235" height="59">
    <img src="/i/logo.png" alt="Alt Text">
</object>

Some server environments don’t send the correct headers with SVG and SVGZ files, so you may need to add the following lines to your .htaccess file.

AddType image/svg+xml svg svgz
AddEncoding gzip svgz

Step 3: Detecting support and progressively enhancing

Unfortunately this simple solution will mean that all modern browsers will download two images. Instead, we should use Javascript to detect and handle support for SVG. This code needs to be added in the head to ensure it runs before any images are downloaded.

<script>
    if (document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")) {
        document.getElementsByTagName('html')[0].className += ' svg'; 
    }
</script>

Now, instead of providing an image inside the object, you should use the following code:

<object data="/i/logo.svgz" type="image/svg+xml" width="235" height="59" class="logo">
    <span>Alt Text</span>
</object>

And use some CSS to set a background image on the span, removing that image if SVG support is detected.

.logo span {
    display: inline-block;
    *display: inline;
    width: 235px;
    height: 59px;
    background: url(/i/logo.png) 0 0 no-repeat;
    text-indent: 100%;
    white-space: nowrap;
    overflow: hidden;
    zoom: 1;
}
.svg .logo span {
    background: none;
}

Now we have a PNG image on older browsers which don’t support SVG, an SVG image on newer browsers, and only one image is ever downloaded (except if javascript is disabled). We will never see both images as the fallback <span> isn’t displayed when SVG files are supported. Apart from the extra image download, this solution works just as well without javascript as with.

I’m pretty happy with this technique, please let me know if you see any issues with it.


Notice: Array to string conversion in /var/www/joshemerson.co.uk/public_html/site/plugins/tags.php on line 22

Fatal error: Uncaught Error: Function name must be a string in /var/www/joshemerson.co.uk/public_html/site/plugins/tags.php:22 Stack trace: #0 /var/www/joshemerson.co.uk/public_html/site/templates/post.php(12): tags(Object(page)) #1 /var/www/joshemerson.co.uk/public_html/kirby/lib/template.php(36): require('/var/www/joshem...') #2 /var/www/joshemerson.co.uk/public_html/kirby/lib/template.php(25): tpl::loadFile('/var/www/joshem...', Array, true) #3 /var/www/joshemerson.co.uk/public_html/kirby/lib/site.php(203): tpl::load('post', Array, true) #4 /var/www/joshemerson.co.uk/public_html/kirby/system.php(65): site->load() #5 /var/www/joshemerson.co.uk/public_html/index.php(71): require_once('/var/www/joshem...') #6 {main} thrown in /var/www/joshemerson.co.uk/public_html/site/plugins/tags.php on line 22