12周年記念パーティ開催! 2024/5/10(金) 19:00

Compassで簡単、CSSスプライト作成 第1回 CSSスプライト作成の基礎

CompassでCSSスプライトが手軽にできるのをご存知ですか? この記事ではCompassでCSSスプライトを作成する基礎を解説します。業務で使うものですから、生成の仕組みもおさえておきましょう。

発行

著者 高津戸 壮 テクニカルディレクター
Compassで簡単、CSSスプライト作成 シリーズの記事一覧

はじめに

手作業で作ると、ものすごい手間がかかってしまうCSSスプライトですが、Compassを使えば、非常に簡単に実装することができます。このシリーズではCompassのCSSスプライト機能を解説し、Retinaディスプレイ対応のCSSスプライトmixinを作ってみます。

Compassと私

Compassについては、CodeGridでSassの連載時に、簡単に触れました。

CompassはオープンソースのCSSフレームワークです。Rubyで書かれています。SassはCSSにほしかったあんな機能、こんな機能をいろいろと実現してくれるものですが、Compassは、Sassに便利に使えるmixin集をセットにしたようなものです。

このCompass、筆者はSassを使い出した頃には手軽でよく使っていたのですが、最近はめっきり使わなくなっていました。その大きな理由としては、筆者がただ単に便利なmixin集がほしいだけだったからです。筆者はCompassの代わりに、Bourbonというmixinのライブラリをよく使っていました。

このBourbonはSassファイルの中でただ@importするだけで利用できて、非常に手軽です。これに対しCompassの場合、Compassをインストールしたあと、compassコマンドでコンパイルしなければなりません。CompassはSassを完全にラップした存在であり、別のプログラムになっているのです。このような点について、自分の用途に対して、Compassは無駄に巨大であると感じていました。またコンパイルにも、やや時間がかかる気もしていて、Compassを使うのをやめていました。

しかし、とある仕事でチームのメンバーが、Compassを使いCSSスプライトを手軽に実装しているのを見て「これは便利だ、Compass以外でやるととてつもなく面倒だぞ」と思いました。そこで、改めてCompassのCSSスプライト機能を調べてみるに至ったのです。CompassはRubyのプログラムであるため、Sassの機能だけでは実現できないことを、うまいことやってくれるのです。CSSスプライト作成は、そのCompassがやってくれる素敵な機能のひとつです。

CompassのCSSスプライトを、もし手作業で実装するとしたら、ものすごい手間がかかりますし、運用もとても複雑になってしまいます。CSSスプライトを利用したいなら、そのためだけにCompassを利用する価値があるなと筆者は感じました。

このシリーズではCompass*のCSSスプライト機能を解説し、最終的にRetinaディスプレイ対応のmixinを作っていきます。またCSSスプライトを使う上での注意点などについても併せて触れていきます。なお、Compassの基本的な使用方法については省略します。

*注:Compassのバージョン

このシリーズでは、Compass 0.12.2 (Alnilam) を使用して検証しています。CompassやSassのバージョンアップにより、本シリーズ内容の互換性が確保されない可能性がありますのでご注意ください。

今回の記事の中で使用するサンプルは、以下よりダウンロードできます。記事内容とともに、こちらも参照してください。

サンプルダウンロード

サンプル中に使用されている画像はOpen Icon Libraryのものを使用しています。著作権はそれぞれの著作者にあります。(ライセンス:Creative Commons - Attribution-Share Alike 3.0 License)。

なお上記リポジトリにアップロードされているファイルには、Compassがコンパイルして生成したファイルも含まれています。ご自身で試したい場合はCompassが生成するファイル(CSSファイルとCompassが作ってくれる画像)を削除したあと、compass compileコマンドを打つと、動作を確認できます。

サンプル1:とりあえずいちばん簡単な方法

まずはじめに、もっとも簡単にCSSスプライトを実装する方法について解説します。Compassは特に難しいことを覚えなくても、非常に手軽にうまいことCSSスプライトを作ってくれる機能を持っています。以下よりこのサンプルの内容を参照できます。

サンプル1

以下がサンプルのページです。

まずはファイルの構造を確認してみましょう。

ファイル構造

