Sass は Less, Stylus, Tass, PCSS などと同様の CSS を拡張したメタ言語のひとつです。
Less と Sass どちらがよいのか比べてみました。初心者向きの Less、プログラマ向けの Sass といったところでしょうか。
Sass には二つの形式の構文があります。一つは Sass(Syntactically Awesome Stylesheets)構文で、Python と同様インデント(字下げ)でブロックを、改行で文末を示します。もうひとつは SCSS(Sassy CSS)構文で、CSSと同様 { ... } でブロックを、セミコロン(;)で文末を示します。Sass構文ファイルの拡張子は .sass、SCSS構文ファイルの拡張子は .scss を用います。
$font-stack: Helvetica, sans-serif $primary-color: #333 body font: 100% $font-stack color: $primary-color
$font-stack: Helvetica, sans-serif; $primary-color: #333; body { font: 100% $font-stack; color: $primary-color; }
sass-convert コマンドを用いて Sassファイルを SCSSファイルに、SCSSファイルを Sassファイルに変換することができます。
# sass-convert example.sass example.scss # sass-convert example.scss example.sass
Sass が提唱された当初は Sass構文のみでしたが、CSS との親和性から SCSS構文が追加されました。SCSS構文は CSS と互換性があり、有効な CSS構文は、有効な SCSS構文でもあります。また、SCSS構文では、古い IE の filter: などのベンダ依存構文も使用することが可能です。現在では SCSS構文が主流となっており、本書でも以降の説明は SCSS構文を用いて説明します。
Red Hat Enterprise Linux や CentOS 系では下記の様にインストールします。
# yum -y install ruby rubygems # gem install sass # sass -v Sass 3.4.19 (Selective Steve)
Ubuntu 系では下記の様にインストールします。
# sudo apt-get install ruby rubygems # sudo gem install sass # sass -v Sass 3.4.19 (Selective Steve)
Mac ではすでに Ruby や gem がインストール済みですので、ターミナルを起動し、下記の様にインストールします。
# sudo gem install sass
Windows では、Ruby Installer から環境にあった Ruby をダウンロードしてインストールします。インストールする際に「Ruby の実行ファイルへ環境変数 PATH を設定する」のチェックをオンにしてください。インストール後、コマンドプロンプトを起動し、下記の様にインストールしてください。
C:\>gem install sass
Python 環境では sass の代わりに pysass をインストールすることができます。
# pip install pysass # pysass --version
sass コマンドを用いて、Sassファイルや、SCSSファイルをコンパイルします。(# はプロンプトを意味します)
$color: red; body { color: $color; }
# sass example.scss example.css
--watch オプションをつけると sass コマンドは常駐し、ソースファイルが変更されると自動的に css ファイルにコンパイルします。ソースファイルと CSS ファイルの間はスペースではなく、コロン(:)としてください。
# sass --watch example.scss:example.css
ディレクトリ内のすべての scss ファイルを監視してコンパイルするには下記の様に実行してください。
# sass --watch scss_dir:css_dir
--style はコンパイル後の CSSファイルのスタイルを指定します。expanded は最もポピュラーな CSS 形式、nested は階層に合わせてネストされた形式、compact は1行に集約したコンパクトな形式、compressed は改行や空白を最小限に抑えた形式で出力します。
# sass --watch example.scss:example.css --style expanded
body { color: red; } body h1 { color: blue; }
body { color: red; } body h1 { color: blue; }
body { color: red; } body h1 { color: blue; }
body{color:red}body h1{color:blue}
-i オプションは、sass コマンドをインタプリタモードで起動します。
# sass -i >> "Hello world!!" "Hello world!!" >> 16px + 4px 20px >> rgb(100%, 50%, 50%) #ff8080 >> ← Ctrl-D で終了
その他のコマンドラインオプションは --help を参照してください。
# sass --help
複数行コメント /* ... */ と単行コメント // ... を利用することができます。複数行コメントはコンパイル後の CSSファイルにも残されますが、単行コメントは削除されます。
/* * 複数行コメント */ h1 { color: red; } // 単行コメント
/* * 複数行コメント */ h1 { color: red; }
出力形式を compressed に指定した場合は複数行コメントも削除されますが、コメントの最初の文字が ! の場合は残されます。compressedファイルに著作権情報等を残したい場合に有用です。
/* 普通のコメント */ /*! Copyright (C) 2015 Tohoho */ h1 { color: red; }
/*! Copyright (C) 2015 Tohoho */h1{color:red}
コメントの中で #{...} を用いて変数を参照することもできます。
$version: "1.2.3"; /* Common CSS file. Version: #{$version} */
/* Common CSS file. Version: 1.2.3 */
下記の様に $font-stack や $primary-color などの変数を定義・利用することができます。
$font-stack: Helvetica, sans-serif; $primary-color: #333; body { font: 100% $font-stack; color: $primary-color; }
body { font: 100% Helvetica, sans-serif; color: #333; }
下記のデータタイプがサポートされています。データタイプは type-of() 関数で調べることができます。
1, 2, 3 などの整数、1.2, 1.3 などの小数の他、10px など単位付きのものも数値として扱われます。
ダブルクォート(") またはシングルクォート(') で囲まれた文字列や、クォートで囲まれない文字列。例: "MG ゴシック", 'MS ゴシック', sans-serif, bold。#{...} で参照される際は、クォート付き文字列もクォート無し文字列として扱われます。
true または false で表される真偽値です。
カンマ無しのリスト (margin: のパラメータ 10px 15px 0 0 など) や、カンマ付きのリスト (font-family: のパラメータ Helvetica, Arial, sans-serif など)を扱うことができます。
キーバリューのリストを表します。$map: (key1: value1, key2: value2, key3: value3); など。
red や #f99 や #ff9999 など、CSS で利用可能な色情報。Sass の新しいバージョンでは、--style compressed でコンパイルすると、色情報は最も文字数の少ない色情報に変換されます。
null は値が存在しないことを示す特別な値です。
数値、長さ、色、文字列などに対して加算・連結(+)、減算(-)、乗算(*)、除算(/)、除余(%)などの演算を行うことができます。減算(-) を使用する際は負値と解釈されないように前後にスペースを入れてください。除算(/) を使用する際は値リストのデリミタと解釈されないように式を (...) で囲ってください。文字列の連結で、クォートで囲まれた文字と囲まれていない文字を連結する場合、連結後のクォータの有無は、右辺の形式に従います。
p { // 算術演算子 margin: 10px + 2px; margin: 10px - 2px; margin: 10px * 2; margin: (10px / 2); margin: 10px % 2; // 比較演算子 @if (10 < 20) { color: red; } @if (10 <= 20) { color: red; } @if (10 > 2) { color: red; } @if (10 >= 2) { color: red; } @if (10 == 10) { color: red; } @if (10 != 2) { color: red; } // 論理演算子 @if (2 < 3 and 4 < 5) { color: blue; } @if (2 < 3 or 5 < 4) { color: blue; } @if not (3 < 2) { color: blue; } // 文字列演算子 font-family: "sans-" + "serif"; font-family: "sans-" + serif; font-family: sans- + "serif"; // 色演算 color: #666 + #333; color: #fff - #666; color: #666 * 2; // 括弧による演算優先順位の制御 width: 1em + (2em * 3); }
p { /* 算術演算子 */ margin: 12px; margin: 8px; margin: 20px; margin: 5px; margin: 0px; /* 比較演算子 */ color: red; color: red; color: red; color: red; color: red; color: red; /* 論理演算子 */ color: blue; color: blue; color: blue; /* 文字列演算子 */ font-family: "sans-serif"; font-family: "sans-serif"; font-family: sans-serif; /* 色演算 */ color: #999999; color: #999999; color: #cccccc; /* 括弧による演算優先順位の制御 */ width: 7em; }
#{...} を用いることで、セレクタやプロパティ名にも変数や式を使用することができます。インターポレーションでは、クォータ付きの文字列もクォータ無しの文字列に変換されます。
$name: foo; $attr: "border"; p.#{$name} { #{$attr}-color: blue; }
p.foo { border-color: blue; }
セレクタの包含関係をネストで表現することができます。HTML構文のネストに似た形式で記述することが可能なため、より直観的に SCSS ファイルをメンテナンスすることが可能となります。
body { #header { h1 { color: blue; } } #body { color: green; } #footer { color: red; } }
body #header h1 { color: blue; } body #body { color: green; } body #footer { color: red; }
下記の様にコロン(:)を用いて、プロパティ名をネストで表現することもできます。
* { font: { size: 9pt; family: Arial; weight: bold; } }
* { font-size: 9pt; font-family: Arial; font-weight: bold; }
ネストの中では親セレクタを示す & を用いることができます。
a { &:hover { color: red; } &:link { color: #339; } }
a:hover { color: red; } a:link { color: #339; }
ミックスイン(Mixin) は、マクロやプログラミング言語の関数に似た、再利用可能な部品です。@mixin でミックスインを定義し、@include でミックスインを使用します。
@mixin mybox { border: 1px solid #999; } h4 { @include mybox; }
h4 { border: 1px solid #999; }
ミックスインに引数を渡すこともできます。
@mixin border-radius($radius) { -webkit-border-radius: $radius; -moz-border-radius: $radius; -ms-border-radius: $radius; border-radius: $radius; } .box { @include border-radius(10px); }
.box { -webkit-border-radius: 10px; -moz-border-radius: 10px; -ms-border-radius: 10px; border-radius: 10px; }
引数にデフォルト値を指定することができます。
@mixin mybox($color:#333, $width:1px) { border: $width solid $color; } p { @include mybox(red); }
p { border: 1px solid red; }
名前付きでパラメータを指定することも可能です。
@mixin mybox($color:#333, $width:1px) { border: $width solid $color; } p { @include mybox($width:3px); }
p { border: 3px solid #333; }
... を用いて可変引数を渡すことができます。
@mixin box-shadow($shadows...) { -webkit-box-shadow: $shadows; -moz-box-shadow: $shadows; box-shadow: $shadows; } p { @include box-shadow(0px 4px 5px #666); }
p { -webkit-box-shadow: 0px 4px 5px #666; -moz-box-shadow: 0px 4px 5px #666; box-shadow: 0px 4px 5px #666; }
色変換、透明度制御、文字列操作、数値演算、リスト操作、マップ操作、セレクタ操作、判定関数など、様々な関数が用意されています。関数の一覧は「関数リスト」を参照してください。
p { color: rgb(100%, 0%, 0%); }
p { color: #ff0000; }
関数の引数は、下記の様にキーワードを指定して記載することもできます。
p { color: rgb($red:100%, $green:0%, $blue:0%) }
p { color: #ff0000; }
@return を用いて関数を定義することができます。@return は関数の戻り値を示します。
@function add($x, $y) { @return $x + $y; } p { width: add(100px, 200px); }
p { width: 300px; }
@import を用いて他のファイルを読み込むことができます。@import によりソースファイルのメンテナンス性を向上させるとともに、複数のソースファイルをひとつの CSS ファイルにまとめてコンパイルすることで HTTP の通信回数を減らすことができます。
@import で指定するファイルは、拡張子を省略することができます。下記の場合、border.sass ファイルや border.scss ファイルが探索されます。両方のファイルが存在する場合はエラーとなります。
@mixin border($color) { border: 1px solid $color; }
@import "border"; h1 { @include border(#666); }
h1 { border: 1px solid #666; }
パーシャルは、他の Sass/SCSSファイルに @import されることを前提とした部品ファイルです。ファイル名の先頭をアンダーバー(_)にすることで、ファイルがパーシャルであることを示します。パーシャルファイルにすると、--watch オプションで自動コンパイルする際に、パーティションファイルに対してはコンパイルを行わず、無駄ファイルを生成しなくてすむようになります。
@import では、アンダーバー(_) を省略することができます。下記の場合、border.sass, border.scss, _border.sass, _border.scss ファイルが探索されます。複数のファイルが存在する場合はエラーとなります。
@mixin border($color) { border: 1px solid $color; }
@import "border"; h1 { @include border(#666); }
h1 { border: 1px solid #666; }
@extend により、他のセレクタで定義した内容を継承することができます。
.message { border: 1px solid #ccc; padding: 10px; color: #333; } .success { @extend .message; border-color: green; } .error { @extend .message; border-color: red; } .warning { @extend .message; border-color: yellow; }
.message, .success, .error, .warning { border: 1px solid #ccc; padding: 10px; color: #333; } .success { border-color: green; } .error { border-color: red; } .warning { border-color: yellow; }
!optional をつけると、セレクタが存在しない場合のエラーを抑制することができます。
.warning { @extend .message !optional; border-color: yellow; }
.warning { border-color: yellow; }
クラス名の先頭につけるドット(.)の代わりに % を用いることで、コンパイルされないプレースホルダを指定することができます。
%message { border: 1px solid #ccc; padding: 10px; color: #333; } .success { @extend %message; border-color: green; }
.success { border: 1px solid #ccc; padding: 10px; color: #333; } .success { border-color: green; }
if() は、第一引数が真であれば第二引数を、さもなくば第三引数を返します。
if(condition, value1, value2)
p { color: if(5 > 3, red, blue); }
p { color: red; }
@if は、条件が真となった場合に { ... } を有効にします。@else は「さもなくば」を意味します。
@if condition { ... }
p { @if 1 + 1 == 2 { border: 1px solid; } @if 5 < 3 { border: 2px dotted; } @if null { border: 3px double; } }
p { border: 1px solid; }
@else は「さもなくば」を意味します。
@if condition { ... } @else if { ... } @else { ... }
$type: monster; p { @if $type == ocean { color: blue; } @else if $type == monster { color: green; } @else { color: black; } }
p { color: green; }
$var の値を start から end までひとつづつ増やしながら(減らしながら) { ... } を繰り返します。through の場合は end になるまで、to の場合は end 未満の間繰り返します。
@for $var from start through end { ... } @for $var from start to end { ... }
@for $i from 1 through 3 { .item-#{$i} { width: 2em * $i; } }
.item-1 { width: 2em; } .item-2 { width: 4em; } .item-3 { width: 6em; }
list の要素を $var に代入しながら map を定義します。
@each $var[, $var...] in list or map { ... }
@each $color in red, green, blue { .color-#{$color} { color: $color; } }
.color-red { color: red; } .color-green { color: green; } .color-blue { color: blue; }
@each $h, $size in ( h1:3em, h2:2em, h3:1em ) { #{$h} { font-size: $size; } }
h1 { font-size: 3em; } h2 { font-size: 2em; } h3 { font-size: 1em; }
@each $h, $size in (h1, 3em), (h2, 2em), (h3, 1em) { #{$h} { font-size: $size; } }
h1 { font-size: 3em; } h2 { font-size: 2em; } h3 { font-size: 1em; }
@while は、条件が真である間 { ... } を繰り返します。
@while condition { ... }
$i: 1; @while $i < 4 { .item-#{$i} { width: #{($i * 100) + "em"}; } $i: $i + 1; }
.item-1 { width: 100em; } .item-2 { width: 200em; } .item-3 { width: 300em; }
@at-root は、指定したセレクタをネストせず、ルートセレクタとして定義します。
.parent1 { color: red; @at-root .child1 { color: green; } } .parent2 { color: red; @at-root { .child2a { color: green; } .child2b { color: blue; } } }
.parent1 { color: red; } .child1 { color: green; } .parent2 { color: red; } .child2a { color: green; } .child2b { color: blue; }
@at-root は、CSS を BEM記法や MindBEMding 記法で記述する際などに利用されます。
.searchBox { background-color: #ccc; @at-root &__keyword { width: 200px; } @at-root &__submitButton { width: 100px; } }
.searchBox { background-color: #ccc; } .searchBox__keyword { width: 200px; } .searchBox__submitButton { width: 100px; }
@at-root (with: ...) や @at-root(without: ...) は、@media や @support などの @ルールや、CSSルールを残すか除外するかを指定します。media, support は @mediaルール、@supportルール、rule は CSSルール(セレクタ)、all はすべての @ルールや CSSルールを残す、または除外します。
@media screen { .parent { .child1 { color: red; } @at-root { .child2 { color: red; } } @at-root(without:media) { .child3 { color: red; } } @at-root(without:rule) { .child4 { color: red; } } @at-root(without:all) { .child5 { color: red; } } } }
@media screen { .parent .child1 { color: red; } .child2 { color: red; } } .parent .child3 { color: red; } @media screen { .child4 { color: red; } } .child5 { color: red; }
Sass 3.2 で追加された機能で、{ ... } ブロックを引数として渡すことが可能となります。
@mixin xs { @media screen and (max-width: 767px) { @content; } } @include xs { margin-right: 5px; margin-left: 5px; }
Ruby 1.9 以降であれば、Sass はソースファイルの文字コードを推測します。BOM 情報があれば BOM に従い、無ければ @charset 宣言に従い、それも無ければ Ruby の文字列エンコーディングに従い、さもなくば、UTF-8 であるとみなします。
@charset "Shift_JIS"; * { font-family: "MS ゴシック"; }
セレクタの内部で利用可能という点以外では、@media は CSS の @media と同じように利用可能です。
.body { color: #333; @media screen and (min-width: 768px) { margin-right: 2em; margin-left: 2em; } }
.body { color: #333; } @media screen and (min-width: 768px) { .body { margin-right: 2em; margin-left: 2em; } }
変数定義の後ろに !default をつけると、変数に値が設定されていない場合のみ、変数代入が行われます。
$var1: red; $var1: blue; $var2: red; $var2: blue !default; h1 { color: $var1; } h2 { color: $var2; }
h1 { color: blue; } h2 { color: red; }
@debug はデバッグのための情報を書き出します。
@debug 10em + 12em;
Line 1 DEBUG: 22em
@warn はワーニング情報を書き出します。指定したメッセージに加え、スタイルシートのトレース情報が書き出されます。--quiet コマンドラインオプションや :quiet オプションで無効にすることができます。
@mixin my-box($color) { @if (type-of($color) != "color") { @warn "#{$color} is not color"; } border: 1px solid $color; } p { @include my-box(brue); }
WARNING: brue is not color on line 3 of example.scss, in `my-box' from line 9 of example.scss p { border: 1px solid brue; }
@error は処理を中断し、詳細なスタックトレース情報を書き出します。
@mixin my-box($color) { @if (type-of($color) != "color") { @error "#{$color} is not color"; } border: 1px solid $color; } p { @include my-box(brue); }
Error: brue is not color on line 3 of example.scss, in `my-box' from line 8 of example.scss Use --trace for backtrace. /* Error: brue is not color on line 3 of example.scss, in `my-box' from line 8 of example.scss 1: @mixin my-box($color) { 2: @if (type-of($color) != "color") { 3: @error "#{$color} is not color"; 4: } :
下記などの関数が用意されています。
各関数の詳細は下記を参照してください。