WebOS Goodies

WebOS の未来を模索する、ゲームプログラマあがりの Web 開発者のブログ。

WebOS Goodies へようこそ! WebOS はインターネットの未来形。あらゆる Web サイトが繋がり、共有し、協力して創り上げる、ひとつの巨大な情報システムです。そこでは、あらゆる情報がネットワーク上に蓄積され、我々はいつでも、どこからでも、多彩なデバイスを使ってそれらにアクセスできます。 WebOS Goodies は、さまざまな情報提供やツール開発を通して、そんな世界の実現に少しでも貢献するべく活動していきます。
Subscribe       

Closure Stylesheets で CSS を最適化する (1)

これまで Closure Library を使っていろいろと開発をしてきましたが、 CSS の扱いについてはいつも不満でした。 JavaScript コードについては Closure Compiler との組み合わせで極限まで最適化できるのに、 CSS についてはほとんどサポートがなく、仕方がないので自作の Rakefile と YUI Compressor を使ってしのいでいました。

しかし、それも今日までです。ついに Google が CSS の最適化ツール「Google Closure Stylesheets」(以下 GSS)を公開したのです!

Closure Stylesheets
http://code.google.com/p/closure-stylesheets/

GSS は YUI Compressor のような CSS 最適化の機能と SassLESS のような CSS の拡張機能を併せ持っており、さらに他の Closure Tools と組み合わせることで CSS クラス名の短縮も可能になる、強力な CSS プリプロセッサです。主に以下の機能を持っています。

  • 空白やコメント、冗長な記述などの削除
  • 文法チェック
  • 変数定義・展開
  • 加減乗除、最大値、最小値を展開する関数
  • プロパティ定義の継承(ミックスイン)
  • LTR / RTL の反転
  • CSS クラス名の短縮

Closure Library を愛用する者として、これは試さずにはいられない!ということで、二回に分けてこの Closure Stylesheets をご紹介することにしました。一回目の今回は GSS を独立した CSS プリプロセッサとして使った時の機能に焦点を当てます。 GSS は他の Closure Tools と連携するように作られていますが、単体でもなかなか強力です。 CSS の最適化やメンテナンス性向上に、どんどん活用しましょう。

インストール

GSS を利用するには、 Java で記述された GSS コンパイラをインストールする必要があります。以下のページから closure-stylesheets.jar をダウンロードして、適当なディレクトリにコピーしてください。それでインストールは完了です。

http://code.google.com/p/closure-stylesheets/downl...

もし Java の実行環境 (JRE) がインストールされていければ、そちらも入れておいてください。 Windows ならこちらでインストーラがダウンロードできます。 Mac OS X Lion ならコンソールで java コマンドを実行するとインストールしてくれます。 Linux ならパッケージ管理ツールで OpenJDK とかを検索すれば見つかるはずです。

インストールができたら、以下のコマンドを実行してみてください。 closure-stylesheets.jar のパスは、必要に応じて正しいものに置き換えてください。

java -jar closure-stylesheets.jar --help

コマンドラインオプションの説明が表示されるはずです。参考までに、現在利用できるオプションとその簡単な説明を書いておきます。

オプション説明
--allow-unrecognized-functionsurl() と rgb() 以外の非標準の関数を許可する
--allowed-non-standard-function許可する非標準の関数を追加する
--copyright-notice指定された文字列を出力ファイルの先頭に付ける
--define条件分岐で使用する定数の定義
--excluded-classes-from-renaming短縮しない CSS クラス名を指定する
--gss-function-map-providerカスタム関数を実装した Java クラス名を指定する
--input-orientation入力ファイルが LTR と RTL のどちらに向けて書かれているかの指定
--output-file出力ファイル名の指定
--output-orientation出力ファイルを LTR と RTL のどちらに変換するかの指定
--output-renaming-map短縮 CSS クラス名のマップを出力するファイルの指定
--output-renaming-map-formatクラス名マップファイルのフォーマット指定
--pretty-print読みやすいように改行・インデントして出力
--renameCSS クラス名の短縮方法の指定

これらのオプションの詳細は、以降で必要に応じて解説します。

使ってみる

GSS は他の Closure Tools と組み合わせて CSS クラス名の短縮を実現できるのが最大の特徴ですが、独立した CSS プリプロセッサとしても使えます。今回は、 GSS のみで使える機能に絞って、基本的な使い方を解説していきます。

