CSS→Stylusを学ぶまでの軌跡② SASS

# [SASS](sass-lang.com/)

![SASS](http://kwout.com/cutout/6/dn/iv/7gy_bor.jpg)

- CSSを効率的に書く為の機能
- .sass（Ruby/Haml系）
- **.scss（CSS）→CSSらしく記述でき、デザイナでも修正できるので主流となっている**

⇒さらに詳しく

- HTMLによるマークアップを簡略化するためのHamlから派生。
- コンパイラーは**Ruby**で実装。
- SCSS(.scss)ファイルのCSSファイルへの変換。
- サーバーサイドでの利用を想定。
- 非常に豊富な機能を持っており、条件分岐や繰り返しによる柔軟な制御が可能。
- 日本語のドキュメントが多く、開発コミュニティが安定。
- [Compassフレームワーク](http://compass-style.org/)が使えて便利？

## 前提知識
- HTML/CSS/CSS3
- Unix Command

## 公式サイト／学習サイト
- [Sass: Syntactically Awesome Style Sheets](sass-lang.com/)
- [ドットインストール（Sass/SCSS入門 (全15回)）](http://dotinstall.com/lessons/basic_sass)
- [CSSコーディングで泣かないためのSassの基礎知識と10の利点 (1/3)](http://www.atmarkit.co.jp/ait/articles/1402/17/news102.html)
- [CSSコーディングで泣かないためのSassの基礎知識と10の利点 (2/3)](http://www.atmarkit.co.jp/ait/articles/1402/17/news102_2.html)
- [CSSコーディングで泣かないためのSassの基礎知識と10の利点 (3/3)](http://www.atmarkit.co.jp/ait/articles/1402/17/news102_3.html)
- [SassでCSSの弱点を克服しよう](http://www.atmarkit.co.jp/fcoding/articles/sass/sassa.html)


## SASS & SCSS のメリット

- 変数が使える。
- CSSの継承をネストでまとめられる。
- ネームスペースでネストできる。
- Partial（@importでCSSファイルを1つにまとめられる。）
- @mixinと@includeでスタイルを使い回せる。@mixinでは引数も使える。
- 算術演算子で値の加減乗除ができる。
- 別の単位同士で演算できる。
- 条件分岐（@if）や繰り返し（@for, @while, @each）処理ができる。
- コンパイルオプションで変換の仕方を変えられる。

## 変換の流れ

![.scss（.sass） ⇒ .css](http://image.itmedia.co.jp/ait/articles/1402/17/dreamWP03_2.jpg)

+ SCSSをCSSに変換し、「css」フォルダに保存する。
+ cssに保管されたCSSをindex.htmlでインポートする。

```text:フォルダ構成
 +-index.html
 +-scss（記述ファイル保存先）
   +-main.scss
 +-css（変換後ファイル保存先）
   +-main.css
   +-main.css.map
```

## セレクタに変数を代入

```scss:style.scss
@h1-color:red;
@h2-color: darken(@h1-color, 10%);
@h1-size: 24px;
@h2-size: @h1-size - 8px;

@header: h;
@color : color;
@dir : "/img";

@{header}1{
  font-size: @h1-size;
  @{color}: @h1-color;
}

@{header}2 {
  font-size: @h2-size;
  @{color}: @h2-color;
  background: url("@{dir}/bg.png");
}
```

```css:style.css
h1 {
  font-size: 24px;
  color: red;
}
h2 {
  font-size: 16px;
  color: #cc0000;
  background: url("/img/bg.png");
}
```

## ネスト／疑似クラス（＆） 

```scss:style.scss
header {
  font-size: 18px;
  a {
    color: red;
    &:hover {
      color: green;
    }
  }
}

// .button-ok, .button-ng
.button {
  &-ok {
    color: green;
  }
  &-ng {
    color: red;
  }
}
```

```css:style.css
header {
  font-size: 18px;
}
header a {
  color: red;
}
header a:hover {
  color: green;
}
.button-ok {
  color: green;
}
.button-ng {
  color: red;
}
```

### 簡単な変換例

```sass:sample.sass
body
  color: #000
```

```scss:sample.scss（CSSに近い）
body{
	color:#000;
}
```

　↓ コンパイル

```css:sample.css（CSSに近い）
body {
  color:#000;
}
```

## SCSS記法とSASS記法とCSSの違い

| |SCSS記法|SASS記法|CSS|
|:-----------|:------------:|:------------:|:------------:|
|波括弧　{}|必要|不要<br/>インデントで<br/>ネスト|必要|
|セミコロン（;）|必要|不要|必要|
|コロン（:）の後にスペース|	不要|必要|不要|
|ミックスイン|@mixin|=|なし|
|インクルード|@include|+|なし|
|拡張子|.scss|.sass|.css|

## 環境（インストール）

```bash:console
# Ruby インストール状態の確認（インストール済）
$ ruby -v
ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin13]
$ sudo gem update --system
$ sudo gem install sass
Fetching: sass-3.4.18.gem (100%)
Successfully installed sass-3.4.18
Parsing documentation for sass-3.4.18
Installing ri documentation for sass-3.4.18
Done installing documentation for sass after 6 seconds
1 gem installed
$ sudo gem list sass

*** LOCAL GEMS ***

sass (3.4.18)
```

## SCSS ⇒ CSS　変換

```scss:main.scss（変換元ファイル）
/**
 * 変換後、反映されるコメント
 */
// 変換後、反映されないコメント
#main {  /*親要素*/
  width : 90%;  /*属性*/ 
  p {    /*子要素*/
    font-size:16px;
    a {
      text-decoration: none;
      /*&=入れ子の構造でhoverが有る場合の親要素を指す。*/
      &:hover {
        font-weight: bold;
      }
    }
  }
}
```

```bash:console
# sass （オリジナル）:（出力先）
$ sass scss/main.scss:css/main.css
# 字下げが綺麗になる。
$ sass --style expanded scss/main.scss:css/main.css
```

- **nested／expanded／compact／compressed**のオプションを使用可。

```css:main.css（変換先ファイル）
@charset "UTF-8";
/**
 * 変換後、反映されるコメント
 */
#main {
  /*親要素*/
  width: 90%;
  /*属性*/
}
#main p {
  /*子要素*/
  font-size: 16px;
}
#main p a {
  text-decoration: none;
  /*&=入れ子の構造でhoverが有る場合の親要素を指す。*/
}
#main p a:hover {
  font-weight: bold;
}

/*# sourceMappingURL=main.css.map */
```

### SCSSに変更がある場合、自動的に変換する。

```bash:console
$ sass --style expanded --watch scss:css
>>> Sass is watching for changes. Press Ctrl-C to stop.
[Listen warning]:
  Listen will be polling for changes. Learn more at https://github.com/guard/listen#polling-fallback.
>>> Change detected to: scss/main.scss
      write css/main.css
      write css/main.css.map
# Ctrl+Cで終了
```

## 変数の使用

- 変数は「**$**変数名**:**値**;**」で定義する。

```scss:main.scss
/**
 * 変数：データにつけるラベル
 * データ型（数値、文字列、真偽、色、リスト）
 * 四則演算も可能
 */
$baseFontSize: 14px;
#main {
  width : 90%;
  p {
    font-size:$baseFontSize;
    .sub {
      font-size: $baseFontSize - 2px;
    }
  }
}
```

```css:main.css
@charset "UTF-8";
/**
 * 変数：データにつけるラベル
 * データ型（数値、文字列、真偽、色、リスト）
 * 四則演算(+ - * /) も可能
 */
#main {
  width: 90%;
}
#main p {
  font-size: 14px;
}
#main p .sub {
  font-size: 12px;
}

/*# sourceMappingURL=main.css.map */
```

## 変数の埋込み

- 変数の埋込みは「**$**FOO+**$**BAR」で連結する。もしくは「#{**$**FOO}#{**$**BAR}」のように埋込む。
- 「#{\$FOO\$BAR}」とコーディングしたところ、\$FOOと\$BARの間に半角スペースが開いたため、この記述は不可？

```scss:main.scss
/**
 * 文字列変数を埋込む
 */
$imageDir: "../img/";
$image: "bg.png";

#main {
  width : 90%;
  p {
    font-size:#{12 + 12}px;
    //background: url($imageDir + "bg.png");
    background: url("#{$imageDir}#{$image}");
  }
}
```

```css:main.css
@charset "UTF-8";
/**
 * 文字列変数を埋込む
 */
#main {
  width: 90%;
}
#main p {
  font-size: 24px;
  background: url("../img/bg.png");
}

/*# sourceMappingURL=main.css.map */
```

## 色を扱う（Sass Built-in Functions）

```scss:main.scss
/**
 * 色を埋込む
 */
 $brandColor: red;
// $brandColor: #ff0000;
// $brandColor: rgb(255, 0, 0, 0.9);

#main {
  width : 90%;
  p {
    font-size:14px;
    // lighten, darken
    color: lighten($brandColor, 30%);
  }
}

```

- [Search:Sass Built-in Functions](http://sass-lang.com/documentation/Sass/Script/Functions.html)

## 分岐（@if, @else）

```scss:main.scss
$debugMode: true;
$x: 30;

#main {
  @if $debugMode == true { // == , != , <=, >=
    color: red;
  } @else {
    color:green;
  }
  p {
    @if $x > 20 { color: red; }
  }
}
``` 

```css:main.css
#main {
  color: red;
}
#main p {
  color: red;
}

/*# sourceMappingURL=main.css.map */
```

## ループ(@for, @while）

```scss:main.scss
@for $i from 10 through 14 {
  .fs#{$i} { font-size: #{$i}px; }
}

$i: 10;
@while $i <= 14 {
  .ws#{$i} { font-size: #{$i}px; }
  $i: $i + 1;
}
```

```css:main.css
.fs10 {
  font-size: 10px;
}

.fs11 {
  font-size: 11px;
}

.fs12 {
  font-size: 12px;
}

.fs13 {
  font-size: 13px;
}

.fs14 {
  font-size: 14px;
}

.ws10 {
  font-size: 10px;
}

.ws11 {
  font-size: 11px;
}

.ws12 {
  font-size: 12px;
}

.ws13 {
  font-size: 13px;
}

.ws14 {
  font-size: 14px;
}

/*# sourceMappingURL=main.css.map */
```

## リスト

```scss:main.scss
$animals: cat, dog, tiger;

@each $animal in $animals {
  .#{$animal}-icon {background: url("#{$animal}.png");}
}

@each $animal in cat, dog, tiger {
  .#{$animal}-icon {background: url("#{$animal}.png");}
}
```

```css:main.css
.cat-icon {
  background: url("cat.png");
}

.dog-icon {
  background: url("dog.png");
}

.tiger-icon {
  background: url("tiger.png");
}

.cat-icon {
  background: url("cat.png");
}

.dog-icon {
  background: url("dog.png");
}

.tiger-icon {
  background: url("tiger.png");
}

/*# sourceMappingURL=main.css.map */
```

## 関数（@function）・デバッグ表示（@debug）

関数内の変数はプライベード変数となっている事に注意する。

```scss:main.css
$totalWidth: 940px;
$columCount: 5;

@function getColumnWidth($width, $count) {
  $padding: 10px;
  $columnWidth: floor(($width - ($padding * ($count - 1))) / $count);
  @debug $columnWidth;
  @return $columnWidth;
}

.grid {
  float: left;
  width: getColumnWidth($totalWidth, $columCount);
}
```

```css:main.css
.grid {
  float: left;
  width: 180px;
}

/*# sourceMappingURL=main.css.map */
```

## ファイル分割（Partial）

```scss:_settings.scss
$totalWidth: 940px;
$columCount: 5;
```

```scss:_functions.scss
@function getColumnWidth($width, $count) {
  $padding: 10px;
  $columnWidth: floor(($width - ($padding * ($count - 1))) / $count);
  @debug $columnWidth;
  @return $columnWidth;
}
```

```scss:main.scss
@import "settings";
@import "functions";

.grid {
  float: left;
  width: getColumnWidth($totalWidth, $columCount);
}
```

## @mixin & @includex 

```scss:main.scss
@mixin round ($radius) {
  border-radius: $radius;
}

.label {
  font-size: 12px;
  @include round(5px);
}
```

```css:main.css
.label {
  font-size: 12px;
  border-radius: 5px;
}

/*# sourceMappingURL=main.css.map */
```

## 継承（@extend）

```scss:main.scss
// @extend（継承）
// .errorMsg, .warningMsg

.msg {
  font-size: 12px;
  font-weight :  bold;
  padding: 2px 4px;
  color: white;

}
.errorMsg {
  @extend .msg;
  background: red;
}

.warningMsg {
  @extend .msg;
  background: orange;
}
```

```css:main.css
.msg, .errorMsg, .warningMsg {
  font-size: 12px;
  font-weight: bold;
  padding: 2px 4px;
  color: white;
}

.errorMsg {
  background: red;
}

.warningMsg {
  background: orange;
}

/*# sourceMappingURL=main.css.map */
```
----