SVG 101: Setting Up

hero_svg_blogpost_1024x423

SVG (Scalable Vector Graphics) is an XML-based markup language for describing two-dimensional vector graphics. While SVGs have been around for nearly two decades and there is a stunning amount of information out there, a recent comeback in popularity is growing the need for resources and tutorials. These graphics are essential to web development, and, in this blog series, I aim to guide you in the best practices for using SVGs. If there is anything I am missing, please let me know!

Again, SVG may be a blast from the past, but it’s coming back in full force.


The article has been split into two posts. The section below describes the contextual background – how to set up vectors for the web, optimize them, embed them, and the viewport / viewbox – everything that’s needed to get the graphics to show up on the front end. The second post, coming next week, gets into the guts of this subject – an overview of SVG ‘anatomy’: Object primitives, their (main) attributes, masking, clipping, switch statements, and filters. Each one of these topics could likely fill a book with how they work and the techniques for using them. What you’ll find here are high level descriptions with enough detail to (hopefully) provide an understanding of what each does and the basics of use.

Also, there are a few things I’m going to assume you’re already familiar with. First off, the core web technologies: HTML, CSS and JavaScript. SVG is essentially the same as HTML in that the structure is based on XML and it responds to CSS and JS in pretty much the same way, so a lot of this will be very familiar. Secondly, a basic understanding of what SVGs actually are (as in the difference between vector & raster) will be useful.

Optimizing SVGs

Pretty much every time we deal with a vector graphic, we start in Illustrator (or pencil and paper if you’re a designer!). There are other ways (Inkscape / downloading vectors), but however you acquired your SVG it’s likely to have a lot of extra stuff included which we don’t really need:

  • Comments & metadata we don’t need like: <?xml version="1.0" encoding="iso-8859-1"?> with one very specific caveat: running SVGs without that tag through grunticon on Windows 8 has the amusing bug of rendering the xml text as an image for png fallbacks – yeah you read that right, a png of code.
  • Hidden layers or artwork that have somehow flown off the artboard – remove them!
  • Overly defined coordinates, as in the x/y values of a point, aren’t usually needed either. Often these are specified down to 4, 5 or 6 decimal places – we could probably do without the last 2 or 3 unless you’re working with a very intricate piece of artwork.

All of this adds data, granted it’s not much, but we’re pretty obsessed with optimization! Much of this we can avoid by keeping tidy files, but to be completely thorough, it’s probably best to automate tasks. Fortunately this fantastic tool exists: SVGO. Beware, though – SVGO is used through the command line / terminal and requires Node.js to be installed. It’s not complicated, but if you’re not into techy stuff, this might not be so fun.

With node installed, open the command line and run the following:

  • npm install -g svgo – this will install SVGO globally
  • cd to the directory holding your SVG
  • now run svgo yourGraphic.svg yourGraphic.min.svg

Now we have an optimized, minified version of any SVG to work with! There are a few more options with SVGO which you can check out, but the above is all we need for cutting down the majority of extra bulk.

Embedding

As with images, we have a number of ways to get SVGs into the page. Each has its pros and cons, and all of them need some kind of fallback if you’re supporting things like ie8 or Android Browser 2.3. I’ll go through each technique here, but if you already know how you’re going to be using your vectors, feel free to skip to the next section that outlines the best SVG import methods for each use case


INLINE HTML

  • IE8, Android Browser 2.3, iOS 3 & 4 don’t support inline SVG.
  • IE needs the ‘padding-hack’ to make it responsive.
  • We do get access from CSS – this lets us play… a lot.
  • Fallback: svg4everybody will replace any SVG or <use> elements (we’ll get to them later) with browser specific fallbacks, alternatively (if you don’t want any extra js running) there is the switch/foreignObject trick. Hat tip. Although both assets will be loaded. Here’s the rough layout for that:
<svg xmlns="http://www.w3.org/2000/svg" height="200px" width="200px">
    <switch>
        <g>
            SVG
        </g>
        <foreignObject>
            Fallback (eg. raster image)
        </foreignObject>
    </switch>
</svg>

Note, that fallback loads both the SVG and the graphic – so it’s probably best only to use it if you have a lot of traffic from outdated browsers.


IMAGE TAG

  • No interaction – browsers block scripts within img tags, for good reason!
  • Styling, transforms, and animations have to be within the SVG.
  • IE needs img { width:100%; } to make it responsive.
  • Fallback: use svgeezy or modernizr to swap in a raster image, or the onerror attribute trick:
<img src="image.svg" onerror="this.src='image.png'">

EMBED TAG

  • No interaction.
  • Styling, transforms, and animations have to be within the SVG.
  • IE needs embed { width:100%; } to make it responsive.
<embed type="image/svg+xml" src="image.svg" />