├── config.rb
├── html
│   └── 1.html
├── images
│   ├── icon
│   │   ├── face-cool.png
│   │   ├── face-sad.png
│   │   └── face-wink.png
│   └── icon-s51e5ca4f42.png // コンパイルして作られた画像
├── sass
│   └── styles.scss
└── stylesheets
    └── styles.css // コンパイルして作られたCSS

このサンプルでは、3つのアイコン画像をPNGで用意しています。それらをSCSS内でCSSスプライトのために使うと、Compassは自動的にCSSスプライトの画像を作ってくれます。icon-s51e5ca4f42.pngというのがそのファイルです。この画像についてはのちほど解説します。

HTML

HTMLはアイコンのspanを配置しているだけの非常に単純なものにしてあります(body内の内容だけを以下に示しています)。

<span class="icon-face-cool"></span>
<span class="icon-face-sad"></span>
<span class="icon-face-wink"></span>

画像

今回用意したアイコン画像は、次の3つです。

SCSS

この画像を元にCompassにCSSスプライトをうまいことやってもらうわけですが、その記述方法は非常に単純です。SCSSファイルを見てみます。

@import "icon/*.png";
@include all-icon-sprites;

.icon-face-cool { width:48px; height:48px; }
.icon-face-sad { width:48px; height:48px; }
.icon-face-wink { width:128px; height:128px; }

// デバッグ用

span {
  display:inline-block;
  border:3px solid #000;
}

CSSスプライトの実装のために必要なのは、始めの2行だけです。このように書くだけで、Compassは画像ディレクトリ(config.rb内で指定)直下にあるiconディレクトリ直下のPNG画像をすべて読み込み、CSSスプライト用のスタイルを一気に書き出してくれます。あとは各要素の幅と高さを指定してやれば完了です。

ハイ、以上! CompassでCSSスプライトを使う手順はこれで終わりです!

……でもいいのですが、引き続き、どのようなCSSが書き出されるのか見てみましょう。

コンパイルして作られたCSS/画像

以下が、前掲のSCSSをコンパイルしたときに作られるCSSです。backgroundと、background-positionに、CSSスプライトの記述がなされているのが確認できます。

.icon-sprite, .icon-face-cool, .icon-face-sad, .icon-face-wink {
  background: url('../images/icon-s51e5ca4f42.png') no-repeat;
}

.icon-face-cool {
  background-position: 0 -128px;
}

.icon-face-sad {
  background-position: 0 -176px;
}

.icon-face-wink {
  background-position: 0 0;
}

.icon-face-cool {
  width: 48px;
  height: 48px;
}

.icon-face-sad {
  width: 48px;
  height: 48px;
}

.icon-face-wink {
  width: 128px;
  height: 128px;
}

span {
  display: inline-block;
  border: 3px solid #000;
}

このようにCompassのCSSスプライト機能を使った場合、CompassはPNGファイルの親ディレクトリの名前をベースの名前として使用します。このサンプルの場合、iconです。これに合わせSCSSファイルの2行目で、CSSスプライト設定用にincludeするmixinも、@include all-icon-sprites;と、all--spriteの間にiconを挟んだ名前にします。

PNGを読み込む@imoprtと、CSSスプライト用のmixin。この2行を書けばCompassは上記CSSの通り、icon-から始まり、ファイル名をクラスとして扱ったセレクタと、対応するスタイルを書き出します。

このCSS内において、始めの方で変なファイル名の画像を参照しているのがわかります。この画像は、Compassが自動的に作ってくれたCSSスプライト用の画像です(以降、スプライトマップと呼びます)。この画像は、次のようなものです。

スプライトマップのファイル名には、ランダムな文字列が含まれます。ブラウザにキャッシュを残させないようにするため、このような文字列が毎回ランダムで付加されるようになっているらしいです。

スプライトマップ上での各アイコンの位置をいちいち計算することを考えると、このようなCSSスプライト用の画像を自分で作り運用していくのには、手間と時間がかかることが容易に想像できます。

ですがCompassを使えば、いつも通りひとつずつ画像を書き出すのに加え、たった2行の記述をするだけで、このような画像を合成する処理を行ってくれます。とりあえずこれだけでも、Compassを使えば、手軽にCSSスプライトが実装できるのがおわかりいただけるのではないでしょうか。

