このサイトは ie6 ie7 ie8 ではみられません。

2011-12-06
category: css/sass

Less & Sass Advent calendar 2011の7日目です。

勢いで参加登録をしたのは良いのですが、記事を投稿するBlogをもっていなかったため自作しました。はい。完全にスタートの仕方を間違いました…おかげで超大変でしたBlog作るのが。heroku + padrino + postgresql にてかろうじて動いております。

さて、前回までのみなさんの記事で、Sassの概要や導入方法、ベンダープリフィックスを気にすることなく開発が進められる有用性、便利なfunction methodなど、Sass/Lessの良さ感じていただけたかと思いますが、この投稿ではSassの実戦導入に向けて、もうちょっとだけ背中をそっと押せる内容を書いてみようかと思います。

実際、僕もSassを導入するか検討していた時期に心配していた事だったりします。
「Sassって便利なのは解るけど、コンパイルするからFirebug使えなくなってしまうんでしょう?Firebugは凄く便利に使わせてもらっているから、あれが使えなくなると開発効率が…ちょっと、ねぇ…」

「そんなことありません奥さん!(誰)なんと、そんなあなたにはコレ!FireSass for Firebugがあるんですっ!!」 ※Lessに同等のAdd-onがあるかは知らないです、ごめんなさい。

2012-1-21 追記
上記のFireSassですが、Firebug1.9から動作しなくなってしまっているようです。FireSassのアップデートを待つしかなさそうですね。

さて、FireSassの紹介です。

まずは、FireSassのインストール。
FireSass for Firebugからか、メニュー > ツール > アドオン > アドオンを検索にfiresassを入力して、Add-onをインストールします。

さす子 写真はリンクから飛んだページです。

インストールが終わったら、あとはSassをガシガシ書き、該当ディレクトリに移動して下記のオプションでコンパイルするだけです。

$ sass -g style.scss style.css
▲ 通常の場合
$ sass -g --watch style.scss:style.css
▲ --watchの場合

実際にコンパイル前と後のコードを比べてみます。

// ********************
// mixin
// ********************
@mixin box-shadow( $arg: nil ) {
  @if $arg != nil {
    -moz-box-shadow: $arg; // firefox
    -webkit-box-shadow: $arg; // chrome, safari
    box-shadow: $arg; // opera10.5~
  }
}
/* ******************** *
   sample box 1
 * ******************** */
#box1 {
  width:100px;
  @include box-shadow( 0 1px 2px #00f ); 
}
/* ******************** *
   sample box 2
 * ******************** */
#box2 {
  width:150px;
  @include box-shadow( 0 1px 2px #f00 ); 
}
▲ コンパイル前
/* ******************** *
   sample box 1
 * ******************** */
@media -sass-debug-info{filename{font-family:file\:\/\/\/Users\/obara\/Dropbox\/work\/saucer\/web\/saucerjp\/doc\/sample_scss\/style\.scss}line{font-family:\0000314}}
#box1 {
  width: 100px;
  -moz-box-shadow: 0 1px 2px blue;
  -webkit-box-shadow: 0 1px 2px blue;
  box-shadow: 0 1px 2px blue; }

/* ******************** *
   sample box 2
 * ******************** */
@media -sass-debug-info{filename{font-family:file\:\/\/\/Users\/obara\/Dropbox\/work\/saucer\/web\/saucerjp\/doc\/sample_scss\/style\.scss}line{font-family:\0000321}}
#box2 {
  width: 150px;
  -moz-box-shadow: 0 1px 2px red;
  -webkit-box-shadow: 0 1px 2px red;
  box-shadow: 0 1px 2px red; }
▲ コンパイル後

なんだか、きもいコードがはき出されますね。でもこれで合っています。僕の作業フォルダへのパスが丸見えなのは気にしないでください。
実際にFirebugで確認してみましょう。

さす子活躍

はい。ちゃんと「style.scss(14行目)」と表示されていますね!これで「Firebug使えなくなると困る」が解消されました。
ただ、この-gオプションでコンパイルされたコードはデバッグ用でFirebugのために不要なコードが大量に含まれていますので、実際に納品する際はnested, compact, compressed, expandedなどで再コンパイルを忘れないようにしましょう。

$ sass --style compressed style.scss style.css
▲ compressed コンパイル
#box1{width:100px;-moz-box-shadow:0 1px 2px blue;-webkit-box-shadow:0 1px 2px blue;box-shadow:0 1px 2px blue}#box2{width:150px;-moz-box-shadow:0 1px 2px red;-webkit-box-shadow:0 1px 2px red;box-shadow:0 1px 2px red}
▲ compressed コンパイル後

ちょっと脱線しますが、RubyのFramework: Sinatra, Padrino, Ruby on Rails などで開発する際は、Framework側がsassファイルの変更を監視して自動でコンパイルしてくれますので、開発中はsass -gで書き出して、本番をsass --style compressed で運用するなどの設定をして、デバッグ用コードの再コンパイル忘れを防止できたりします。

さらに…

あと、Sassの実戦導入時に問題になりそうな事と言えば、「納品後cssに修正が入ったのだが、先方が納品したcssファイルを勝手に変更していたために、手元のscssファイルが最新で無くなってしまった…」問題(長い)があると思います。

先に結論から言うと、僕もまだこれと言った最良な解決方法にはたどり着けてないです。
一応、思いついた方法を下記してみます。

  • sass --style compressedで納品して、そもそも変更する気を萎えさせる。ただし、逆にやる気を出されて変更を入れられてしまった場合のmergeコストを考えると、諸刃の剣。
  • sass -l でcssファイルにラインナンバー入りで納品する。この場合は変更されてもdiffとってmergeは比較的らくなんじゃないかと思う。