OBJECT ELEMENT

  • Styling, transforms, and animations have to be within the SVG.
  • IE needs the ‘padding-hack’ to make it responsive.
  • Fallback: within the object block.
<object id="image" type="image/svg+xml" data="image.svg">
    <div>Fallback and Accessibility description!</div>
</object>
#image div {
    width: 100px;
    height: 50px;
    background-image: url("image.png");
}

IFRAME

  • Styling, transforms, and animations have to be within the SVG.
  • IE needs the ‘padding-hack’ to make it responsive.
  • Fallback: within the iFrame block.
<iframe src="image.svg">
    <img src="fallback.png"><!-- We get a fallback! -->
</iframe>

CSS BACKGROUND

  • No interaction.
  • Styling, transforms, and animations have to be within the SVG.
  • Fallback: use conditional style sheets for older browsers or Modernizr to inject a class.
.element {
    background-image: url(image.svg);
}
.no-svg .element { /* .no-svg injected through modernizer */
    background-image: url(image.png);
}

An alternative fallback, the invisible gradient technique. As with everything, there’s a price: some SVG capable browsers will render the fallback instead of our nice sharp vector, but that may well be a price worth paying for the stability it affords.

.element {
    background: transparent url(fallback-image.png) center center no-repeat;
    background-image: -webkit-linear-gradient(transparent, transparent), url(vector-image.svg);
    background-image: linear-gradient(transparent, transparent), url(vector-image.svg);
}

DATA URI

In the case of image tags and CSS backgrounds, we can embed the SVG itself into the src which saves us a network request – brilliant! This may be familiar if you’ve ever converted and added something in base64 (like a raster graphic in CSS). That base64 conversion is to avoid any unexpected, and potentially breaking, characters. With SVG we don’t need to do that, it’s XML so our characters are safe, and, as pointed out in this article on css-tricks, base64 will actually increase the size of our SVG. So it’s best to just add it in as is.

<img src='data:image/svg+xml;utf8,<svg>...</svg>'>
background: url('data:image/svg+xml;utf8,<svg>...</svg>');

<use>ING AN EXTERNAL FILE

This one will likely require working with a build tool. Set up your vectors in an external sheet within <symbol> tags. These can include a <title><description>, and aria attributes. Include the .svg file in the page head then in the markup we can do the following and it’ll bring in the specified vector as well as the accessibility extras, this one seems to be a favorite (for now, Q4 2015) of Chris Coyer (of CSS-Tricks and Codepen), that’s a pretty big plus for this technique!

<svg viewBox="0 0 100 100">
   <use xlink:href="defs.svg#symbolName"></use>
</svg>

Best practices for embedding SVGs

Quick note before starting off on all of these: if you’re working with accessibility in mind – inline or <use>ing with an external file are the best ways to go. The other methods aren’t as reliably accessible.

One off simple graphic – a logo / article image that doesn’t do anything interactive.
Use the CSS background with the invisible gradient technique. Before that, the Object element seemed to have the lowest overhead but this CSS technique seems safer – all of your visitors are guaranteed to see something.

One off complex graphic – an animated logo / hero graphic with fancy interactive things.
Use inline HTML – this is the most powerful method. There are a few caveats with the older browsers, but their usage is going down! I’d also hazard a guess that if you’re doing something really cool, your target audience is probably going to be on a modern browser.

Icons – nav icons / list icons, the simple things we don’t want to repeat.
If you’re supporting older browsers, use an icon font. It gets supported way back to ie6 but you’ll only get to apply a single color on each icon. Or, if you’re over the old browsers, the <use>ing approach is really powerful. It gives you multiple colors, animation, and interaction. Be warned – if you go down that route, make sure you’ve got someone with a good eye on board – multi colored icons seem like a potentially dangerous path for any design.

Complex & repeated graphics (interactive things that you might be using in multiple locations).
This is basically the same as the last recommendation: <use> it! If you’re looking for this kind of thing in your design, I’d hope your concern for the old browsers has been put to rest, otherwise you’re in for a rough ride. Creating interactive moments in digital experiences is the kind of thing we love to do at Hero Digital. Here’s another example of the <use> system that I find powerful:

The ‘Source SVG’:

<svg style="display:none;">

    <symbol id="firstGraphicID" viewBox="0 0 100 10" aria...>
        <title>title!</title>
        <desc>description!</desc>
        <path d="…"></path>
    </symbol>
    
    <symbol id="secondGraphicID" viewBox="0 0 10 100">
        <path d="…"></path>
    </symbol>
    
</svg>

<use>ing it in the markup:

<svg viewBox="0 0 100 100">
    <use xlink:href="defs.svg#firstGraphicID"></use>
</svg>

This example is moving into something like sprites in SVG, which have been covered in epic detail on 24-ways. There are a few attributes that need to be understood thoroughly before we can get the full use out of spriting SVG’s.