ちなみにCSSスプライトの機能は、PNGに対してしか行えませんので注意してください(Compass 0.12.2時点)。

サンプル2:2つのスプライトマップを作る

次のサンプルでは2つのスプライトマップを作ってみます。今回は顔のアイコンと、オーディオ関係のアイコンを別のスプライトマップにしました。

サンプル2

以下がサンプルのページです。

HTML

先ほどのサンプルと同様、アイコンを配置するための要素を準備します。クラス名と、以降の画像ディレクトリ、ファイル名を見比べてみてください(body内の内容だけを以下に示しています)。

<span class="face-cool"></span>
<span class="face-sad"></span>
<span class="face-wink"></span>
<span class="audio-headset"></span>
<span class="audio-keyboard"></span>
<span class="audio-speaker"></span>

画像

顔のアイコンはfaceディレクトリに、オーディオ関係のアイコンはaudioディレクトリに配置しています。顔のアイコンはファイル名は異なりますが、先ほどサンプル1で使ったものと同じです。

SCSS

先ほどのサンプルではiconだった場所が、audiofaceになっているのに注目してください。それ以外は特に変わった部分はありません。

@import "icon/audio/*.png";
@import "icon/face/*.png";
@include all-audio-sprites;
@include all-face-sprites;

.face-cool { width:48px; height:48px; }
.face-sad { width:48px; height:48px; }
.face-wink { width:128px; height:128px; }
.audio-headset { width:128px; height:128px; }
.audio-keyboard { width:128px; height:128px; }
.audio-speaker { width:32px; height:32px; }

// デバッグ用

span {
  display:inline-block;
  border:3px solid #000;
}

コンパイルして作られたCSS/画像

コンパイル結果として作られるのは、以下のようなCSSです。

.audio-sprite, .audio-headset, .audio-keyboard, .audio-speaker {
  background: url('../images/icon/audio-sf2be771957.png') no-repeat;
}

.face-sprite, .face-cool, .face-sad, .face-wink {
  background: url('../images/icon/face-s820149b219.png') no-repeat;
}

.audio-headset {
  background-position: 0 0;
}

.audio-keyboard {
  background-position: 0 -128px;
}

.audio-speaker {
  background-position: 0 -256px;
}

.face-cool {
  background-position: 0 -128px;
}

.face-sad {
  background-position: 0 -176px;
}

.face-wink {
  background-position: 0 0;
}

.face-cool {
  width: 48px;
  height: 48px;
}

.face-sad {
  width: 48px;
  height: 48px;
}

.face-wink {
  width: 128px;
  height: 128px;
}

.audio-headset {
  width: 128px;
  height: 128px;
}

.audio-keyboard {
  width: 128px;
  height: 128px;
}

.audio-speaker {
  width: 32px;
  height: 32px;
}

span {
  display: inline-block;
  border: 3px solid #000;
}

始めのところで読み込んでいる2つの背景画像は、Compassが作った2つのスプライトマップです。

このようにCompassは、@importでPNGファイルをまとめて読み込み、all-マップ名-spritesというmixinをincludeするだけで、CSSスプライトを作ってくれます。

サンプル3:自分でセレクタを定義する

ここまでのサンプルでは、Compassが勝手にセレクタを定義してくれていました。しかし自分でセレクタ部分を定義したいケースは多いでしょう。このサンプルでは、その方法を解説します。

サンプル3

以下が、サンプルのページです。

HTML

このサンプルでは、HTMLの構造を変更しています。

<div class="faces">
  <span class="cool"></span>
  <span class="sad"></span>
  <span class="wink"></span>
</div>

ここに、どのようにCSSスプライトを適用していくのか見いきましょう。

画像

使用する画像は、サンプル1で使用した画像と同じです。

SCSS

今回のサンプルでは、これまでのサンプルで使っていたall-マップ名-spritesというmixinをincludeしていません。代わりにicon-spriteというmixinをincludeしている点に注目してください。

@import "icon/*.png";

