書籍転載:Ruby on Rails 4アプリケーションプログラミング
Sass(SCSS)入門
CSSのコードを生成するための言語「Sass(SCSS)」の基礎として、基本的な使い方/スタイル定義のネスト/変数/演算子/関数/ディレクティブ/について解説。書籍転載の10本目(「Part 3《応用編》 第9章 クライアントサイド開発」より)。
書籍転載について
ご注意
本記事は、書籍の内容を改変することなく、そのまま転載したものです。このため用字用語の統一ルールなどはBuild Insiderのそれとは一致しません。あらかじめご了承ください。
前々回~前回は、CoffeeScriptの基礎解説しました。今回は「Sass(SCSS)」の基礎を説明します。
■
9.4 Sass(SCSS)
Sass(Syntactically Awesome StyleSheets) は、いわゆるCoffeeScriptのCSS版とも言うべき存在で、CSSのコードを生成するための言語です。CoffeeScriptと同じく、Sassのコードもまた、CSSにコンパイルされた上で送出されますので、クライアント環境に特別なプラグインやライブラリは必要ありません。
Sassは、ネストや変数、文字列展開のような機能を提供しており、従来のCSSでは冗長になりがちであったコードをコンパクトにまとめることができます。
Sassの文法は、インデント文法とSCSS(Sassy CSS)とに大別できますが*21、本書ではCSS3と高い互換性を持つSCSSに沿って解説を進めます。正しいCSSのコードはそのまま正しいSCSSとなりますので、既存のCSSを移行するのも容易ですし、学習コストも低くて済みます。以下でも、CSSの知識を前提に、SCSSで拡張されている機能について解説します。
- *21 本書では便宜上、旧来からあるインデント文法をSassと呼び、SCSSと区別するものとします。
9.4.1 SCSSの基本
RailsではAsset Pipelineを利用して、SCSSを自動的にコンパイルしてくれますので、特にコンパイル作業を意識する必要はありません。拡張子を「.css.scss」とし、/app/assets/stylesheetsフォルダに配置するだけで利用できます。
もっとも、SCSSに慣れないうちは、いきなりアプリケーションに組み込んでしまうよりは、コンパイル結果を確認しながらコーディングできた方が便利です。以下に手元でSCSSコードをコンパイルするための方法を示します。
1ブラウザ上で動作する簡易インタプリタを利用
SassMeisterというサイトから、ブラウザ上で簡易なインタプリタを利用できます。
左のテキストエリアにSCSSのコードを入力(コピー&ペースト)すると、右の欄にコンパイル結果がリアルタイムに表示されます*22。
- *22 結果の表示方法は、右上の「CSS(xxxxx)」という選択ボックスで、Expanded( 展開)、Compact(シンプル)、Compressed(圧縮)などから選択できます。
2オフライン環境でコンパイルする
Railsをインストールしているならば、既にコンパイル環境は準備済みのはずです。scssコマンド(Linux環境では/usr/local/lib/ruby/gems/2.0.0/gems/sass-3.2.12/bin、Windows環境ではC:\Ruby200\lib\ruby\gems\2.0.0\gems\sass-3.2.13\bin)へのパスを通した上で、以下のコマンドを実行してください。これでカレントフォルダにあるstyle.css.scssをstyle.cssにコンパイルできます。
> scss style.css.scss style.css
|
以下でも、SCSSのコードとコンパイル済みのCSSコードを併記しますので、理解の手助けとしてください。
9.4.2 スタイル定義のネスト
SCSSの最大の特長は、スタイル定義をネスト(入れ子)できるという点です。ネストによって、たとえば「#list」「#list li」「#list li a」「#list li a:hover」のように親子関係にあるセレクターの記述をシンプルにできます。
「a:hover」「a:visited」のような疑似クラスで親セレクターを参照させるならば、「&:hover」のように、SCSSの予約文字「&」を利用してください。
#books {
margin: 0px;
li {
margin: 4px;
list-style-type: square;
a {
color: #00f;
&:hover { color: #0f0; } // ……疑似クラスでは「&」を利用
}
}
}
|
#books {
margin: 0px; }
#books li {
margin: 4px;
list-style-type: square; }
#books li a {
color: #00f; }
#books li a:hover {
color: #0f0; }
|
ネストできるのは、セレクターばかりではありません。以下のようにプロパティ名をネストさせることもできます(名前の後ろに「:」を付けます)。これによってborder-xxxxx、list-xxxxx、font-xxxxx、text-xxxxxなど、サブプロパティを持つプロパティをよりシンプルに記述できます。
.ad {
font: {
family: serif;
weight: bold;
}
border: {
top: {
width: 3px;
color: #0f0;
}
bottom: {
width: 3px;
color: #00f;
}
}
}
|
.ad {
font-family: serif;
font-weight: bold;
border-top-width: 3px;
border-top-color: #0f0;
border-bottom-width: 3px;
border-bottom-color: #00f;}
|
9.4.3 変数
SCSSでは、SassScriptと呼ばれる拡張スクリプトを提供しており、変数や演算子、独自の関数を利用できます。
たとえば、変数は「$変数」の形式で表現できます。フォントや色、サイズの設定など、複数の箇所で参照するような値は、変数として宣言しておくことで、修正時にも影響範囲を抑えられます*23。
$spcolor: #f30; // ……変数$spcolorを宣言
#attention { color: $spcolor; }
|
#attention {
color: #ff3300; }
|
- *23 ただし、変数とは言っても、あくまで擬似的なもので、コンパイル時に静的なCSSに変換されます。実行時に、動的に値を変更するような用途では利用できません。
#{変数名}という書式で、変数を(プロパティ値だけでなく)セレクターやプロパティ名の一部として埋め込むこともできます(変数展開)。
$type: lime;
$side: top;
#main-#{$type} { // ……セレクターの一部を変数で指定
border-#{$side}-color: #0f0;
border-#{$side}-width:3px; // ……プロパティ名の一部を変数で指定
}
|
#main-lime {
border-top-color: #0f0;
border-top-width: 3px; }
|
9.4.4 演算子
+、-、*、/、and、orなどの演算子を利用できます。演算子はほぼ直感的に利用できるものばかりですが、単位付きの数値やRGBカラーなども処理できる点に注目です。
#main menu {
background-image: url('../images/' + 'webdeli.jpg'); // ……文字列の連結
height: 30mm + 2cm; // ……単位付き数値の演算
color: #123456 + #987654; // ……RGBカラーの演算も可
}
|
#main menu {
background-image: url("../images/webdeli.jpg");
height: 50mm;
color: #aaaaaa; }
|
【NOTE】インタラクティブモード
演算子や関数をはじめ、SassScriptの挙動を単発的に確認したいならば、scssコマンドのインタラクティブモードを試してみると良いでしょう。scssコマンドを-iオプション付きで実行することで、コマンドライン上で対話的にスクリプトを実行できます。
> scss -i
DL is deprecated, please use Fiddle*24
>> rgb(255, 255, 255)
#ffffff
|
- *24 この警告は、scssコマンドが内部的に利用しているDLライブラリが非推奨であるために発生しています。現時点では無視して構いません。
9.4.5 関数
文字列/数値/リストなどの基本データや色/明るさを操作するための関数が提供されています。たとえば以下は、指定された色を指定の割合だけ明るくする例です。
$basecolor: #039;
#sidebar {
background-color: lighten($basecolor, 20%); // ……指定の色を指定割合だけ明るくする
}
|
#sidebar {
background-color: #0055ff; }
|
その他、SassScriptで利用できる主な関数をまとめます。
分類 | 関数 | 概要 |
---|---|---|
例 ⇒ 結果 | ||
色 | hsl( $hue, $saturation, $light) | 色相/彩度/輝度から色を生成 |
hsl(100deg, 25% , 25% ) ⇒ #3a5030 | ||
hsla( $hue, $saturation, $light, $alpha) | 色相/彩度/輝度/透明度から色を生成 | |
hsla(100deg, 25% , 25% , 0.5) ⇒ rgba(58, 80, 48, 0.5) | ||
adjust-hue( $color, $degrees) | 指定色の色相を- 360°~360°の範囲で変化 | |
adjust-hue(#3c0, 60deg) ⇒ #00cc99 | ||
lighten( $color, $amount) | 指定色の輝度を指定量だけ明るく | |
lighten(#3c0, 40% ) ⇒ #b3ff99 | ||
darken( $color, $amount) | 指定色の輝度を指定量だけ暗く | |
darken(#3c0, 40% ) ⇒ #269900 | ||
saturate( $color, $amount) | 指定色の彩度を指定量だけ増加 | |
saturate(#3c0, 10% ) ⇒ #33cc00 | ||
desaturate( $color, $amount) | 指定色の彩度を指定量だけ減少 | |
desaturate(#3c0, 10% ) ⇒ #38c20a | ||
grayscale( $color) | 指定の色をグレースケール変換 | |
grayscale(#00f) ⇒ #808080 | ||
invert( $color) | 色を反転 | |
invert(#f00) ⇒ #00ffff | ||
mix( $color1, $color2, [ $weight]) | 2個の色を混ぜる($weightは$color2の割合で0~1の範囲) | |
mix(#fff, #00f, 25% ) ⇒ #3f3fff | ||
透明度 | alpha( $color) | 指定色の透明度を取得(0~1) |
alpha(blue) ⇒ 1 | ||
fade-in( $color, $amount) | 指定色の不透明度を増加 | |
fade-in(rgba(0, 0, 10, 0.3), 0.4) ⇒ rgba(0, 0, 10, 0.7) | ||
fade-out( $color, $amount) | 指定色の透明度を増加 | |
fade-out(rgba(0, 0, 10, 0.6), 0.4) ⇒ rgba(0, 0, 10, 0.2) | ||
リスト | length( $list) | リスト長を取得 |
length(10 20 30) ⇒ 3 | ||
nth( $list, $n) | リストから$n番目の値を取得 | |
nth(10 20 30, 2) ⇒ 20 | ||
index( $list, $value) | 指定された値のリスト位置を取得 | |
index(10 20 30 40, 30) ⇒ 3 | ||
join( $list1, $list2, [ $sep]) | リストをひとつにまとめる | |
join(10 20 30, 40 50 60) ⇒ (10 20 30 40 50 60) | ||
その他 | if( $cond, $true, $false) | 条件式trueであれば$trueを、さもなくば$falseを返す |
if(true, 10px, 20px) ⇒ 10px | ||
unit( $number) | 値から単位を取得 | |
unit(5px) ⇒ "px" |
9.4.6 ディレクティブ
ディレクティブとは、「@名前」の形式で指定できる命令のことで、条件分岐や繰り返し処理、Mixinのようなさまざまな処理制御に対応しています。以下に、主なものをまとめます。
条件分岐を表現する - @if…@else if…@else
@ifディレクティブは、条件式がtrueの場合に、配下のスタイルを有効にします。たとえば以下は、変数$typeの値に応じて、colorプロパティの値を切り替える例です。
$type: spring;
div {
@if $type == spring {
color: #0f0;
} @else if $type == fall {
color: #f30;
} @else {
color: #0ff;
}
}
|
div {
color: #0f0; }
|
リストを繰り返し処理する - @each
@eachディレクティブは、リストから順番に値を取り出して、配下のスタイル定義を出力します。たとえば以下では、fine/cloudy/rainyを順に$typeにセットし、backgroud-imageプロパティの画像パスに埋め込んでいます。
@each $type in fine, cloudy, rainy {
.item-#{$type} { background-image: url('/images/#{$type}.gif'); }
}
|
.item-fine {
background-image: url("/images/fine.gif"); }
.item-cloudy {
background-image: url("/images/cloudy.gif"); }
.item-rainy {
background-image: url("/images/rainy.gif"); }
|
条件式に応じて処理を繰り返す - @while
@whileディレクティブは、指定された条件式がtrueである間だけ、配下のスタイル定義を出力します。たとえば以下は変数$iを1~3の範囲で変化させて、それに応じた背景色(background-colorプロパティ)を生成します。lightenは、指定色を指定量だけ明るくする関数でした。
$i: 1;
@while $i < 4 {
.sect#{$i} { background-color: lighten(#300, 15% * $i); }
$i: $i + 1;
}
|
.sect1 {
background-color: maroon; }
.sect2 {
background-color: #cc0000; }
.sect3 {
background-color: #ff1a1a; }
|
スタイル定義を再利用する - @mixin/@include
@mixinディレクティブ(ミックスイン)は、スタイル定義を再利用するためのしくみです。@mixinディレクティブで定義したスタイルは、@includeディレクティブで任意の場所に埋め込むことができます。
たとえば以下は、あらかじめ定義しておいたcommon-boxミックスインを、別の場所で再利用する例です。
@mixin common-box { // ……common-boxミックスインを定義
border: solid 1px #300;
font-size: 11px;
}
.menu {
@include common-box; // ……ミックスインでの定義内容を埋め込み
text-align: left;
}
|
.menu {
border: solid 1px #300;
font-size: 11px;
text-align: left; }
|
@mixinディレクティブでは引数を受け取ることもできます。
@mixin common-border($color, $backcolor: #00f) { // ……引数$color、$backcolor(デフォルト値は#00f)を受け取るcommon-borderミックスイン
border: solid 1px #{$color};
background-color: #{$backcolor};
}
.top {
@include common-border(#300, #ffc); // ……引数付きのミックスインを呼び出し
margin: 0px;
}
|
.top {
border: solid 1px #330000;
background-color: #ffffcc;
margin: 0px; }
|
スタイル定義を継承する - @extend
@extendディレクティブは、定義済みのスタイルの定義を継承して、新たなスタイルを定義します。たとえば以下は、main-contentスタイルを継承して、subcontentスタイルを生成する例です。
.main-content {
color: #300;
background-color: #ffc;
}
.sub-content {
@extend .main-content;
border: solid 2px #003;
}
|
.main-content, .sub-content { // ……継承先のセレクターが補完される
color: #300;
background-color: #ffc; }
.sub-content {
border: solid 2px #003; }
|
コンパイル済みのCSSを見ると、継承先(子スタイル)のセレクターが継承元(親スタイル)のそれに追加されていることが確認できます。これによって、あるスタイル定義を拡張、積み重ねながら、新たなスタイルを定義するということが、よりスリムに表現できます。
ここでは一段階の継承のみ表現していますが、Rubyのオブジェクトと同じく、子スタイルを更に継承した孫スタイルを、そのまた、曾孫スタイルを作成することも可能です。
ミックスインにも似ていますが、ミックスインがあらかじめ再定義すべきスタイルを@mixinディレクティブで切り出しておく必要があるのに対して、@extendディレクティブでは既にあるスタイル定義をそのまま再利用できるという点でより手軽です。また、スタイル同士に明確な親子関係がある場合には、継承を利用するのがより直感的でしょう。
外部スタイルシートをインポートする - @import
@importディレクティブは、外部の.scssファイルをインポートします。@importディレクティブを利用することで、外部ファイルで定義された変数やミックスインも呼び出せるようになります。その性質上、特にミックスインなどは外部ファイル化し、必要なファイルからインポートするのが望ましいでしょう。
@importディレクティブでは拡張子の「.scss」を省略しても構いません。よって、以下のコードは同じ意味です。
@import 'common';
@import 'common.scss';
|
9.4.7 コメント
SCSSのコメントには、JavaScriptと同じく、以下の2種類があります。
- //(単一行コメント)
- /* … */(複数行コメント)
ただし、単一行コメントはコンパイル時に破棄されますが、複数行コメントはコンパイルの前後で維持される点に注意してください。その性質上、複数行コメントにはライセンス表示など、配布時にも維持するような内容を記述します。
// コメントです。
/* これも
コメントです。
*/
|
……単一行コメントは破棄される
/* これも
コメントです。
*/
|
■
次回は、最終回として、開発したRailsアプリを本番環境へ配置する方法について説明します。
※以下では、本稿の前後を合わせて5回分(第7回~第11回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
8. CoffeeScript入門(前編) ― CoffeeScriptの基本構文
Rubyプログラマーの必須知識「CoffeeScript」の基礎として、基本構文/変数とリテラル表現/演算子/制御構文を解説。書籍転載の8本目(「Part 3《応用編》 第9章 クライアントサイド開発」より)。
9. CoffeeScript入門(後編) ― 関数/オブジェクト指向構文/即時関数
CoffeeScriptの基礎を解説。今回は関数/オブジェクト指向構文/即時関数について説明する(書籍転載の9本目)。CoffeeScriptをマスターしよう。
10. 【現在、表示中】≫ Sass(SCSS)入門
CSSのコードを生成するための言語「Sass(SCSS)」の基礎として、基本的な使い方/スタイル定義のネスト/変数/演算子/関数/ディレクティブ/について解説。書籍転載の10本目(「Part 3《応用編》 第9章 クライアントサイド開発」より)。
11. Apache+Passenger環境/Heroku環境への、Railsアプリの配置
書籍転載の最終回。開発したRailsアプリを本番環境へ配置する方法について説明する(「Part 3《応用編》 第10章 Railsの高度な機能」より)。