しるてく

技術的な話をします

compassでcssスプライトするときの出力をできるだけ少なくする試み

概要

Sprite layouts | Compass Documentation

compassでのcssスプライトを試してみたのでメモ。
sprite-backgroundっていうmixinは結構色々な人がブログに書いてるんだけど、retina対応していなかったり、無駄な処理が入っていたりしてなんかしっくりこなかったので自分で実装してみた。

完成品

以下のファイルは使い回せるので、mixins/_sprite.scssみたいにプロジェクトに依存しないファイルとして置いておく。

@mixin sprite-background-size($name, $sprites, $device-pixel-ratio: 2) {
  $_width:  image-width(sprite-file($sprites, $name)) / $device-pixel-ratio;
  $_height: image-height(sprite-file($sprites, $name)) / $device-pixel-ratio;
  height: $_height;
  width: $_width;
  background-size: $_width auto;
}

@mixin sprite-background-position($name, $sprites, $device-pixel-ratio: 2) {
  $_pos: sprite-position($sprites, $name);
  $_x: round(nth($_pos, 1) / $device-pixel-ratio);
  $_y: round(nth($_pos, 2) / $device-pixel-ratio);
  background-position: $_x $_y;
}

@mixin sprite-background-image($name, $sprites, $sprites-image, $display: block) {
  display: $display;
  background-image: $sprites-image;
  background-repeat: no-repeat;
}

// shortcut
@mixin sprite-background($name, $sprites, $sprites-image, $display: block, $device-pixel-ratio: 2) {
  @include sprite-background-image($name, $sprites, $sprites-image, $display);
  @include sprite-background-position($name, $sprites, $device-pixel-ratio);
  @include sprite-background-size($name, $sprites, $device-pixel-ratio);
}

使用方法

単純に色々な画像突っ込んだsprite画像の場合、またはCSS大きくても気にしないよって場合

scss
$sprites-all: sprite-map("all/*.png", $layout: smart);
$sprites-all-image: sprite-url($sprites-all);

.star {
  @include sprite-background('star', $sprites-all, $sprites-all-image);
}
.banner {
  @include sprite-background('banner', $sprites-all, $sprites-all-image);
}
.logo {
  @include sprite-background('logo', $sprites-all, $sprites-all-image);
}
css
.star {
  display: block;
  background-image: url('/img/all-s5858cd14d5.png');
  background-repeat: no-repeat;
  background-position: 0 0;
  height: 16px;
  width: 16px;
  background-size: 16px auto;
}

.banner {
  display: block;
  background-image: url('/img/all-s5858cd14d5.png');
  background-position: -16px 0;
  background-repeat: no-repeat;
  height: 30px;
  width: 80px;
  background-size: 80px auto;
}

.logo {
  display: block;
  background-image: url('/img/all-s5858cd14d5.png');
  background-position: 0 -16px;
  background-repeat: no-repeat;
  height: 40px;
  width: 120px;
  background-size: 120px auto;
}

アイコンとかhoverとか同じサイズの画像が並んだsprite画像の場合

width, heightとか余計にアレするの嫌なので、そういうのは共通のクラスでやって、個別にはpositionしか書かない。

scss
$sprites-pager: sprite-map("pager/*.png", $layout: smart);
$sprites-pager-image: sprite-url($sprites-pager);
@mixin sprite-background-pager-base($name) {
  @include sprite-background-image($name, $sprites-pager, $sprites-pager-image);
  @include sprite-background-size($name, $sprites-pager);
}
@mixin sprite-background-pager-position($name) {
  @include sprite-background-position($name, $sprites-pager);
}

.prev-pager {
  @include sprite-background-pager-base('prev');
  @include sprite-background-pager-position('prev');

  &:hover {
    @include sprite-background-pager-position('prev-hover');
  }
  &.disable {
    @include sprite-background-pager-position('prev-disable');
  }

css

.prev-pager {
  display: block;
  background-image: url('/img/pager/pager-s3354cd445.png');
  background-repeat: no-repeat;
  height: 40px;
  width: 70px;
  background-size: 70px auto;
  background-position: 0 0;
}

.prev-pager:hover {
  background-position: 0 -40px;
}

.prev-pager.disable {
  background-position: 0 -80px;
}

特徴

optionで表示をカスタマイズしやすく

  • sprite画像使う要素のdisplayはblockにしたいときとinline-blockにしたいときがあったのでoptionで渡せるようにした
  • retina対応用にdevice-pixel-ratioを渡せるようにした
    • 普通に"/ 2"とかやると、何やってるのかわかりづらいので変数名で何やっているのかわかりやすくした

mixinを細かく分けて出力をカスタマイズしやすく

  • positionだけ渡したいなと思って、positionだけ吐くmixinを用意してsprite-backgroundで@includeするようにした
    • 細かくimage, size, positionに分けたのでさらに頑張りたい場合は、それぞれの画像サイズが違うspriteの場合でもimageの部分だけ共通クラスにあてることもできる

その他細かいところ

  • sprite-urlを@mixinの外でやっているのはコンパイルの高速化のため
  • sprite-mapで$layout: smartすると余白を埋める感じで画像作ってくれる