Reducing the size of an iconfile

18‑09‑2019 Yelitza Jansen 10 min.

About our icons

In our application we use a lot of icons, we have with ease over 130 icons. Icons are a necessary need in our application, they help our users by explain functions and recognize similar elements throughout our application. Without icons understanding the application would be a lot harder for our users. In our application we use icons in different colours. Sometimes we need the colour to be red because we want to give them a warning and sometimes in white because it’s placed on a button with a coloured background.

Name spacing for findability

All our icons are made in Adobe Illustrator by one of our UX designers and are saved as SVG file. Important is that the icon name represents their purpose. Eventually, in our icon CSS file they get a prefix name ‘icon- ‘, so it will be icon-info. The icon will be placed as a background image. But only using the class icon-object doesn’t do the trick in using the icons in our applications. We also use the class ‘icon’ where the standard styling is applied for every icon. Resulting in, for example:

<div class='icon icon-info'/></div>

The problem: Our icon file was to heavy

We love our icons, we love their shape, colours, their meaning and purpose, but we kind of hate their weight. We use our icons in 6 different colours: standard, neutral, warning, negative, positive, new and a bonus white version to place on darker backgrounds. In order to change the fill of an SVG into the correct colour a ‘LESS mixin’ is used. For all these icons we had a separate SVG which means, all the icons had to be loaded in those colours. 130 x 7 colours resulted in one big file. That data needed to be loaded in our application every time. This wasn’t maintainable therefore we needed to look for a better solution.

 

What kind of solution where we looking for and what was important to us

We had the following requirements for the new solution:

  • It needed to reduce the file size.
  • The class names should remain unchanged. 
  • The solution had to be future proof.

Our number one requirement was reducing the file size but also important was that we could still use our current naming convention. How we called upon on icons in our applications must stay the same because replacing every icon in our application with a new class was a no-go. Lastly, it was important that our new way of loading in icons was futureproofed, meaning that if in the future we want to add a new colour for our icons this should be possible.

The search

In order to find a solution, we advised our good old friend Google. We figured out the best way to reduce the data size, was using a sprite sheet. Within the sprite sheet, we found a few solutions which worked for one colour icons, but that didn’t cross out all our requirements since we needed to be able to use the icons in multiple colours. Eventually, we stumbled upon a good example on codepen.io [1] where they use the <view> tag. This gave use the first hint to which direction we were aiming.

From this point we started to read and research more about how sprites are built up and what kind of properties the SVG format should have in order to use it as a sprite sheet. We found a few SVG properties that are very useful when you want to make a sprint sheet for icons. Let’s look at <view>, <symbol> and the <use> tag.

 

<view> definition:

The <view> tag is a defined way to view the image, like a zoom level or a detail view. [2]

<view id='info-neutral-view' viewBox='32 0 16 16' />

With the view tag you can basically tell which part of the SVG you want to show in your screen within the ‘viewBox’. In the <view> tag an ‘id’ can be added which enables you to refer to this icon in your CSS file.

 

<symbol> definition:

The <symbol> element is used to define graphical template objects which can be instantiated by a <use> element. [3]

<symbol id="info"><path xmlns="http://www.w3.org/2000/svg" d="M8 0c-4.418 0-8
3.582-8 8s3.582 8 8 8c4.418 0 8-3.582 8-8s-3.582-8-8-8zM10.635 12.954l-0.193 0.789-
0.098 0.039c-0.503 0.199-0.911 0.352-1.212" />
</symbol>

Around the original SVG path we wrap a <symbol> tag and give it an ’id’. The use tag doesn’t work properly without with a <symbol> tag but with the ‘id’ it knows what to copy.

 

<use> definition:

The <use> tag takes nodes from within the SVG file and duplicates them somewhere else. [4]

<use xlink:href="#info" href="#info" fill="#999992" x="32" y="0" />

The <use> tag makes a copy of the SVG by using the ‘href’ that points to the ’id’ of the <symbol> tag. With the x and y is described where in the sprite the nodes of the SVG can be copied to, which ensures they are not copied over each other. The ‘viewBox’ of the <view> tag navigates to the x and y of the <use> tag. The most important characteristic of the <use> tag is that the fill colour of the SVG can be changed. This means that the copied SVG is not rendered again but only the colour is changed. We only change the colour and in this way our data usage will be reduced significantly. 

 

 

 

By using these tags in an SVG we could make an SVG sprite to our wishes. Accordingly, we use the <view> tag to say where the ‘viewBox’ must navigate to in the sprite and give it an ‘id’ so we can call upon it with CSS. Furthermore, we use the <use> tag in order to only change the fill colour and we use the <symbol> tag to place the icon in the right place by using coordinates. For this to work every colour needs its own <use> tag and <view> tag. On the contrary the <symbol> tag is only used once. In the image below you can read what a full SVG sprite looks like in code. The path is shortened therefore no proper image will be rendered. This example is only to show how an SVG sprite is built up. 

