Generating Spritesheets with Grunt and Spritesmith

CSS Sprites can greatly increase the loading speed of web sites, by reducing the number of HTTP requests. Multiple images are combined into a single image and individual image regions are defined using a stylesheet. Creating spritesheets manually can be a long a tedious process. There are a number of tools one can use to assist with creating sprites, but wouldn't it be better if it were just part of the build process? It is now possible to do just that using Grunt and Spritesmith. I'll walk you through setting it up.

Grunt is a build process automation tool for web projects. It's like using Make, but the rules and tasks are defined in JavaScript. Grunt is built on top of Node.js, but your project doesn't need to have any server-side scripting to use it. In fact, it really doesn't need to be a web-based project at all, but most of the built-in tasks and plug-ins are of course geared towards web projects.

If you are not already using Node.js, you'll need to install it using the installer provided on nodejs.org. When you have Node.js set up and working, you'll want to install Grunt globally. This is quite easy using NPM. You can install Grunt using the following command. You will most likely need to use sudo to elevate your privileges and install Grunt globally.

npm install -g grunt-cli

After installing the Grunt command-line interface, you should be able to run the Grunt executable by typing grunt. If you can't, then there's a problem with your PATH. Check to see that /usr/local/bin is in your PATH.

$ grunt
grunt-cli: The grunt command line interface. (v0.1.6)

Fatal error: Unable to find local grunt.

If you're seeing this message, either a Gruntfile wasn't found or grunt
hasn't been installed locally to your project. For more information about
installing and configuring grunt, please see the Getting Started guide:

http://gruntjs.com/getting-started

If you successfully run the Grunt executable, you should see it complain that it can't find a Gruntfile. That's because we have not made one yet. A Gruntfile is the Grunt equivalent of a Makefile, if you are familiar with Make. We'll start out by creating a sprite task, by creating a file called Gruntfile.js in the root folder of our project.

module.exports = function(grunt) {
    grunt.initConfig({
        sprite: {
            dist: {
                src: ['sprites/*.png'],
                destImg: 'public/images/sprite.png',
                destCSS: 'less/sprite.less',
                cssFormat: 'less',
                imgPath: '../images/sprite.png',
                algorithm: 'left-right'
            }
        }
    });

    grunt.loadNpmTasks('grunt-spritesmith');
    grunt.registerTask('default', 'sprite');
};

Here's what those properties mean.

| Property | Meaning | |------------|----------------------------------------------------------| | src | The images to combine. | | destImg | The name of the combined image. | | destCSS | The stylesheet to create. | | cssFormat | The format of the stylesheet to output. | | imgPath | The path of the combined image to use in the stylesheet. | | algorithm | How to organize the resultant image. |

Note that I'm also using the LESS stylesheet language because it will also allow us to efficiently combine the styles created by Spritesmith with our own styles. We now need to add Spritesmith and LESS as dependencies. Modify or create your package.json file to include grunt-spritesmith and grunt-contrib-less as devDependencies.

{
    "name": "spritesmith-example",
    "version": "0.0.1",
    "private": true,
    "devDependencies": {
        "grunt": "~0.4.0",
        "grunt-spritesmith": "~0.5.2",
        "grunt-contrib-less": "~0.5.0"
    }
}

Spritesmith also requires that you install either Cairo or Graphics Magick. For this tutorial, I'll install Cairo via the Homebrew ports system on OS X.

$ brew install cairo

After installing Cairo or Graphics Magick, you can install your grunt-spritesmith and grunt-contrib-less dependencies by executing the following command in the project root.

npm install

Now you need to add some images to create your spritesheet. For the purposes of this demonstration, I will use the following 3 images. You can download them here. If you're following along you should unzip the file and put the 3 images in the sprites folder we specified in Gruntfile.js.

You should now be able to generate your spritesheet by executing the grunt command in the root folder of your project.

$ grunt
Running "sprite:dist" (sprite) task

Done, without errors.

If you open the generated file public/images/sprite.png, you should see something that looks like the following image.

The 3 source images have been combined into a single resultant image. You should also find a LESS stylesheet located at less/sprite.less which describes the properties of the images.

Now that you've created your spritesheet, we need to use it. Create a new LESS spreadsheet located at less/sprite.less that looks like this.

@import "sprite.less";

.kiwi-image {
    .sprite(@image1);
}

.windmill-image {
    .sprite(@image2);
}

.tree-image {
    .sprite(@image3);
}

This file imports the generated sprite.less stylesheet and then defines 3 styles that use them. Notice that Spritesmith has created styles that match your image filenames, so you probably want to give your images more meaningful filenames than image1.png, image2.png, and image3.png like we did in this tutorial. It should also be noted that you can put your other site related styles in this file or create other LESS stylesheets and import them here.

You now need to update Gruntfile.js to compile your LESS stylesheet. You should load and configure the grunt-contrib-less task resulting in the following file.

module.exports = function(grunt) {
    grunt.initConfig({
        sprite: {
            dist: {
                src: ['sprites/*.png'],
                destImg: 'public/images/sprite.png',
                destCSS: 'less/sprite.less',
                cssFormat: 'less',
                imgPath: '../images/sprite.png'
            }
        },
        less: {
            dist: {
                options: {
                    paths: ['less']
                },
                files: {
                    'public/stylesheets/site.css': 'less/site.less'
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-spritesmith');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.registerTask('default', ['sprite', 'less']);
};

You should also note that I've changed the default task to first generate the spritesheet and then compile the LESS stylesheet. You should now be able to run grunt again to have your stylesheet generated.

$ grunt
Running "sprite:dist" (sprite) task

Running "less:dist" (less) task
File public/stylesheets/site.css created.

Done, without errors.

You can now use individual images on your spritesheet by using the classes we defined. Here is an example HTML file using the windmill image.

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="stylesheets/site.css">
</head>
<body>
    <div class="windmill-image"></div>
</body>
</html>

Finally, here is what an individual image being used looks like.

Now that you've automated your spritesheet generation, you will be able to easily add more images to the sprites folder and run grunt again to generate a new spritesheet.

Posted on Feb 20, 2013
Written by Emlyn Murphy