DEV Community

Adam McKenna
Adam McKenna

Posted on • Updated on

How, and why, to clean SVG markup

You wouldn't think that the SVG format has been around for almost 20 years.

Over the last few years, the popularity of the format has grown so phenomenally that you'd be forgiven for thinking it was a recent innovation.

These days, it is common practice to provide your logo, graphics, charts, and the like as an SVG, instead of its pixellated bitmap counterparts.

So, where did this file format come from? The SVG (Scaleable Vector Graphic) format was brought to the table in 1999 by the W3C (World Wide Web Consortium). It's an XML based vector image format designed specifically for the web.

One of the many beauties of vector images, including SVG, is that they can be scaled to any size without a loss of quality. Bitmap images, on the other hand, such as .jpg, .png, and .gif, pixelate when scaled beyond their natural size.

Scalability makes the SVG format a natural fit for the responsive web. An SVG can easily be scaled for mobile, desktop, all the way to 5K displays, and everywhere in between and beyond.

Image source

An SVG typically has a smaller file size than any of its bitmap counterparts. An SVG also supports several interesting use cases that bitmaps cannot, including animation and interaction with JavaScript.

If you’re not yet convinced that SVGs are the future, I strongly recommend watching this Chris Coyer video or reading Chris’ book, Practical SVG.

Convincing readers to use the format is not the purpose of this article. Rather, this article is a guide for those who have already adopted SVGs, and want to squeeze a little more out of the format.

Let's explore how we can cleanup SVG markup, and why we probably should.

SVG Anatomy (SVG == Markup)

When you preview an SVG in a browser or an image viewer, it will, more or less, behave as a bitmap. You can see the image rendered. Of course, the SVG will be sharper, and won't pixelate if you zoom in, but beyond that there is little difference.

The difference is behind the scenes. SVG is XML-based. Behind every SVG there is readable, HTML-like markup. This means that you have readable line-by-line control, regardless of what tool churned out the file.

Heck, SVGs could be coded from scratch, and often are. But, most SVGs are produced in a graphics editor, such as Adobe Illustrator, Inkscape or Sketch. These applications often export their SVG markup with superfluous, and sometimes outdated, elements and attributes.

For example, here is the XML from an SVG icon created in Adobe Illustrator:

<?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>
Enter fullscreen mode Exit fullscreen mode

If you’re familiar with HTML, this will look quite familiar: it's just elements and attributes.

And, just like HTML, we can optimise it.

Let’s look at another example. This SVG markup is for a map marker icon generated by Sketch:

<?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>
Enter fullscreen mode Exit fullscreen mode

Sketch generated this simple icon with 21 lines of markup.

Relative to a typical HTML file, that is not many lines. But, for a simple icon, it's much more than necessary. Most icons that I work with are around 4-10 lines.

Why the bloat? There are several elements and attributes that are redundant and can be removed. Let's have a look at what they are, and why we can remove them.

What Markup can we remove?

XML Prolog

The first thing that we can remove is the first line: the XML prolog.

<?xml version=”1.0″ encoding=”UTF-8″ standalone=”no”?>
Enter fullscreen mode Exit fullscreen mode

Most XML documents begin with a prolog. A prolog is one or more lines of code that provide information about the current XML 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 removed.

Leaving the prolog will have no effect to the user, but removing it helps keep your code clean and reduces file size.

The <svg> version Attribute

The <svg> tag comes packaged with the version attribute, indicating that it is using the latest version of SVG – SVG 1.1.

<svg version=”1.1″ … >
Enter fullscreen mode Exit fullscreen mode

This attribute has no influence on the rendering of the SVG and can be removed.

XML Comments

Did you see Sketch's obtrusive XML comment?

<!– Generator: Sketch 39.1 (31720) – http://www.bohemiancoding.com/sketch →
Enter fullscreen mode Exit fullscreen mode

Although in certain contexts, XML comments can be helpful, this particular comment is redundant. We don't need to know where the icon came from.

Many other graphic editors include XML comments when generating SVGs, and these comments can also be safely removed.

The <title> and <desc> tags

Next, we’re going to look at the title and desc elements.

<title>Hospital</title>

<desc>Created with Sketch.</desc>
Enter fullscreen mode Exit fullscreen mode

You may not want to remove these elements. It depends upon the context in which the SVG will be used.

The title and desc tags are helpful for accessibility. The title element is displayed on hover in certain browsers. Both elements may also be displayed instead of the graphic if there is a situation where the SVG paths cannot be rendered.

If the SVG provides important context to the page, for example, a graph or chart, then you should keep the title and desc tags, and change their text content to convey the content of the graphic.

On the other hand, if the SVG does not provide important context, for example, an icon or logo, then the title and desc tags can be removed.

As I am working with an icon in this example, I removed the tags.

The <g> tags

The major clutter of the SVG markup in my example is the chain of <g> tags that serve as a wrapper for the SVG paths.

Most of the <g> elements have a transform attribute, among others.

<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>
Enter fullscreen mode Exit fullscreen mode

All of these <g> elements are redundant and can be removed.

Why Sketch decides to leave an endless trail of <g> tags in its wake is one of life's great mysteries. We may never know.

