あと味

たくさん情報を食べて、たくさん発信すると、あとになって味わい深い。

watchオプションの使い方

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

Sassは自分がコーディング担当の案件は、確実に使っているのですが、まだまだ表面的な使い方しかできてないのかなと、Advent Calendarの他の記事を見ると感じます。

さて、Sassを使ってCSSを書いていく時には、ほぼ例外なく、watchオプションのお世話になることと思います。

弊社のデザイナーのやり方などを見ると、イマイチ理解して使ってない感じもしたりしたので、少し細かく説明する記事があってもいいのかなと思って、この記事を書くことにしました。

知ってる人には当たり前すぎて、得るものがないかもしれませんが、その点はご了承下さい...

watchオプションとは?

Sassはfilename.sassまたは、filename.scssを使って、Sassの記法、もしくはSCSSの記法で書いたファイルを、コマンドラインを使ってfilename.cssにコンパイルするという方法で、CSSファイルを作ります。(以後、SCSSの記法を使うことを前提で書きます)

その際、SCSSファイルを更新するたびに、毎回コンパイルし直すという手順が非常に面倒なので、ファイルの更新を監視し、更新があれば、自動でコンパイルしてくれる、watchオプションが非常に役に立ちます。

watchオプションの使い方

Sassのリファレンスにwatchオプションの指定方法が書いてある他、Unixコマンドラインツールの多くは、コマンドラインオプションを、

commandname --help

と入力することで確認することができます。

Sassの場合も、

sass --help

と入力することでSassのコマンドラインオプションをすべて確認することができます。*1

watchオプションの項目を見ると、

sass --watch input.sass:output.css
sass --watch input-dir:output-dir

というコマンドが確認できます。

どちらも、変換元と変換先をコロンで区切る形でオプション引数を指定することがわかります。

SCSSファイルの作り方

人それぞれかもしれませんが、SCSSファイルは用途やページによってファイルを分けることが一般的なのかなと思います。

@importが強力で、CSSの@importルールと違い、Sassの@importはインポートするファイルを一つのファイルに結合してくれます。

Webサイトパフォーマンスの改善が流行った時期に、CSSの@importはHTTPコネクションが多く発生してしまうからやめましょうという流れがあって、@importを使うことを消極的にしていた方もいらっしゃると思いますが、SCSSの@importはガンガン使っちゃっても最終的に一つのファイルに結合されるのでガンガン使っちゃって問題ありません。

ファイルの監視とフォルダの監視

watchオプションは、ファイルの監視とフォルダの監視があると述べましたが、上述のSCSSファイルの作り方に書いたように、複数のファイルを@importで結合する場合、ファイル単位の監視ではちょっと厳しくなってきます。

例えば、以下のような場合、

/* /scss/style.scss */
@import "hoge.scss";
@import "fuga.scss";

ファイル単位の監視をすると以下のようなコマンドになるかと思います。

sass --watch scss/style.scss:css/style.css

この時、せっかくwatchオプションで監視していても、hoge.scssやfuga.scssを更新しても、style.scssの更新をしたことにはならないので、style.cssが新たにコンパイルされることはありません。

なので、基本的にはフォルダの監視がオススメです。

同じ例で、フォルダ単位の監視をすると以下のようなコマンドになります。

sass --watch scss:css

フォルダ名を指定すると、watchオプションは、監視元フォルダに指定したフォルダに保存されている.scssと.sassを探して、ファイルの更新を監視してくれます。

先ほどのファイルの監視では、hoge.scssやfuga.scssを更新しても、監視対象に含まれていなかったので、style.cssが新たにコンパイルされることはありませんでしたが、このフォルダの監視であれば、hoge.scssやfuga.scssを更新すると、style.cssが新たにコンパイルされます。

アンダースコア付きファイル名について

ただ、上記に関して、1点問題があります。

それは、hoge.scss、fuga.scssも、それぞれ、hoge.css、fuga.cssにコンパイルされるということです。

style.cssは、最終的にHTMLで読み込むCSSファイルですが、hoge.css、fuga.cssは、style.cssに結合されていれば良く、無駄な中間成果物かもしれません。

