grunt-spritesmith を使って LESS でもスプライト画像を自動生成する

多数の小さな画像を 1 枚の画像の上に並べ、CSS で切り分けることにより、サーバへの問い合わせの回数を減らして Web ページの表示を高速化する CSS スプライトと呼ばれる手法がある。これまで Sass + Compass ではできていたが、Grunt をはじめとする自動化ツールが充実してきたおかげで LESS でも可能になった。
あらかじめ Grunt と grunt-spritesmith をインストールし設定しておく。方法は先日の記事を参照。

Gruntfile.js を書く

通常と同じように loadNpmTasks() でタスクを読み込み、 initConfig() に設定を書く。

grunt.loadNpmTasks('grunt-spritesmith');

grunt.initConfig({
	sprite: {
		all: {
			src: "src/sprites/*.png",
			destImg: "ftp_root/public_html/common/img/sprite.png",
			destCSS: "src/less/sprite.less",
			imgPath: "../img/sprite.png",

			algorithm: "binary-tree",
		}
	},
	...

destCSS のファイル名の終わりを “.less” にすると、LESS のミックスインとして出力される。
imgPath には、最終出力時の CSS ファイルから見たスプライト画像のパスを指定する。
algorithm で画像の並べ方を指定できる。最も充填できる “binary-tree” を指定した。

テンプレートを書き換える

この設定で LESS ファイルは出力できるものの、 LESS Compiler 1.5.1 では書法が変わっておりコンパイルできない。そこでテンプレートを書き換えて 1.5.1 でもコンパイルできるようにする。
もとのテンプレートは node_modules/grunt-spritesmith/node_modules/json2css/lib/templates/less.template.mustache に配置されている。きわめて汎用的に書かれているが、実際そこまで使うことはないのでもっと簡素に片付けることにした。

{{#items.0}}.sprite() { background-image: url({{{image}}}); }{{/items.0}}
{{#items}}
.sprite-{{name}}() { .sprite; width: {{px.width}}; height: {{px.height}}; background-position: {{px.offset_x}} {{px.offset_y}}; }
{{/items}}

テンプレートを用意したら Gruntfile.js を修正する。cssTemplate の設定を追加した。

grunt.initConfig({
	sprite: {
		all: {
			src: "src/sprites/*.png",
			destImg: "ftp_root/public_html/common/img/sprite.png",
			destCSS: "src/less/sprite.less",
			imgPath: "../img/sprite.png",

			algorithm: "binary-tree",

			// テンプレート設定
			cssTemplate: "src/sprite-template.less",
		}
	},
	...

これでもっと簡素な .less ファイルが出力されるはずである。
使うときは次のようにする。

.btn-download:before {
	content: "";
	display: inline-block;
	.sprite-download; // ここに展開される
}

おまけ

grunt-spritesmith のほかに、分散したメディアクエリをまとめる grunt-group-css-media-queries、不要な空白を取り除く grunt-contrib-cssmin も入れ、grunt-watch でファイルの更新を監視できるようにした Gruntfile.js 全体を Gist に公開した。スプライト画像が更新される頻度はそう高くないので監視対象には含めていない。