The <svg> viewBox Attribute

The <svg> viewBox attribute is a complicated concept.

I will not delve into it within this article, but I strongly recommend Sara Soueidan’s article if you are unfamiliar with the attribute.

<svg viewBox=”0 0 39 39″ … >
Enter fullscreen mode Exit fullscreen mode

Once the <g> tags were removed, the positioning of the SVG elements was slightly off by 3 pixels. I adjusted the starting point of the viewBox to compensate.

<svg viewBox=”-3 -3 39 39″ … >
Enter fullscreen mode Exit fullscreen mode

This isn’t ideal, but it’s better than the endless chain of <g> tags and their non-sensical transform attributes.

Although I did, you may not have to make any edits to the viewBox attribute. But, if you do, it is likely that you will have to use different values.

IDs

Most of the SVG elements were generated with an id attribute. The <rect> element, for example:

<rect id=”Rectangle-57″ … />
Enter fullscreen mode Exit fullscreen mode

Unless you need to target these elements with JavaScript, these id attributes can be stripped out. The only instances where the id attributes are important are within the <defs> block.

In my example, the <defs> block looks like this:

<defs>

    <rect id=”path-1″ x=”0″ y=”0″ width=”33″ height=”33″ rx=”9″></rect>

</defs>
Enter fullscreen mode Exit fullscreen mode

The elements within the <defs> are not initialised within this block, but rather they are declared for future use.

You can see the path-1 element defined within the <defs> block is referenced later in the markup via a <use> element:

<use xlink:href=”#path-1″ … ></use>
Enter fullscreen mode Exit fullscreen mode

That means we need to keep the id attribute so that the <use> element can reference the <rect>. But, the id value path-1 is not descriptive. I renamed it to border:

<defs>

    <rect id=”border” x=”0″ y=”0″ width=”33″ height=”33″ rx=”9″></rect>

</defs>

<use xlink:href=”#border” … ></use>
Enter fullscreen mode Exit fullscreen mode

The new id clearly describes the element.

What's next?

Okay, lets address the elephant in the room...

Why not use an automated SVG optimiser, like SVGO or SVGOMG?

It's true. There are a number of automated tools that will optimise SVG markup for you.

But, this can come at a cost.

In some cases, automated tools can merge all of the SVGs layers, making the SVG 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.

Here is an interesting Twitter thread on the topic by Sara Soueidan et al here, which is also the source of the above quote.

Conclusion

And that’s it.

<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>
Enter fullscreen mode Exit fullscreen mode

We’ve managed to reduce the lines of code down to 9 -- over 50% of the lines of code were removed. That’s pretty impressive.

Now, you’re probably wondering what the point of all this cleanup was.

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 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 graphics.

  • JavaScript – understandable markup makes it easier to integrate with JavaScript. For instance, sensible, unique id attributes.

While it is true that an SVG minifier, such as SVGOMG, can do most of the leg work for you, it can also damage the quality of the SVG.

Do you have the time? Are you going to animate the SVGs? It's contextual and the choice is yours.

Thanks for reading.

Top comments (9)

Collapse
 
eljayadobe profile image
Eljay-Adobe

I worked on one project where someone decided SVG was too complicated and converted them all to PNG files.

Guess what happened when the application was on anything other than 100% scale? That's right... it looked like @$$.

All that fine SVG converted into sad bitmaps. And not just bitmaps... bitmaps for all the different states. Which could easily have been done with SVG w/CSS.

Sad panda.

Collapse
 
lexlohr profile image
Alex Lohr

In some cases, you can do even more optimization by hand: some exports I received from our designers had base64-encoded jpeg-blurs and -shadows in them. So I handcoded a blur and a shadow filter and used them on parts of the design, bringing down a 30kb SVG (that was supposed to replace a 50kb PNG) to 7.5kb.

As a front-end developers, SVG is the bridge between development and design; thus to unleash it's full potential, you need a designer and a developer. Tools will only bring you so far.

Collapse
 
schroef profile image
schroef

Nice article, i was looking for the title issue i had with icons in an Electron app. I "fixed" by manually deleting the title tag. But there must be a better way. I mean who is going to do such work if you have perhaps more than 100 ions in a project?

Collapse
 
adammckenna profile image
Adam McKenna

Thanks 😊

In that case, you can use an SVG minifier!

Collapse
 
nikrunic profile image
KRUNAL R PRAJAPATI

This is also beautiful website for free svg icon - custicon.com
10000+ free icons for use in web, iOS, Android, and desktop apps. Support for SVG. License: MIT, Free for commercial or personal use.
This provide svg icon and svg code and also provide the icon image and it should be free

Image description

Collapse
 
daviddeejjames profile image
David James

Great read, had to write a wiki page similar to this for my team. Link for Chris Coyer video?

Collapse
 
adammckenna profile image
Adam McKenna

Thanks! I've added that link in there now, and a few others I was missing :)

Collapse
 
douira profile image
Douira

Maybe build an optmisier that applies just the here described rules?

Collapse
 
adammckenna profile image
Adam McKenna

There's a challenge for you 😊