Viewport, viewBox, and preserveAspectRatio

Now we have our vectors in the page, we have to start looking at their size & ratio. That’s what these three guys are for. Maybe they make sense to you immediately, but for me, thinking of them in terms of a camera broadcasting to a TV helped a lot, so I’ll be using that metaphor throughout this section.

The viewport is essentially the parent <svg> tag, this is our TV – it’s the screen (or port?) that displays the picture in our web page.

The viewbox, then, is our camera – it moves around in the SVG world by panning and zooming(ish). It’s essentially a rectangle on the SVG canvas (the rectangle is where the camera is looking). Whatever is in that rectangle gets broadcast to our TV, the viewport.

Both of these attributes can have their position, width and height changed. For the viewbox (our camera), the result should be quite intuitive as I’d imagine we’re all familiar with pointing a camera at a subject. For the viewport, though (our TV), the results may not be so familiar – this is where preserveAspectRatio comes into play.

  • preserveAspectRatio="none": the ‘picture’ broadcast by the viewBox will stretch/squish to fill the ‘screen’ / viewPort. In CSS it’s like setting the width and height to 100%.
  • preserveAspectRatio="meet": the ‘picture’ will be scaled to the largest size within the ‘screen’ without changing the aspect ratio. Like watching a widescreen movie on an old tv, we’ll get a letterboxing effect. In CSS it’s the same as background-size:contain.
  • preserveAspectRatio="slice": The opposite of “meet”, the image will be scaled to the smallest size possible while still completely covering the screen and maintaining the aspect ratio, in CSS: the same as background-size:cover.

In the example below, the viewport (or <svg> / TV) is 100x100px, and the viewbox (our camera rectangle in the SVG world) is set to a 50×50 square that starts at the top left of the canvas (its origin) – our camera is pointing at a small area in the top left corner of our SVG. So anything within that 50×50 box is broadcast to the viwePort which will scale it up to fill the screen.

<svg width="100" height="100" viewBox="0 0 50 50">
</svg>

If we were to change the viewBox (camera) in the example to be viewBox="0 0 100 50" (like a widescreen camera) then the image would scale to fit within the viewport and leave 25px of space above and below as preserveAspectRatio="meet", the letterboxing one, is the default setting. Now, in this situation, our ‘SVG camera’ starts to do magic things that a normal camera wouldn’t. If the SVG extends beyond what the camera (viewBox) is looking at (in this example: above and below), then the ‘letterboxed’ parts of the screen (viewport) will show those extra bits that are supposedly beyond the camera’s (viewBox‘s) view. Magic! Though potentially annoying magic.

In these situations where ‘letterboxing’ may be happening, or the opposite (“slice”), we can also tell preserveAspectRatio where to align the ‘picture’ within the ‘screen’, it’s like fiddling with the position settings on your computer monitor if you’ve ever tried that. We supply this as a second argument to the preserveAspectRatio attribute in the form of one of these values:

xMinYMin | xMidYMin | xMaxYMin
xMinYMid | xMidYMid | xMaxYMid
xMinYMax | xMidYMax | xMaxYMax

Here are some examples to demonstrate (they’re live examples so feel free to open them up in Codepen and experiment with them!). The red box indicates the bounds of each SVG element (our screen: the viewPort), and the blue shows the bounds of the viewbox.

See the Pen JYXNMK by Iain J McCallum (@ijmccallum) on CodePen.

For a far more verbose explanation of these things, check out Sara Soueidan’s article on the subject, it’s pretty in depth! Also, note in the first row, the viewPort is showing vectors that are outside the viewBox‘s field of view – that’s the “magic” I mentioned earlier.

Grunticon

Grunticon is an extension for Grunt – our beloved build tool. It’s not really a basic part of the SVG world but it’s been such an amazing tool for me that I thought it worth tagging onto the end of this article. It relates to how we embed SVGs into the web page. I described each technique above and it’s good to know them, but with this tool, our lives become much simpler. With a little JavaScript that Grunticon generates, we can add vectors into the page by adding a class to an element (class="icon-<filename>"). When the page loads, that element will have an SVG background image. It also frees us from worrying about older browsers – Grunticon generates png back ups for use where SVG isn’t supported, without us having to do a thing! Additionally, if we want to do more interesting things, we can have the SVG injected into that element by adding data-grunticon-embed.

<span class="icon-filename" data-grunticon-embed></span> //magic!

There’s a little bit of set up, but once you’re there, Grunticon works by taking a folder that you can fill with individual SVG files. It compiles them into a single SVG and loads in only the specific parts that are used on any individual page. The class icon-filename should now make a bit more sense.


In next week’s blog post I’ll cover SVG Anatomy.

If you’re interested in learning more about how we use design to solve business challenges, contact us here.