スプライトにアイコンをパックしてWEBを高速化しよう

はじめに

大量のアイコンをすべて別々にurlでリンクを張るとリソース読み込みにかなりの時間がかかります

そこですべてのアイコンをまとめたスプライト画像をひとつ作り、それをダウンロードしてcssで必要なアイコンのUV位置を変えることでページ読み込みを高速化する方法がよくとられます

実装

今回はgulp+spritesmithでまとめます

spritesmithはいくつか手段がありますがcli版がなんかwindowsでいくつかエラーが出てすぐに動かせそうになかったのでgulp版を使用します

インストール

npmの説明は割愛します
nodeをインストールするとnpmも入ると思います => https://nodejs.org/ja

まずgulpをインストールします
gulpはタスクランナー、様々なタスクを登録してアセットパイプラインを組むことができます

1
2
cd 作業したいフォルダ
npm install gulp --save-dev

--save-devオプションはローカルインストールするためのオプションです
この辺はお好みでどうぞ

続いてspritesmithをインストールします
spritesmithはスプライトパックのための便利ライブラリ
gulp用の拡張であるgulp.spritesmithをローカルにインストールします

1
npm install --save-dev gulp.spritesmith

スプライトをパックするだけなら上記で終了ですが、今回はアイコンのサイズもそろえてみたいので追加でパッケージgulp-image-resizeを入れます

内部的にGraphicsMagickというツールを使用するみたいなのでこちらからインストールしてください => http://www.graphicsmagick.org/

完了したらnpm installします

1
npm install --save-dev gulp-image-resize

インストールは以上です

gulpfile.jsを書く

gulpの実行スクリプトを書きます

コードを掲載しておくとsprite化のコードは以下

gulpfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const gulp = require('gulp');
const spritesmith = require('gulp.spritesmith');

const src_dir = 'illust';
const dst_dir = 'output';

gulp.task('sprite', () => {
const src = src_dir + '/*.png';
const dst = dst_dir;
const param = {
imgName: 'icon_sprite.png', // 生成される画像ファイル
cssName: 'icon_sprite.css', // 生成されるCSSファイル
imgPath: '/css/images/icon_sprite.png', // css内でのスプライト画像へのパス
padding: 2 // アイコン同士の余白
};

return gulp.src(src)
.pipe(spritesmith(param))
.pipe(gulp.dest(dst));
});

これを作業フォルダにおいて、以下のgulp実行コマンドをたたけば、illustフォルダ以下の.png画像をパッキングしてoutputフォルダ以下にスプライト画像と.cssが生成されます

1
node_modules/.bin/gulp sprite

今回gulpもローカルにインストールしているので上記のようにローカル.binのパスから実行コマンドをたたきます

spritegulp(タスク名, タスク関数)で登録した名前になるので適宜変更してください

以下が生成物です

.cssには以下のよう各アイコンの座標が書かれているクラスicon-ファイル名が生成されます

1
2
3
4
5
6
.icon-monster06 {
background-image: url(/css/images/icon_sprite.png);
background-position: -289px -100px;
width: 48px;
height: 48px;
}

これをhtmlで使用する場合は次のように<div>のクラスとして指定すれば描画されます

1
<div class="icon-monster06"></div>

アイコンをそろえる

特にアイコンサイズがバラバラでも問題なければ上記までの処理で問題ないです

ところがこれをそろえて表示したい場合、後からだと結構面倒です

生成される.css側のサイズを調整するなどの方法でもできるのですが( https://teratail.com/questions/102820 )、実装が厄介なのでアイコン側をそろえることで対応します

gulpfile.jsに以下のようにタスクを組みます

gulpfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const gulp = require('gulp');
const imageResize = require("gulp-image-resize");

const src_dir = 'illust';
const dst_dir = 'output';

gulp.task('resize', () => {
const src = src_dir + '/*.png';
const dst = tmp_dir;
const param = {
height: 48,
crop: false,
upscale: false,
sharpen: true
};
return gulp.src(src)
.pipe(imageResize(param))
.pipe(gulp.dest(dst));
});

これでサイズを揃えてspriteを実行するといい感じになります

さいごに

余談ですがネイティブだとフォントとかUIを一つにまとめたものをアトラステクスチャなんて言い方をしますが、WEBだと単純にスプライトって言うんですね