Sassでは、そのケースを解決するために、Partialsという仕組みを用意しています。

hoge.scssや、fuga.scssのように、@importで結合はするが、CSSファイルにコンパイルする必要がないファイルについては、_hoge.scss、_fuga.scssと、ファイル名の先頭にアンダースコアを入力しておくことで、コンパイルされないSCSSファイルにすることができます。

この際、アンダーバーを付けたからといって、

/* /scss/style.scss */
@import "_hoge.scss";
@import "_fuga.scss";

とする必要はありません。

さらに言うと、sassファイルまたは、scssファイルの場合は、拡張子も省略できます。

/* /scss/style.scss */
@import "hoge";
@import "fuga";

なので、上記のような指定をすれば結構です。

まとめ

では、まとめです。

  1. Sassのwatchオプションは、ファイル単位の監視とフォルダ単位の監視があるが、フォルダ単位の監視がおすすめ。
  2. 結合元のscssファイルで、cssとして使用することがないファイルはファイル名の先頭にアンダースコアを付ける

リファレンスに書いてあることですが、始めたての頃の自分や、身近な人が理解できてないようだったので、少し丁寧に説明してみました。

Sassは、一度使い出すとなくてはならないツールになると思うので、まだの方はぜひお試しください。

オマケ

個人的には、このくらいのコマンドラインの操作はできるようになった方がいいと思うのですが、どうしてもコマンドラインツールが難しい方は、GUIツールでwatchする方法もあります。

まだ使ってはいないのですが、CompassというSass向けのCSSフレームワークがあって、そのCompass用にGUIツールがあるようです。

どうしても難しいという方は、上記のツールを使うのもありなんじゃないでしょうか。

アプリをつかうかどうかは置いておいて、個人的にCompassは今後使っていこうかなとは思っています。現状、SassとYUIと組み合わせていますが、Sassに最適化されたCompassの方が良いのかもしれませんし、調べてみます。

LESSにもLESS.app For Mac OS Xというアプリがあるみたいです。

LESSは使ったことないですけど、Sassに比べて大きなアドバンテージがあったら触ってみようかな。

*1:最近のバージョンからか、今まで気づかなかっただけなのか、scssってコマンドもあるみたいですね。使い方はsassコマンドと同じです。

最近の案件でのSassの運用

今進めている案件で、Sass + YUIを使っています。

どんな感じに運用しているかを紹介するとともに、自分用のメモとしてまとめておきます。

SCSSファイルの全容

_yui-reset.scss

_yui-reset.scss は、YUI 3 CSS Resetをファイル名と拡張子だけ変更したファイル。

_yui-customized-fonts.scss

_yui-customized-fonts.scss は、YUI 3 CSS Fontsを日本語フォントを考慮してカスタマイズしたファイル。

_yui-fonts-map.scss

_yui-fonts-map.scss は、YUI 3 CSS Fontsのパーセントとpx数の対応を変数にしたファイル。

_utility.scss

_utility.scss は、clearfixなどのサイト共通で使用するユーティリティスタイルをまとめたファイル。

_common.scss

_common.scss は、サイト共通で使うCSSをまとめたファイル。

_page-name.scss

_page-name.scss は、各ページ固有のCSSをまとめたファイルで、ページの数だけある。

style.scss

style.scss は、style.cssに変換するファイルで、上記すべてをインポートするファイル。

_yui-customized-fonts.scss

/*
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.com/yui/license.html
version: 3.3.0
build: 3167
*/
/*
customize for japanese fonts.
author: taiju
version: 1.0
date: 2011.7.10
*/
/**
* Percents could work for IE, but for backCompat purposes, we are using keywords.
* x-small is for IE6/7 quirks mode.
*/
body {
font:13px/1.231 "ヒラギノ角ゴ Pro W3","Hiragino Kaku Gothic Pro","メイリオ",Meiryo,Osaka,"MS Pゴシック","MS PGothic",arial,helvetica,clean,sans-serif;
*font-size:small; /* for IE */
*font:x-small; /* for IE in quirks mode */
}