CSS ファイルの結合・最適化

最初に、単純に通常の CSS ファイルを結合・最適化するツールとして使ってみます。以下の内容を example1.gss として保存しておいてください。蛇足ですが、 GSS の入力ファイルは通常の CSS ファイルと区別するために .gss とするのが通例のようです。

/* フォントサイズを変える */
h1 {
   font-size: 24px;
}

/* さらに大きくする */
h1 {
   font-size: 32px;
}

これを、 GSS にかけてみます。

java -jar closure-stylesheets.jar example1.gss

すると、以下の出力が得られます。

h1{font-size:32px}

空白やコメントが取り除かれただけでなく、必ず上書きされる冗長な CSS 属性も取り除かれているのがわかりますね。このように、 GSS は CSS の定義を解析して不要な属性定義を取り除くことで、 .css ファイルのサイズを削減してくれます。

さらに、コマンドラインに複数のファイルを指定することで、それらを結合してくれます。適当に example2.gss を作成して、以下のコマンドを実行してください。

java -jar closure-stylesheets.jar example1.gss exapmle2.gss

2 つのファイルを結合した上で最適化した結果が出力されたはずです。ページに複数の .css ファイルを適用する場合、このようにあらかじめ GSS で結合して最適化することで、それぞれのファイルで重複した定義なども取り除くことができ、最適化の効果がより大きくなるでしょう。

変数の定義・展開

ここからは、 GSS によって追加される CSS の拡張記法について説明していきます。まずは変数の定義です。特定の色やサイズなどを多数の属性に対して与えるときに便利な機能です。 example3.gss として以下の内容を保存してください。

@def MENU_HEIGHT 20px;

.menu {
  height: MENU_HEIGHT;
}

.menu a {
  display: block;
  height: MENU_HEIGHT;
}

そして、以下のコマンドでコンパイル。 --pretty-print オプションを付けると、読みやすくフォーマットして出力してくれます。デバッグに便利。

java -jar closure-stylesheets.jar --pretty-print example1.gss

結果はこうなります。

.menu {
  height: 20px;
}
.menu a {
  display: block;
  height: 20px;
}

関数の使用

GSS では、プロパティ値を計算するために以下の関数が使えます。

  • add()
  • sub()
  • mult()
  • div()
  • min()
  • max()

機能はそれぞれの名前から想像されるとおりです。引数としては計算する値を複数(2 つ以上も可)指定し、最後に単位(px, em など)を付けます。

@def BOX_WIDTH 300px;
@def BORDER_WIDTH 2px;
@def PADDING 10px;

.box {
  border: solid BORDER_WIDTH black;
  padding: PADDING;
  width: sub(BOX_WIDTH, mult(add(BORDER_WIDTH, PADDING, px), 2, px), px)
}

コンパイル結果はこうなります。

.box {
  border: solid 2px black;
  padding: 10px;
  width: 276px;
}

ただし、残念ながら複数の単位をミックスして指定することはできないようです(それなら最後に単位を指定する必要はないような… ^^;)。また、関数の追加も .gss ファイル内ではできず、 Java のクラスを実装して closure-stylesheets.jar 自体をリコンバイルする必要があります。そして、 --gss-function-map-provider にクラス名を指定すると、そのクラスで実装されたカスタム関数が有効になるようです。

ミックスイン

CSS を書いていて常に苦痛なのが、同じような定義を何回も書かなければいけないことです。例えば複数箇所の背景にグラデーションをかけたい場合、クロスブラウザ対応のためにプレフィクスのついた属性のセットをすべての定義に書かなくてはなりません。 @defmixin と @mixin を使うと、そうした定型的な記述をまとめることができます。

@defmixin gradient(POS, HSL1, HSL2, HSL3, COLOR, FALLBACK_COLOR) {
  background-color: FALLBACK_COLOR; /* グラディエントをサポートしていない時のフォールバック */
  background-image: -webkit-linear-gradient(POS, hsl(HSL1, HSL2, HSL3), COLOR);               /* Chrome 10+,Safari 5.1+ */
  /* @alternate */ background-image: -moz-linear-gradient(POS, hsl(HSL1, HSL2, HSL3), COLOR); /* FF3.6+ */
  /* @alternate */ background-image: -ms-linear-gradient(POS, hsl(HSL1, HSL2, HSL3), COLOR);  /* IE10 */
  /* @alternate */ background-image: -o-linear-gradient(POS, hsl(HSL1, HSL2, HSL3), COLOR);   /* Opera 11.10+ */
}