<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"><symbol id="info"><path 
xmlns="http://www.w3.org/2000/svg" d="M8 0c-4.418 0-8 3.582-8 8s3.582 8 8 8c4.418 0 
8-3.582 8-8s-3.582-8-8-8zM10.635 12.954l-0.193 0.789-0.098 0.039c-0.503 
0.1991.136z" />
 </symbol><view id='info-normal-view' viewBox='0 0 16 16' /><use xlink:href="#info" 
href="#info" fill="#3a3a33" x="0" y="0" /><view id='info-normal-hover-view' 
viewBox='16 0 16 16' /><use xlink:href="#info" href="#info" fill="#000000" x="16" 
y="0" /><view id='info-neutral-view' viewBox='32 0 16 16' /><use xlink:href="#info" 
href="#info" fill="#999992" x="32" y="0" /><view id='info-neutral-hover-view' 
viewBox='48 0 16 16' /><use xlink:href="#info" href="#info" fill="#7a7a77" x="48" 
y="0" /><view id='info-warning-view' viewBox='64 0 16 16' /><use xlink:href="#info" 
href="#info" fill="#ffb700" x="64" y="0" /><view id='info-warning-hover-view' 
viewBox='80 0 16 16' /><use xlink:href="#info" href="#info" fill="#e6a400" x="80" 
y="0" /><view id='info-negative-view' viewBox='96 0 16 16' /><use xlink:href="#info" 
href="#info" fill="#e33724" x="96" y="0" /><view id='info-negative-hover-view' 
viewBox='112 0 16 16' /><use xlink:href="#info" href="#info" fill="#b02b1c" x="112" 
y="0" /><view id='info-positive-view' viewBox='128 0 16 16' /><use xlink:href="#info" 
href="#info" fill="#28ab65" x="128" y="0" /><view id='info-positive-hover-view' 
viewBox='144 0 16 16' /><use xlink:href="#info" href="#info" fill="#1c7847" x="144" 
y="0" /><view id='info-new-view' viewBox='160 0 16 16' /><use xlink:href="#info" 
href="#info" fill="#0076a3" x="160" y="0" /><view id='info-new-hover-view' 
viewBox='176 0 16 16' /><use xlink:href="#info" href="#info" fill="#005070" x="176" 
y="0" /><view id='info-selected-view' viewBox='192 0 16 16' /><use xlink:href="#info" 
href="#info" fill="#ffffff" x="192" y="0" /><view id='info-heading-view' 
viewBox='208 0 16 16' /><use xlink:href="#info" href="#info" fill="#506762" x="208" 
y="0" /><view id='info-accent-view' viewBox='224 0 16 16' /><use xlink:href="#info" 
href="#info" fill="#6c8f89" x="224" y="0" /><view id='info-button-view' 
viewBox='240 0 16 16' /><use xlink:href="#info" href="#info" fill="#3a3a33 " x="240" 
y="0" /><view id='info-disable-view' viewBox='256 0 16 16' /><use xlink:href="#info" 
href="#info" fill="#b3b3b1" x="256" y="0" /></svg>

 

The CSS tells us which icon to load as a background image. Meaning the classes stayed the same but now an URL is used which refers to a part in an icon sprite sheet. It was now clear to us how to make an SVG sprite and how to render the right part of the SVG sprite with CSS.

Embedding the icon in CSS will look like this:

<span class="icon icon-info icon-color-warning" title=""></span>

With CSS we call upon the icon we want and what colour it should be. For this a ‘::before pseudo’ is used to add a background image.

.icon.icon-above.icon-color-warning::before {
    background-image: url(img/icons/above.svg#above-warning-view);
}

 After thinking about implementing this process we realised that making 130 sprites manually would mean a lot of labour. To solve this, we decided to make an icon generator with PHP. This icon generator takes SVGs from a source directory where all our cleaned SVGs are located. The icon generator then transforms SVGs into a sprite sheet which are added in a build directory.

 

The mistakes we made

We made a ‘less’ file that contains mixins which generates CSS names which we can call upon to add an icon to our application. In the beginning we put all these mixins in one big ‘less’ file.

A Mixin is a feature that is only used in ‘less’ which means we had to make this file with ‘less’ instead of CSS. After testing this method, we found out that our icons were loading very slowly. By using our inspector, we found out that the problem was the ‘less compiler’. The compiler could not handle rendering so many mixins at once, since we are talking about mixins for 130 icons. To solve this, we split our ‘less’ file in two separated ‘less’ files so our less compiler could handle the mixins since they were not loaded simultaneously.

Putting our sprites sheet to work

The newly set up system worked after we copied the SVG sprites in our Design System and changed the path of the background image. Now, whenever we want to insert an icon, we use our icon generator to generate the SVG sprite, copy the sprite to our Design System, add some CSS and voila! In order to communicate this system to our colleagues, we have made a Wiki page which explains the process and the implementation step-by-step.

Conclusion

Our biggest problem was that our icon data was getting too big. This is solved with our new way of loading our SVG icons. We improved our performance in our applications because the data we load in the applications decreased a lot. Accompanied by the fact that the new system makes it is easy to add new icons in our Design System and we didn’t need to change our naming convention. Overall, we would advise this method to everyone who desires a smooth-running icon system in their CSS. 

 

 



Sources 

front-end Design System icons EN

Deel deze blog