/**
* Nudge down to get to 13px equivalent for these form elements
*/
select,
input,
button,
textarea {
font:99% "ヒラギノ角ゴ Pro W3","Hiragino Kaku Gothic Pro","メイリオ",Meiryo,Osaka,"MS Pゴシック","MS PGothic",arial,helvetica,clean,sans-serif;
}

/**
* To help tables remember to inherit
*/
table {
font-size:inherit;
font:100%;
}

/**
* Bump up IE to get to 13px equivalent for these fixed-width elements
*/
pre,
code,
kbd,
samp,
tt {
font-family:monospace;
*font-size:108%;
line-height:100%;
}

*:first-child+html * {
font:13px/1.231 "メイリオ",Meiryo,Osaka,"MS Pゴシック","MS PGothic",arial,helvetica,clean,sans-serif;
}

* html * {
font:13px/1.231 "メイリオ",Meiryo,Osaka,"MS Pゴシック","MS PGothic",arial,helvetica,clean,sans-serif;
}

_yui-fonts-map.scss

/* mapping yui-fonts px and % */
$f10px: 77%;
$f11px: 85%;
$f12px: 93%;
$f13px: 100%;
$f14px: 108%;
$f15px: 116%;
$f16px: 123.1%;
$f17px: 131%;
$f18px: 138.5%;
$f19px: 146.5%;
$f20px: 153.9%;
$f21px: 161.6%;
$f22px: 167%;
$f23px: 174%;
$f24px: 182%;
$f25px: 189%;
$f26px: 197%;

_utility.scss

.clearfix {
  \zoom: 1;
  &:after {
    content: '';
    display: block;
    clear: both;
    height: 0;
  }
}

/* 他はサイト固有で使い回す変数とか、クラスとか */

_utility.scssは、もっと経験積んで増やしていけると良い。

_common.scss

#header {
  ...
}
#container {
  ...
}
#footer {
  ...
}

_page-name.scss

body.page-name {
  ...
}

style.scss

@import "yui-reset.scss";
@import "yui-customized-fonts.scss";
@import "yui-fonts-map.scss";
@import "utility.scss";
@import "common.scss";
@import "page-name.scss";
...

最終的に

sass -t compressed --watch scss:css

後はフォルダ単位で監視してひたすら更新する。

scssフォルダはサーバーには転送せず、ローカルにしか置かない。

こんな感じやってます。

SassをWindowsにインストールする

Sassについて話してから、うまく動かないなどの問合せをいただきます。

インストールはやっぱり完全初めてだと難しいんですね。その反省も込めて、Windowsでのインストール方法を説明することにします。

手元にWindows XPしかないので、Windows XPでの操作説明になりますがご了承ください... 適当に読み替えて進めてください。

RubyInstaller for Windowsのダウンロード

Sassの公式サイトにもリンクがありますが、以下のサイトからRubyInstallerがダウンロードできます。

ここのダウンロードページに移動したら、RubyInstallersという項目があるので、
Ruby1.8.xをダウンロードします。Ruby1.9.xをダウンロードします。

Rubyは1.9系と1.8系があって、今は1.9系への移行期間です。これから本格的にRubyも勉強したい人は1.9系をダウンロードすればいいと思います。Sassを使うだけなら、1.8系で良いと思います。

1.9系をダウンロードした方が良いのでは?とオススメもらいました。

Sassだけ利用する場合は1.9系の方が良いようで、さらにWindowsだと速度差が大きいとのことでした。

参考: あーありがち - Ruby 1.9の高速化の恩恵はWindowsでこそ大きい

RubyInstallerのインストールウィザード

f:id:jdg:20110607111147p:image
最初の画面は「Next」をクリックしましょう。

f:id:jdg:20110607111148p:image
ライセンスの記述です。「I accept the License」を選択して、「Next」をクリックしましょう。

重要なのは次の画面です。

f:id:jdg:20110607111149p:image
「Add Ruby executables to your Path」にチェックを入れてください。

これをすることで、Windowsの環境変数のPathにRuby実行ファイル関連が保存されるディレクトリが追加されます。