.header {
  @mixin gradient(top, 0%, 50%, 70%, #cc0000, #f07575);
}

@alternate という記述(アノテーション)は、同じ属性を重複して定義することによるエラーを抑制するものです。

コンパイル結果はこうなります。

.header {
  background-color: #f07575;
  background-image: -webkit-linear-gradient(top,hsl(0%,50%,70%) ,#cc0000);
  background-image: -moz-linear-gradient(top,hsl(0%,50%,70%) ,#cc0000);
  background-image: -ms-linear-gradient(top,hsl(0%,50%,70%) ,#cc0000);
  background-image: -o-linear-gradient(top,hsl(0%,50%,70%) ,#cc0000);
}

単に属性定義を挿入するだけでなく、引数を与えられるところがいいですね。よく使う記述をライブラリ化しておけば、凝った CSS 定義も楽になりそうです。

条件分岐

GSS では、静的な条件分岐も可能です。主にブラウザごとに別々の CSS ファイルを用意してクロスブラウザ対応を行うことを意図しているようです。例えば、背景画像に透過 PNG を使用する際は、以下のように記述して IE6 のときだけ DXImageTransform を利用します。

@if(BROWSER_IE6) {
  .image_bg {
    filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="bg.png");
  }
} @else {
  .image_bg {
    background: url(bg.png) no-repeat;
  }
}

以下のコマンドでコンパイルします。 --allow-unrecognized-functions オプションは、非標準の DXImageTransform でエラーを出さないためのものです。

java -jar closure-stylesheets.jar --pretty-print --define BROWSER_IE6 --allow-unrecognized-functions image_bg.gss 

この場合は BROWSER_IE6 が未定義なので、 @else が展開されます。

.image_bg {
  background: url(bg.png) no-repeat;
}

これに対して、 "--define'' オプションで定数 (?) を定義してコンパイルすると…

java -jar closure-stylesheets.jar --define BROWSER_IE6 --pretty-print --allow-unrecognized-functions image_bg.gss 

@if(BROWSER_IE6) のほうが展開されます。

.image_bg {
  filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="bg.png");
}

また、 @if() { 〜 } 内では @def による変数定義も可能です。こちらについては公式プロジェクトサイトに使用例が掲載されています。残念ながら、 @defmixin などは使えないようです。

RTL の変換

残念ながら私はこの方面の知識がないのですが、 GSS には通常の LTR な言語向けに書かれた CSS を RTL に変換する機能があります。例えば以下の CSS ファイルを

.text {
  direction: ltr;
  border-left: solid 8px black;
  padding: 0 0 0 8px;
}

"--output-orientation RTL" オプションを付けてコンパイルすると、それぞれの属性の左右を入れ替えてくれます。

.text {
  direction: rtl;
  border-right: solid 8px black;
  padding: 0 8px 0 0;
}

正直あまりピンときませんが、きっと便利なのでしょう ^^;

仕組みとしては、 --input-orientation オプションで元の CSS(GSS) ファイルが LTR 向けに書かれているか RTL 向けに書かれているかを指定し、 --output-orientation で出力時の方向を指定する、というようになっています。入力の方向と出力の方向が同じであれば(もしくは出力が「NOCHANGE」と指定されていれば)そのまま出力し、方向が違っていれば左右を反転します。

特定の属性だけ左右の反転を抑止したい場合は、 @noflip アノテーションを使います。

.text {
  direction: ltr;
  border-left: solid 8px black;
  /* @noflip */padding: 0 0 0 8px;
}

これをコンパイルすると、

.text {
  direction: rtl;
  border-right: solid 8px black;
  padding: 0 0 0 8px;
}

となります。 padding 属性だけ変換が行われていないのがわかりますね。

時間の都合により、今回はここまで。従来の CSS の欠点を補う機能が多数追加されて、効率よく記述できるのがお分かりいただけたと思います。まあ、今回ご紹介した機能なら LESS + YUI Compressor などでも実現可能ですが、 GSS の最大の特徴は他の Closure Tools と組み合わせて行う CSS クラス名の短縮です。これについては次回ご紹介したいと思っていますので、お楽しみに!

関連記事

この記事にコメントする

Recommendations
Books
「Closure Library」の入門書です。
詳しくはこちらの記事をどうぞ!
Categories
Recent Articles