Last Updated: February 25, 2016
· sevenupcan

Designing Scalable Icons Using CSS background-size

There are already a lot of ways to create scalable icons but one of the methods that is often overlooked is using background-size. Background-size has the added advantage that you can design an icon exactly the way you want without worrying about the limitations of doing it in CSS.

View the demo

Using one icon

Design your icon in Photoshop using vectors and scale it to as big as you'll ever need it. So for example. If the smallest sized icon you have is 16px square and the largest is 128px square, design your icon at 16px square and scale it to 128px (400%).

Then save the image at the larger size and use background-sizing to make it fit.

.icon {
    width: 16px;
    height: 16px;
    background-image: icon.png;
    background-size: 100%;

When you're using one icon its pretty straight forward.

Now you can use the same image for every size of that icon.

.icon.tick {
    width: 128px;
    height: 128px;

Using a sprite with multiple icons

When you're using a sprite it gets a little bit trickier because you must work out the positioning for each icon in your sprite. Once you create a formular to work this out though it gets a lot easier.

First save all your icons into one sprite and then include the new image in your CSS and up the background-sizing to acknowledge the new icons. This should be 100 multiplied by the number of icons you have in your sprite.

.icon {
    width: 16px;
    height: 16px;
    background-image: icon-sprite.png;
    background-size: 500%;

Then work out the positioning for each icon.

.icon.tick { background-position: 0 0; }
.icon.cross { background-position: 25% 0; } { background-position: 50% 0; }
.icon.warning { background-position: 75% 0; }
.icon.compass { background-position: 100% 0 }

You can work this out by using:


That's the total number of icons multiplied by a hundred divided by the index of the icon minus one.

Using this technique, you can create resolution independent icons simply by creating a large enough asset to work at the resolutions you want it to support. Although it does mean all devices will be forced to download a larger high res asset, it is a fairly painless way to handle images across multiple resolutions.

Using SASS to do all the hard work

I got tired of recalculating the positioning so I created a function which does it for me.

@mixin icon($index, $size) {
    line-height: 1;
    vertical-align: middle;

    &:before {
        // Manually define the icon set */
        $columns: 5; // Number of icons going across
        background-image: url(icons/large/sprite.png);
        background-size: $columns * 100%;

        // Size icon will be displayed */
        width: #{$size}px;
        height: #{$size}px;

        // Position background-image based on number of icons in sprite */
        background-position: #{(100/($columns - 1)*($index - 1))}% 0;   

        // Set position to inline */
        content: "";
        margin-right: #{$size/4}px; 
        display: inline-block;
        line-height: #{$size}px;
        vertical-align: middle;

Call the icon like so

.icon {
    @include icon(5, 24);

2 Responses
Add your response

I got it to work partially, it doesn't work with sprites that have vertical icons.

over 1 year ago ·

Thanks for commenting. I think I know of the problem you're experiencing. Have you tried it using a horizontal and vertical values for the background-size? I think the trouble you have with using both vertical and horizontal vertices is that you have to constantly change these values and you have to stick to even or odd numbers. I found it easier just to put all my icons into one straight line.

over 1 year ago ·