How to export clean .svg icons with Sketch
As designers we strive every single day to solve problems. I personally like to sit with developers and try out new solutions. Going through the source files of our consumer app at Practo I realised that 30% of it comprised of drawables (images, icons, fonts). This amounts to about 3.2 MBs. 200+ drawables. Each drawable in 6 variations. For each dpi. Plus a majority of them weren’t even been used. Having pngs for drawables might be the easy way out but surely not the most optimum one.
Android lately launched its resource for SVG compatibility to back versions as well. Hence we went on this uphill task to determine the benefits of using SVGs instead of PNGs for drawables.
What is SVG?
Scalable Vector Graphics (SVG) is an XML-based vector image format for two-dimensional graphics with support for interactivity and animation.
Vector Drawable?
Vector drawables help you create a drawable based on XML vector graphic. In simple terms all SVGs have to be converted to vector drawables and packed in an .apk file.
Why should we use SVGs?
- Resolution-independent vector graphics. No need to make icons for 6 different DPIs.
- Easier way to make animations and interactions.
- Saves a lot of space. 80–95% space saved by using svg instead of a png (for a 24x24 dp system icon)
- Easier to manage. Making a repo is all the more easier.
- Need file in just one color. You can add colors on the go while development.
- Provision to work for all android devices. Android lately launched backward compatibility for SVG icons.
- Having all drawables in vector format is a big big boon for cross-collaboration.
Current problems with Sketch SVG export
While I was making icons for the central repo I figured out a huge bug. The SVGs exported don’t have any problem whatsoever. Open them on Chrome or preview them on mac, they look similar to what you expect them to be. The problem arises when you convert them to vector drawables.
Here is how an SVG downloaded from google icon looks like :
<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M0 0h24v24H0z" fill="none"/><path d="M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1.4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z"/></svg>
I now open the same SVG on Sketch and export it again. Here’s the new SVG code :
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="22px" height="22px" viewBox="0 0 22 22" 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>ic_build_black_24px</title><desc>Created with Sketch.</desc><defs></defs><g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="city" transform="translate(-171.000000, -375.000000)"><g id="ic_build_black_24px" transform="translate(170.000000, 374.000000)"><g id="Group"><polygon id="Shape" points="0 0 24 0 24 24 0 24"></polygon><path d="M22.7,19 L13.6,9.9 C14.5,7.6 14,4.9 12.1,3 C10.1,1 7.1,0.6 4.7,1.7 L9,6 L6,9 L1.6,4.7 C0.4,7.1 0.9,10.1 2.9,12.1 C4.8,14 7.5,14.5 9.8,13.6 L18.9,22.7 C19.3,23.1 19.9,23.1 20.3,22.7 L22.6,20.4 C23.1,20 23.1,19.3 22.7,19 L22.7,19 Z" id="Shape" fill="#000000"></path></g>
</g>
</g>
</g>
</svg>
Figured the bug?
If you see closely, the height and width in the first svg is 24. Even the viewbox is “0 0 24 24”. The second svg just changed the height and width to 22. Viewbox is “0 0 22 22”. How did that happen?
Ok, so Sketch just takes the zone with the actual icon as the viewbox area. And to compensate, they have a polygon shape which is “0 0 24 24”. Problem happens when you try to convert this svg to a vector drawable.
Android Studio’s tool which converts SVGs to Vector Drawables reads the <svg> tag and the inputs associated to them. Since Sketch’s svg has a faulty viewbox, the vector drawable turns out to be smaller and hence incorrect.
And did you notice the crap Sketch has exported. Unnecessary shapes and groups. The reason for this issue is that Sketch sometimes messes up in identifying masked, grouped or hidden layers while exporting an svg.
How to create correct SVGs?
Its is really not that tough if you follow these steps with caution. It can be bit tedious, but the end results are worth it.
1. Create an Artboard
Make the artboard of the same size of the icon/illustration you want to export.
2. Create your icon
Sketch is a very powerful tool in making icons. Clean, swift and easy. But there are a few rules to follow if you want it be cleanly exported.
Rule 1 : Try to make shapes with fills. Fills are easily exported to vector drawables.
Rule 2 : If your shape has a border, use an centre border. SVGs exported with inner or outer borders don’t convert to vector drawables.
Warnings shown when trying to export to a drawable :
WARNING@ line 14 We don't scale the stroke width!
WARNING@ line 15 We don't scale the stroke width!
WARNING@ line 16 We don't scale the stroke width!
Rule 3 : Don’t use any masks. Masked layers are not identified in vector drawables.
Rule 4 : No groups. Creates a lot of unwanted code which creates a mess while converting to vector drawables.
Rule 5 : No rotation. No flip. No transformation.
Your final artboard should look somewhat similar to this.
Here’s the clean SVG exported from Sketch keeping care of the above rules.
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="24px" height="24px" viewBox="0 0 24 24" 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>24x24 dp</title>
<desc>Created with Sketch.</desc><defs><path d="M13.6,9.9 C14.5,7.6 14,4.9 12.1,3 C10.1,1 7.1,0.6 4.7,1.7 L9,6 L6,9 L1.6,4.7 C0.4,7.1 0.9,10.1 2.9,12.1 C4.8,14 7.5,14.5 9.8,13.6 L18.9,22.7 C19.3,23.1 19.9,23.1 20.3,22.7 L22.6,20.4 C23.1,20 23.1,19.3 22.7,19 L13.6,9.9 Z" id="path-1"></path><mask id="mask-2" maskContentUnits="userSpaceOnUse" maskUnits="objectBoundingBox" x="0" y="0" width="22.0329167" height="21.9001586" fill="white">
<use xlink:href="#path-1"></use>
</mask>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="24x24-dp" stroke="#2985C3" stroke-width="2" fill="#3B99D9">
<use id="Shape" mask="url(#mask-2)" xlink:href="#path-1"></use>
</g>
</g></svg>
This long and careful process makes sure that the SVGs you export convert to clean vector drawables. Converting all 200+ icons to SVGs surely took us sometime. But on the brighter side the downloadable application size reduced by 30%.
Update : There have been some major features added to Sketch 43. Shall be writing about them soon.