Sassをインストールする時に利用する、gemコマンドや、Sassを使用する時に使うsassコマンドがコマンド名のみで使えるようになります。たぶん、問合せしてくる人のほとんどが環境変数の設定ができてないところに起因していると思うので、ここさえチェックを入れておけばほとんど問題ないはずです。

f:id:jdg:20110607111150p:image
これでインストールが終了です。

Sassのインストール

Rubyにはgemというパッケージ管理ツールが付属されています。Sassも、このgemを使ってインストールすることができます。

コマンドプロンプトを起動

Win + Rで、ファイル名を指定して実行を表示します。

f:id:jdg:20110607111151p:image
「cmd」と入力してください。

rubyが入っているか確認

f:id:jdg:20110607111153p:image

ruby -vと入力して、Enterキーを叩きましょう。インストールしたRubyのバージョンが表示されるはずです。

gem

f:id:jdg:20110607111152p:image

gem --helpと入力して、Enterキーを叩けば、gemのヘルプが見れます。gem installのサンプルなども表示されるでしょう。

gemを使って、Sassをインストールする

f:id:jdg:20110607111154p:image
gem install sassと入力して、Enterキーを叩くと、sassのインストールが始まります。CPUの処理性能によっては、そこそこ時間がかかるかもしれません。

sass

f:id:jdg:20110607111155p:image
gemと同様、sass --helpと入力して、Enterキーを叩けば、sassのヘルプが確認できます。

Enjoy!!

これでWindowsの人もSassられましょう。

UPGRADE JAPAN!!で「Sassられ指南」というセッションを担当しました

先週の土曜日にUPGRADE JAPAN!!というチャリティイベントにスピーカーの一人として参加しました。

マスコミの取材とかもいたようで、このような大きなイベントになるとはビックリ。義援金も20万円超集まったそうです。よかった。

ということで、話した内容を、SlideShareにアップしました。今後もアフターフォローを兼ねてSassのことを紹介していきたいです。

Sassが北陸でも流行るとうれしいです。イベント中、イベント後に「Sassられたい」「Sassりたい」という言葉が微妙に流行ってて良かったです。