文字で書いてもあれなので、実際にものを見てみましょう。
サンプルのmixinを-lで書き出してみます。

// ********************
// mixin
// ********************
@mixin box-shadow( $arg: nil ) {
  @if $arg != nil {
    -moz-box-shadow: $arg; // firefox
    -webkit-box-shadow: $arg; // chrome, safari
    box-shadow: $arg; // opera10.5~
  }
}
/* ******************** *
   sample box 1
 * ******************** */
#box1 {
  width:100px;
  @include box-shadow( 0 1px 2px #00f ); 
}
/* ******************** *
   sample box 2
 * ******************** */
#box2 {
  width:150px;
  @include box-shadow( 0 1px 2px #f00 ); 
}
▲ コンパイル前
$ sass -l style.scss style.css
▲ コンパイル
/* ******************** *
   sample box 1
 * ******************** */
/* line 14, style.scss */
#box1 {
  width: 100px;
  -moz-box-shadow: 0 1px 2px blue;
  -webkit-box-shadow: 0 1px 2px blue;
  box-shadow: 0 1px 2px blue; }

/* ******************** *
   sample box 2
 * ******************** */
/* line 21, style.scss */
#box2 {
  width: 150px;
  -moz-box-shadow: 0 1px 2px red;
  -webkit-box-shadow: 0 1px 2px red;
  box-shadow: 0 1px 2px red; }
▲ コンパイル後

通常のコンパイルでは書き出されなかったコメントが line 14, style.scss の書式で、該当sassファイル名と該当行が書き込まれていますね。

これなら、何となくmerge作業も少しは楽になりそうな感じですよね?
ただ、この場合も不要なコードが増えてファイルサイズが増大する弊害はあるので、スマホ案件など転送量にシビアな案件には不向きなのかもしれません。(個人的には、遅いのは最初の一回だけで、キャッシュされれば速いんだからいいんじゃね?って考えです。)

最後に、sass --style compressed 時の小ネタ

sassはcompressed オプションでコンパイルした場合は、通常では消されない/* */コメントも消されてしまいます。ただ、業務で使う場合はクレジットやライセンス情報を残したい場合があると思います。
そんな場合は下記のように、コメントアウト開始直後に ! を入力するとコンパイラがスルーしてくれます。

/*! 絶対残る */
/* 通常残る */
// 必ず消える
▲ コンパイル前
/* 絶対残る */
▲ compressed コンパイル後

ちなみに、//! は一応コンパイルは通りますが、「sass3.2から//! は使えなくなるから/*! */使ってよ」的なWARNINGが出ました。

それと特殊な事例ですが、はまったら原因を見つけ出すのが困難そうなものをひとつ。

compressedコンパイルした場合に、sassがカラーコードを短縮する場合があります。
どのような場合かと言うと、変数やfunction内に#888888などを置いた場合です。
結果は#888に変換されます。
ベタに color: #888888; などとした場合はcompressedしても#888888のままです。
通常では全然良いことで、問題ないのですが、下記のような場合には大問題に発展します。

/* ******************** *
   sample box
 * ******************** */
$start:#111111;
$end:#888888;
#box {
  filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#{$start}', endColorstr='#{$end}'); /* IE6 & IE7 */
  -ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$start}', endColorstr='#{$end}')"; /* IE8+ */
}
▲ コンパイル前
/* ******************** *
   sample box
 * ******************** */
#box {
  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#111111', endColorstr='#888888'); /* IE6 & IE7 */
  -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#111111', endColorstr='#888888')"; /* IE8+ */ }
▲ 通常 コンパイル後
#box{filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#111', endColorstr='#888');-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr='#111', endColorstr='#888')"}
▲ compressed コンパイル後

…はい正解!またIEです。
ちょっと見にくいですが、カラー値が短縮されているのが解ると思います。

-ms-filterのカラー値は短縮の#888は理解できないので、なんか違う色に置き換えられたと思います。(どんな色に置き換わったかは忘れてしまいました。ショッキングな色だった事しか覚えていません…見たくもないですが後日確認してみます。)

そして、この問題の一番悪いところは、テスト環境のコンパイルでは発生しにくいところです。普段から全てcompressedでやっていればテスト環境でも発見できると思いますが、普通はそんな感じにはなってないかと思います。
本番環境で自動的にcompressedコンパイルするような設定にしていると発生します。やっかいですね。

スマートではないですが一応の解決方法は下記です。

$start:#111110;
$end:#888887;
▲ 変数の値を変更

単純に変数の値を圧縮できない数値に変更しました。
色味としてもこの違いを見分けられる人はいないでしょう。

#box{filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#111110', endColorstr='#888887');-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr='#111110', endColorstr='#888887')"}
▲ compressed コンパイル後

2011-12-13 追記
上記のスマートでない解決法ですが、$start:"#111111"; のように文字列として書くことでカラー値の圧縮を避けられると教えていただきました。
@tacamyさん、ありがとうござます!これで気持ち悪かった部分がスッキリしました。

おわり

さて、これで私のパートは終わります。
この投稿が業務にsassを導入するか迷っていた方に、少しでも実戦導入への後押しになってくれれば嬉しいです。
また、そうなれば、次回以降に書かれるであろう実践的なmixinなどなどが、より魅力的に見えてくるのではないでしょうか!(mixin解説丸投げ)

それでは、次回以降のLess & Sass Advent calendar 2011の投稿をお楽しみに!