.faces {
  .cool {
    @include icon-sprite(face-cool);
    width:48px;
    height:48px;
  }
  .sad {
    @include icon-sprite(face-sad);
    width:48px;
    height:48px;
  }
  .wink {
    @include icon-sprite(face-wink);
    width:128px;
    height:128px;
  }
}

// デバッグ用

span {
  display:inline-block;
  border:3px solid black;
}

コンパイルして作られたCSS/画像

とりあえず、どのようなCSSができるのかを先に見てみましょう。

.icon-sprite, .faces .cool, .faces .sad, .faces .wink {
  background: url('../images/icon-s51e5ca4f42.png') no-repeat;
}

.faces .cool {
  background-position: 0 -128px;
  width: 48px;
  height: 48px;
}
.faces .sad {
  background-position: 0 -176px;
  width: 48px;
  height: 48px;
}
.faces .wink {
  background-position: 0 0;
  width: 128px;
  height: 128px;
}

span {
  display: inline-block;
  border: 3px solid black;
}

これまでのサンプルとは異なり、自分で定義したセレクタに、ちゃんとCSSスプライトの指定がされているのがわかります。このサンプルで作られたスプライトマップは以下です。

Compassがやってくれていること

さて、このSCSSファイル内で起きていることを少し解説します。

まず、以下のようなPNGのimportの記述に注目してください。

@import "icon/*.png";

CSSスプライト用の各種mixinを、Compassが自動的に用意します。これまでのサンプルにて登場したall-icon-spritesというmixinも、このとき同時に用意されるmixinです。さらにicon-spriteというmixinも用意されます。

このicon-spriteというmixinは、importしたiconディレクトリのスプライトマップから、引数として渡された名前の画像に相当するCSSスプライト用のスタイルをまとめて書き出してくれるmixinです。

たとえば、このサンプルでは@include icon-sprite(face-cool);と記述しています。このようにすると、iconディレクトリにあるface-cool.pngが、スプライトマップ上でどの位置にあるのかを判断し、以下のようなスタイルを用意してくれます。

background-position: 0 -128px;

そして、このようにiconのスプライトマップを使用したすべてのセレクタをまとめて、背景画像を次のように割り当てます。

.icon-sprite, .faces .cool, .faces .sad, .faces .wink {
  background: url('../images/icon-s51e5ca4f42.png') no-repeat;
}

このようにCompassはCSSスプライトのためのmixinを自動的に定義してくれます。それを使うことで、柔軟にCSSスプライトを実装することが可能になっています。

さらに詳しい仕様を知りたい方は、公式のドキュメントを参照してください。

コラム:mixinはいつ定義されている?

このようにCompassは、Sassだけではできないさまざまな処理を行ってくれます。ただ、ちょっと待って下さい。このmixinの名前に含まれているiconというのは、このサンプルでたまたま私がPNGを格納するディレクトリの名前としてつけただけです。Compassがもとからall-icon-spritesだとか、icon-spritesなどというmixinを定義しているわけはありません。

これはいったいどのような仕組みになっているのでしょうか。Compassがどのようにコンパイルの処理を行っているかという点について、少し触れてみましょう。

Sassはいろいろと拡張可能な作りになっています。Compassは、このSassの拡張機能をうまく使い、さまざまな機能を実現しています。たとえば@importは、通常ただ別のSassファイルを読み込むだけの機能ですが、今回解説しているCSSスプライトの機能では、PNGファイルを読み込ませ、画像を生成しています。

これはSassに@importの処理を拡張できる仕組みが備わっているから実現できていることです。Copmassは@importの処理に、対象がPNGファイルであった場合の処理を加えています。今回のサンプルのようにPNGファイルが@importされた場合、画像の結合を行い、そして、CSSスプライトに必要なmixin、変数などをダイナミックに作り、Sassのコンパイラに読み込ませています。このようにして、all-icon-spritesというmixinが@importを行った次の行から、もう使えるようになっているのです。

このCSSスプライト機能においては、なにやら裏で何かしているという、ブラックボックス的な部分が多いと筆者は強く感じ、違和感を覚えていました。しかしこのような認識でいると、Compassがやってくれていることをざっくりと理解できるかもしれません。

今回は、CompassのCSSスプライト機能のうち、簡単な部分について触れました。次回は、より細かくカスタマイズして使う方法について見ていきます。