当日のTwitterまとめ(#ugj201106)

Sassの@extendでCSSとHTMLをシンプルに

明日、UPGRADE JAPANにて、Sassについて話す予定です。

それ用にSassの記事増やしておきたかったんですけど、あまりそれもできず。しばらくは、UPGRADE JAPANのフォローアップとして、いくつかSassの記事を投稿する予定です。

さて、「Sassの@extendでCSSとHTMLをシンプルに」ということですが、Sassの@extendを使わなかった場合と、使った場合の対比を書いてみます。

したいこと

  • サイドバーがある
  • とあるページのサイドバーは、既存のサイドバーのスタイルと背景色が違うだけ

これですね。つ First Look: Object Oriented CSS - SitePoint

単純なCSS

単純にこれをCSSで対応すると以下のようになるかもしれません。

.sidebar {
  /* sidebarのスタイル */
}
...省略...
.onsalesidebar {
  /* ここにsidebarのスタイルをまるまるコピペする */
  background-color: #FFA500;
}

これだと同じスタイルをコピペしないといけなくて煩雑ですね。

先ほどのリンク先にある例のように、bodyにclassを当てて、各ページのスタイルを使い分ける方が少し楽かもしれません。

<body class="onsale">
.sidebar {
  /* sidebarのスタイル */
}
body.onsale .sidebar {
  background-color: #FFA500;
}

これであれば、必要な箇所だけ上書きするだけで済みますね。

OOCSS

Object Oriented CSSというCSSの設計手法があるそうです。id:t32kに教えてもらいました。

この手法を使うと、小さい部品の組み合わせをclass属性で指定することでモジュール性の高いCSSの設計ができるようです。

<div class="sidebar onsalesidebar">sidebar content…  
</div>
.sidebar {
  /* sidebarのスタイル */
}
.onsalesidebar {
  background-color: #FFA500;
}

最初の例に似ていますが、既存のスタイルをコピペする必要はありません。HTML側でclass属性の値を組み合わせているので、CSS側はシンプルな記述で事足ります。

Sassの@extend

Sassの@extendを使うと、これをさらにシンプルに適用できます。

<div class="onsalesidebar">sidebar content…  
</div>
.sidebar {
  /* sidebarのスタイル */
}
.onsalesidebar {
  @extend .sidebar;
  background-color: #FFA500;
}

これは以下のように展開されます。

.sidebar, .onsalesidebar {
  /* sidebarのスタイル */
}
.onsalesidebar {
  background-color: #FFA500;
}

この利点はHTML側でclassを複数組み合わさなくても良い点と、@extendを記述することで、.sidebarのスタイルを.onsalesidebarで拡張していることが明示化されてわかりやすいという点があります。*1

SassはOOCSSの考え方にも、うまくマッチしますね。

*1:いちいち、HTMLを確認しなくても両者のスタイルの関連性がわかります

SassでCSS Spritesをなるべく簡単に書きたい

前段

Sass始めました。くそ便利ですねこれ。

したいこと

以下のような幅の違う横長なナビゲーションがあると想定して、これをCSS Spritesを使ってなるべく簡単にCSSを書きたい。

CSS Spritesは手計算でやるとくそメンドイので。

┏━━━┳━━━━━┳━┳━━┳━━━┓
┗━━━┻━━━━━┻━┻━━┻━━━┛

前提1 Sprites画像

ナビゲーションはホバー時に画像が置換される。

そのSprites画像は以下のように上段に通常のナビゲーションの画像、下段にホバー時のナビゲーションの画像がくっついていると仮定する。

┏━━━┳━━━━━┳━┳━━┳━━━┓
┣━━━╋━━━━━╋━╋━━╋━━━┫
┗━━━┻━━━━━┻━┻━━┻━━━┛

前提2 HTML

以下のようなHTMLがある仮定する。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf8">
    <title>タイトル</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div id="nav">
      <ul>
        <li><a href="#" class="nav1">nav1</a></li>
        <li><a href="#" class="nav2">nav2</a></li>
        <li><a href="#" class="nav3">nav3</a></li>
        <li><a href="#" class="nav4">nav4</a></li>
        <li><a href="#" class="nav5">nav5</a></li>
      </ul>
    </div>
  </body>
</html>

Sass(SCSS)で書いてみると

@mixin clearfix {
  \zoom: 1;
  &:after {
    content: '';
    display: block;
    clear: both;
    height: 0;
  }
}

@mixin nonspace {
  margin: 0;
  padding: 0;
}

@mixin nav-sprite($accum, $width, $height) {
  width: $width;
  height: $height;
  background-position: $accum 0;
  &:hover {
    background-position: $accum (-$height);
  }
}

#nav ul {
  @include nonspace;
  @include clearfix;
  li {
    @include nonspace;
    list-style-type: none;
    float: left;
    a {
      text-indent: -9999px;
      display: block;
      background: {
        image: url(nav.png);
        repeat: no-repeat;
      }

      /* 計算に使う値を初期化 */
      $width: 0; $height: 30px; $accum: 0;
      &.nav1 {
        $accum: $accum - $width;
        $width: 90px;
        @include nav-sprite($accum, $width, $height);
      }
      &.nav2 {
        $accum: $accum - $width;
        $width: 150px;
        @include nav-sprite($accum, $width, $height);
      }
      &.nav3 {
        $accum: $accum - $width;
        $width: 30px;
        @include nav-sprite($accum, $width, $height);
      }
      &.nav4 {
        $accum: $accum - $width;
        $width: 60px;
        @include nav-sprite($accum, $width, $height);
      }
      &.nav5 {
        $accum: $accum - $width;
        $width: 90px;
        @include nav-sprite($accum, $width, $height);
      }
    }
  }
}

直していくうちにこんな感じになった。

$accumに累計値を保存して、$widthも上書きしていくような感じ。とりあえず、累計値を手計算して当てはめていく必要はなくなる。

これより簡単にしようと思うと、制御構文とか独自メソッドを定義する*1とかになるのかもしれない。

何かもっといい方法はありませんか。

まとめ

Sassすごい。Sassがあると、使い回し効きやすいし、CSSの設計をしようという気になる。それだけでも大きな効果。

*1:CSS Spritesを作るためのフレームワークもあるみたいですね