How, and why, to clean SVG markupOctober 24th 2017
Despite the introduction of the Scalable Vector Graphic (SVG) format almost 20 years ago, the popularity and understanding of working with the SVG format has grown phenomenally in the last few years amongst the web community. The SVG format was brought to the table in 1999 by the World Wide Web Consortium (W3C) and is an XML based vector image format designed specifically for the web.
One of the many beauties of an SVG is that it can be scaled to literally any size, whilst always retaining quality, whereas a bitmap image, such as .jpg, .png or .gif, will pixelate when scaled beyond its natural size. Scalability means that the SVG format is a natural fit for the modern responsive web. An SVG could easily be scaled from mobile, to a standard desktop display, all the way to a 5K display, and everywhere in between and beyond.
The SVG format typically has smaller file sizes than any of its bitmap counterparts, and SVG supports other interesting use cases, including animation. If you’re not yet convinced about the SVG format, I strongly recommend watching this Chris Coyer video or reading Chris’ book; Practical SVG.
The aim of this article is not to convince you to use the SVG format in your web projects, but rather a useful guide to serve those who have already adopted the use of the SVG format in their projects.
SVG Anatomy (SVG == Markup)
An SVG behaves similar to standard bitmap when previewed in a browser or image viewer; it simply looks like a standard graphic. However, since SVG is XML-based, you can find readable, familiar, HTML-like markup under the hood. This means that you have readable line-by-line control, regardless of what tool churned out the file.
Although an SVG could be coded from scratch, most SVGs are produced in some form of graphics editor, such as Adobe Illustrator, Inkscape or Sketch. Generally, these applications export SVGs with additional, unnecessary (sometimes even outdated) elements, attributes and lines within the markup.
Here is some XML from a typical SVG icon created in Adobe Illustrator CC:
<?xml version="1.0" encoding="iso-8859-1"?> <!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 60 60" style="enable-background:new 0 0 60 60;" xml:space="preserve"> <g> <path d="M45.563,29.174l-22-15c-0.307-0.208-0.703-0.231-1.031 0.058C22.205,14.289,22,14.629,22,15v30c0,0.371,0.205,0.711,0.533,0.884C22.679, 45.962,22.84,46,23,46c0.197,0,0.394-0.059,0.563-0.174l22-15 C45.836,30.64,46,30.331,46,30S45.836,29.36,45.563,29.174z M24,43.107V16.893L43.225,30L24,43.107z"/> <path d="M30,0C13.458,0,0,13.458,0,30s13.458,30,30,30s30-13.458,30-30S46.542,0,30,0z M30,58C14.561,58,2,45.439,2,30S14.561,2,30,2s28,12.561,28,28S45.439,58,30,58z"/> </g> </svg>
If you’re familiar with HTML, this too will look quite familiar; elements and attributes. And, just like HTML, we can optimise it.
Let’s take a look at another example. Here is the SVG markup that was generated by Sketch for a simple map marker.
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg width="39px" height="39px" viewBox="0 0 39 39" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <!-- Generator: Sketch 39.1 (31720) - http://www.bohemiancoding.com/sketch --> <title>Hospital</title> <desc>Created with Sketch.</desc> <defs> <rect id="path-1" x="0" y="0" width="33" height="33" rx="9"></rect> </defs> <g id="Maps" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Map" transform="translate(-483.000000, -779.000000)"> <g id="Hospital" transform="translate(486.000000, 782.000000)"> <rect id="Rectangle-57" fill-opacity="0.599999964" fill="#FFFFFF" opacity="0.5" x="0" y="0" width="33" height="33" rx="9"></rect> <g id="Rectangle-57"> <use stroke="#2D2D2D" stroke-width="6" fill-opacity="0.599999964" fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-1"></use> <use stroke="#FF0000" stroke-width="3" xlink:href="#path-1"></use> </g> <polygon id="Shape" fill="#FF0000" points="19.7149758 19.5157005..."></polygon> </g> </g> </g> </svg>
The above SVG markup comes to a total of 21 lines of code. Now, relative to your standard HTML file, this may not seem like a lot, but it’s quite a lot of lines for an simple SVG, typically I work with SVGs of around 4-10 lines.
So, without further ado let’s dig in and see what we can remove.
What Markup can we remove?
The first thing that we can remove is the XML prolog.
<?xml version=”1.0″ encoding=”UTF-8″ standalone=”no”?>
Most XML documents begin with a prolog; one or more lines of code providing information about the current document and related documents. If the SVG is going to be embedded within an HTML document or another SVG, which it most likely will be, the prolog is redundant and can be swiftly removed. Although leaving the prolog will have no effect to the end user, removing it helps to keep your code clean and readable.
<svg> version Attribute
<svg> tag comes packaged with the version attribute, specifying it is using the latest version of SVG – SVG 1.1.
<svg version=”1.1″ … >
This attribute has no influence or bearing on the rendering of the SVG and can be removed. So, let’s strip that out.
One thing that stands out to me is the large XML comment that was generated by Sketch.
<!– Generator: Sketch 39.1 (31720) – http://www.bohemiancoding.com/sketch →
Although in certain contexts, XML comments can be helpful, or even important, this particular comment is redundant. Other SVG editors may include XML comments when generating SVGs, these comments can also be safely removed.
Next, we’re going to strip out the title and desc. Removal of these elements is dependant on the context in which the SVG is going to be used. The title and desc tags both aid accessibility. The title element may be displayed on hover in certain browsers. The title and desc may also be displayed instead of the graphic in situations where the SVG paths cannot be rendered.
<title>Hospital</title> <desc>Created with Sketch.</desc>
If the SVG is a chart or provides some important context to the webpage, keep the title and desc tags. If the SVG is a small icon, perhaps they could be removed. Ultimately, the decision to remove the title and desc tags lies with you, the developer. In this case, however, I have decided to remove the tags.
Note: If you do decide to keep the tags, it’s quite important that you provide better information than the automatically generated content that your SVG editor provides. Provide a rich title and desc that will convey meaning of the SVG to the user.
One of the major clutters of the SVG markup is the chain of
<g> tags that serve as a wrapper for the SVG paths. Most of
<g> elements have transform attribute, and a few other attributes.
<g id="Maps" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Map" transform="translate(-483.000000, -779.000000)"> <g id="Hospital" transform="translate(486.000000, 782.000000)"> <rect ...></rect> <g id="Rectangle-57"> <use ...></use> <use ...></use> </g> <polygon ...></polygon> </g> </g> </g>
All of these
<g> elements can be removed as they are quite redundant. Since a program generated the SVG, it knows very little about optimising code, leaving a trail of endless
<g> tags in its wake.
<svg> viewBox is a difficult subject, and I would strongly recommend Sara Soueidan’s article if you are new to the attribute.
<svg viewBox=”0 0 39 39″ … >
After the removal of the
<g> tags, the positioning of the SVG elements was slightly off by 3px, I adjusted the starting point of the viewBox to compensate.
<svg viewBox=”-3 -3 39 39″ … >
This isn’t ideal, but it’s better than the endless chain of
<g> tags with random, non-sensical transform attributes. You may not have to make any edits to the viewBox, and if you do it is likely that you will have to use different values.
Most of the elements within the SVG markup were provided with some form of ID when the SVG was generated, the
<rect> element, for instance:
<rect id=”Rectangle-57″ … />
In our case, ours
<defs> block looks like this:
<defs> <rect id=”path-1″ x=”0″ y=”0″ width=”33″ height=”33″ rx=”9″></rect> </defs>
The elements within the
<defs> are not initialised, they are simply declared for future use, you can see this element is used further in the markup:
<use xlink:href=”#path-1″ … ></use>
Personally I don’t find the name very descriptive, so I renamed it to border, the markup becomes:
<defs> <rect id=”border” x=”0″ y=”0″ width=”33″ height=”33″ rx=”9″></rect> </defs> <use xlink:href=”#border” … ></use>
The new ID is much nicer and much more descriptive.
Why not use an automated SVG optimiser, like SVGO or SVGOMG?
While it’s true that there are a host of automated SVG optimisers that will, as the name suggests, automatically optimise the markup of an SVG for you, but this can come at a cost.
In some cases, you may find that automated tools can merge all of the SVGs layers, making the SVGs harder to work with in future.
To quote Sarah Soueidan:
[SVGO] can break the SVG as well as any structure you create in it for animation, for example. I use SVGO sparingly. Ai export is v clean.
You can find an interesting Twitter thread on the topic by Sara Soueidan et al here, which is also the source of the above quote.
And that’s it. So, our cleaned-up markup is:
<svg width="39px" height="39px" fill="none" viewBox="-3 -3 39 39" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <rect id="border" x="0" y="0" width="33" height="33" rx="9"></rect> </defs> <rect fill-opacity="0.6" fill="#FFFFFF" opacity="0.5" x="0" y="0" width="33" height="33" rx="9"></rect> <use xlink:href="#border" stroke="#2D2D2D" stroke-width="6" fill-opacity="0.599999964" fill="#FFFFFF" fill-rule="evenodd"></use> <use xlink:href="#border" stroke="#FF0000" stroke-width="3"></use> <polygon fill="#FF0000" points="19.7149758 19.5157005..."></polygon> </svg>
We’ve managed to reduce the lines of code down to 9; that’s over 50% LOC reduction. That’s pretty impressive.
Now, you’re probably wondering what the point of all this cleanup is. Well, clean SVG markup has a myriad of benefits, including:
Maintainability – Your SVGs are easier to edit and maintain, without ever opening an image editor.
Speed – less code means smaller file sizes, smaller file sizes means a faster loading web page.
Animation – it becomes notably easier to animate SVGs when the markup is clean, optimised and free from redundant tags.
Accessibility – image editors seldom focus on accessibility when generating markup. Having clean markup makes it easier to create accessible markup.
Whilst it is true, an SVG minifier, such as SVGOMG, could do most of the leg work for you, but could damage the quality of the SVG. The choice is yours.
Of course, it’s all contextual. Figure out if you have time to optimise your SVGs, and if it’s viable to do so, go ahead! If not, that’s fine too.