sass-basics-thumbnail

はじめに

SassはCSS言語の拡張言語です。以下のような特徴があります。

  • ファイルをひとつにまとめること(パーシャル)ができる
  • 処理を入れ子(ネスト)にできる
  • 変数が使用できる
  • コードを再利用(継承、ミックスイン)できる
  • 1行コメントを使うことができる
  • ifやfor、関数などプログラムのような処理ができる
  • コードを圧縮できる
  • Webフレームワークに標準で組み込まれていることが多い

本記事では個人的によく使用するSassの機能をまとめます。この記事に掲載している内容はSassの持つ機能の極一部ですので、その点についてはご留意ください。

Sassの注意点

  • 環境構築が必要
  • ブラウザはSassファイルを読み込むことはできないため、CSSファイルに変換(トランスパイル)する必要がある
  • 拡張子は.sassではなく.scssを使うのが一般的

環境構築

環境構築についてはMacでの方法を記述します。Windowsは割愛します。

webpackを利用する

webpackを利用することでもSassが使えるようになります。また、多くのWebアプリケーションフレームワークではSassあるいはwebpackを簡単に利用できるようになっているため、そうしたフレームワークを使用して開発する場合は、Sassの環境構築はそちらを参考にしてください。

npmとwebpackを利用してフロントエンド開発環境を構築する

Homebrewのインストール

MacではHomebrewを利用してSassの利用に必要なパッケージをインストールします。
Homebrewのインストールは下記のページを参考にしてみてください。

Macのパッケージ管理システム Homebrewを導入する

rbenvのインストール

Rubyのバージョン管理が行えるrbenvをインストールします。

$ brew install rbenv

rbenvのコマンドが利用できるようにパスを通します。
シェルはbashを利用しているため、.bash_profileにパスを追記しています。
シェルがzshの場合は、.zshrcに追記してください。

$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

ターミナルを再起動します。 その後下記のコマンドを実行して、バージョン情報が表示されればrbenvは有効になっています。

$ rbenv -v

Rubyのインストール

下記コマンドでrubyをインストールします。数値はRubyのバージョンとなります。

$ rbenv install 2.6.6

インストール後、システム全体のRubyのバージョンを変更するために下記コマンドを実行します。

$ rbenv global 2.6.6

下記コマンドを打ち、上記でインストールしたバージョンのRubyが表示されているか確認します。

$ ruby -v
ruby 2.6.6

Sassのインストール

Sassをインストールします。Rubyの拡張ライブラリであるGemとしてインストールします。

下記コマンドを実行してシステム全体にインストールすることもできますが、BundlerというRuby Gemのパッケージ管理ツールを利用して、プロジェクトごとにSassをインストールすることもできます。

$ gem install sass

BundlerからSassを使う場合

BundlerもGemの一つのため、下記コマンドでインストールします。

$ gem install bundler

インストールできたらプロジェクト用のディレクトリを作成し、移動します。

$ mkdir sass-sample
$ cd sass-sample

下記コマンドを実行すると、プロジェクトディレクトリ内にGemfileというファイルが作成されます。
このファイル内にプロジェクトで使用するGemを記述します。

$ bundle init

Gemfileを開いて、中にgem 'sass'と記述して、ファイルを保存します。 その後下記コマンドを実行するとGemfileの内容に応じてSassがインストールされます。

$ bundle install

これでSassが利用できるようになりました。

CSSへのトランスパイル(変換)

先述したように、ブラウザはSassファイルを読み込むことができません。そのため、CSSファイルへと変換する必要があります。

拡張子が.scssのファイルをCSSに変換するにはsassコマンドを使います。

$ sass Sassファイル名:出力するCSSファイル名 オプション

変換したいsassファイルと変換後のCSSファイル名をコロン(:)で繋げます。
ファイル名の前に相対パスを表記することで、出力するディレクトリを指定できます。
オプションは目的に応じて記述します。シンプルに変換するだけなら不要です。

$ sass test.scss:test.css

# ディレクトリを相対パスで指定する
$ sass src/style.scss:dist/style.css

sassコマンドをscssコマンドに置き換えても同じ動作をします。

sass --helpコマンドでヘルプを呼び出せます。

styleオプション

--style スタイル名オプションを利用することで、変換後のCSSの出力形式を指定できます。
styleオプションは全部で4種類あります。

sass src/style.scss:dist/style.css --style nested
sass src/style.scss:dist/style.css --style expanded
sass src/style.scss:dist/style.css --style compact
sass src/style.scss:dist/style.css --style compressed

# --styleの省略形として-tを使うこともできます
sass src/style.scss:dist/style.css -t compressed

nested

Sassはセレクタなどをネスト(入れ子)で記述することができますが、そのネストをインデントで表現した形でCSSに出力されます。
オプションを指定しなかった場合のデフォルトのスタイルです。

expanded

通常のCSSのように、可視性の高いスタイルになります。

compact

セレクタとプロパティが1行で表現されます。

compressed

インデントや改行、コメント文などをすべて取り除いて圧縮された形で出力されます。
ファイルサイズが軽量化されます。

watchオプション

--watchオプションをつけてsassコマンドを実行すると、対象のSassファイルが監視対象となり、ファイルに変更が加えられるとすぐにトランスパイルを行うようになります。
Ctrl + Cで監視を終了することができます。

# 一つのsassファイルの変更を監視
sass --watch src/style.scss:dist/style.css --style expanded

# ディレクトリ内の変更を監視する
sass --watch src:dist --style compressed

シェルスクリプトを使ってトランスパイルする

Sassを使うたびに今までのコマンドを打つのは面倒なので、一連の処理をファイルにまとめてすぐに実行できるようにします。

Windows

バッチファイル(.bat)を作成して、それをダブルクリックするとSassのトランスパイルが簡単に利用できるようになります。

::行の先頭にコロンを二つつけた行はコメントになります

::バッチファイルがある場所に移動するコマンドです
cd /d %~dp0

::sassコマンドを記述します
sass --watch src:dist --style compressed
::sass --watch src:dist --style expanded

Mac

拡張子を.shのファイルを作成することでシェルスクリプトが作成できます。

#!/bin/sh

cd $(dirname $0)
sass --watch src:dist --style compressed

# この行はコメントになります
# sass --watch src:dist --style expanded

#!/bin/shはshebang(シェバン)と呼ばれ、このファイルがシェルスクリプトであることを認識させるための記述です。 cd $(dirname $0)は、このシェルスクリプトのあるディレクトリまで移動するという処理です。

ファイルを作成後、以下のコマンドで、このファイルに実行権限をつけます。

$ chmod u+x sass.sh

シェルスクリプトのパスをターミナルで入力すると、シェルスクリプトを実行できます。

$ ./sass.sh

ファイルをダブルクリックで実行したい場合は、sass.shを右クリック -> 情報を見る -> このアプリケーションで開く -> ターミナル.appを指定することで利用できます。

Sassの主な機能

インポート、パーシャル

CSSにも@import文がありますが、Sass独自のインポート機能パーシャルと組み合わせて利用することで、CSS変換後のファイルをひとつにまとめることができます。

まず、パーシャル(partial)とは、scssファイル名の先頭にアンダーバー(_)をつけることで、そのファイルをCSSに変換しないようにする機能です。
_basic.scssのように書きます。

パーシャルとして書いた_basic.scssはCSSに変換されないため、このままでは書いたスタイルは反映されませんが、@import機能を使用することで、他のSassファイルに取り込まれ、ひとつのファイルにまとめることができます。

例として、_reset.scss_basic.scssの二つのパーシャルファイルをmain.scssにまとめる際は下記のように記述します。
先頭の_.scss拡張子を省略して記述します。

main.scss

@import "reset";
@import "basic";

インポートされるSassファイルは上から順番に読み込まれます。

インポートのネスト

@importはネストして使うことができます。(ネストの詳しい説明はネストの項をご覧下さい。)

.old-page {
  @import "old-style";
}

上記のようにセレクタの中に@import文を書くことで、_old-style.scss内に記述されたスタイルの、全セレクタの先頭には.old-pageがつくことになります。CSSに変換すると下記のようになります。

.old-page header {
  padding: 24px;
}
.old-page footer {
  background: #fefefe;
}

こうすることで、例えばページのリニューアルを行う際に、古いスタイルと新しいスタイルを切り分けて作業ができるようになります。

コメント

Sassファイルには、CSS従来のコメント文だけでなく、一行コメントの//が使えます。

/* CSS従来のコメント文 */
// Sassのコメント文 この行はコメントアウトされます

SassのコメントはCSS変換時に削除されます。CSSの従来のコメント文も、--style compressedオプションの場合だと削除されます。

変数

プログラミング言語のように、値を変数に格納することができます。

$変数名: 値;

上記のように先頭に$をつけて記述することで、変数を宣言することができます。 CSSのプロパティと値を定義するような形式で記述することで、値を変数に代入できます。

例えば下記の変数$white-colorは下記のように利用することができます。

$white-color: #fff;
.wrapper {
  background: $white-color;
}

変数は基本的にプロパティの値として参照します。他の部分でも参照したい場合はインターポレーションを用いることで変数を参照できるようになります。詳しくは変数や引数を柔軟に使用する(インターポレーション)の項をご覧ください。

変数の命名規則

変数名はCSSのClassやID名と同様に命名規則があります。

  • 半角英数字の他にハイフン(-)やアンダーバー(_)を使用できる
  • 日本語などのマルチバイト文字が利用できる
  • 変数名の先頭に連続したハイフン(--)は使用できない
  • 変数名の先頭に半角数字は使用できない

変数のスコープ

変数にはスコープ(適用できる範囲)があります。
セレクタ内の波括弧({})で囲んだ中、つまりCSSルールセット内に変数が宣言されていた場合、その変数はその波括弧の外側では参照することができません。

.sidebar {
  $accent-color: #4c9aee;
}
.main {
  // ここでは$accent-colorを利用できない
  background: $accent-color;
}

全体で使用したい変数は_variable.scssといったファイルでまとめて宣言しておき、インポートする際には、_variable.scssを先頭に記述しておくことで他のSassファイルでも使うことができます。

_variable.scss

$accent-color: #4c9aee;

main.scss

@import "variable";
@import "reset";
@import "basic";

ネスト

CSSのルールセットをネスト(入れ子)することができます。

.box {
  padding: 16px;
  // .boxの中に.buttonセレクタを格納できます
  .button {
    margin: 0px;
  }
  // セレクタ記号を使うこともできます
  + .box {
    padding-bottom: 0px;
  }
  > a {
    text-decoration: none;
  }
}

上記のコードをCSSに変換すると下記のようになります。

.box {
  padding: 16px;
}
.box .button {
  margin: 0px;
}
.box + .box {
  padding-bottom: 0px;
}
.box > a {
  text-decoration: none;
}

ネストで階層的に表現することでコードの記述量が減り、またメンテナンスもしやすくなります。

親セレクタを柔軟に参照できるアンパサンド

アンパサンド(&)記号を使用することで、親セレクタを呼び出す位置を指定することができます。
下記のコードをご覧ください。

.tag a {
  background-color: #f3f0e5;
  &:hover {
    background-color: #ffe484;
  }
  header & {
    background-color: #81d3e6;
    color: #fefefe;
  }
}

CSSに変換するとこのようになります。

.tag a {
  background-color: #f3f0e5;
}
.tag a:hover {
  background-color: #ffe484;
}
header .tag a {
  background-color: #81d3e6;
  color: #fefefe;
}

&記号を使って.tag aセレクタを呼び出す場所を、柔軟に設定できることがわかります。

ミックスイン

ミックスイン(mixin)とは、スタイルの集合体をあらかじめ定義しておき、任意の場所で呼び出すことができる機能です。
スタイルの再利用性を高めることができます。またメンテナンスも容易になります。

ミックスインの定義は下記のように行います。

@mixin ミックスイン名 {
  スタイルの集合体
}

ミックスイン名の命名規則は変数と同様になります。

ミックスインを呼び出す際は@include ミックスイン名;と記述します。

// ミックスインの定義
@mixin indication {
  padding: 2px 8px;
  border-radius: 7px;
  color: #1b2b3c;
  margin: 0px 12px 16px 0px;
  display: inline-block;
  width: auto;
  line-height: 2;
}
// ミックスインの呼び出し
.user-status {
  @include status-indication;
  span {
    color: #a3abb4;
  }
}
.admin-status {
  @include status-indication;
}

CSSに変換すると以下のコードになります。

.user-status {
  padding: 2px 8px;
  border-radius: 7px;
  color: #1b2b3c;
  margin: 0px 12px 16px 0px;
  display: inline-block;
  width: auto;
  line-height: 2;
}
.user-status span {
  color: #a3abb4;
}
.admin-status {
  padding: 2px 8px;
  border-radius: 7px;
  color: #1b2b3c;
  margin: 0px 12px 16px 0px;
  display: inline-block;
  width: auto;
  line-height: 2;
}

また、ミックスインで定義するスタイルの集合体は、プロパティと値のルールセットだけではなく、セレクタを含むスタイルも定義できます。

@mixin window {
  .window {
    padding: 16px;
  }
}

ミックスインに引数を渡す

ミックスインには引数を渡すことができます。

@mixin ミックスイン名($引数名) {
  ルールセット
}

引数名の命名規則も変数と同様になります。

@mixin indication($margin-value) {
  padding: 2px 8px;
  border-radius: 7px;
  color: #1b2b3c;
  margin: $margin-value;
  display: inline-block;
  width: auto;
  line-height: 2;
}

呼び出す際は@include ミックスイン名(引数の値);と記述します。

@include ミックスイン名(引数の値);
section {
  @include indication(0px 12px 16px 0px);
}

上記の例をCSSに変換すると下記になります。

section {
  padding: 2px 8px;
  border-radius: 7px;
  color: #1b2b3c;
  margin: 0px 12px 16px 0px;
  display: inline-block;
  width: auto;
  line-height: 2;
}

引数の初期値

引数名のあとにコロン(:)を使うことで引数の初期値を設定することができます。

@mixin indication($margin-value: 0px 12px 16px 0px) {
  padding: 2px 8px;
  border-radius: 7px;
  color: #1b2b3c;
  margin: $margin-value;
  display: inline-block;
  width: auto;
  line-height: 2;
}

引数を複数用意する

引数を複数用意するには引数同士をカンマ(,)でつなげます。

@mixin indication($padding-value: 2px 8px, $margin-value: 0px 12px 16px 0px) {
  padding: $padding-value;
  border-radius: 7px;
  color: #1b2b3c;
  margin: $margin-value;
  display: inline-block;
  width: auto;
  line-height: 2;
}

可変長引数(残余引数)

プロパティには値にカンマを使うものがあります。そうした値を引数として使おうとすると、引数が複数個指定してあるものと認識してしまいエラーとなります。
そのような場合は、引数名の末尾にドットを三つつける(...)と、可変長の引数として宣言でき、エラーを起こさず使用できます。

@mixin window-shadow($shadow-value...) {
  box-shadow: $shadow-value;
}
section {
  @include window-shadow(0px 6px 0px 0px #ececec, 0px 7px 1px 0px #ececec);
}

ミックスインの中に自由な領域を作る コンテントブロック

ミックスインの各呼び出し先で自由に展開できる領域を作ることができるコンテントブロックという機能があります。

説明ではわかりづらいため、下記の例をご覧ください。

$xl: 1200px;
$lg: 992px;
$md: 768px;
$sm: 576px; 

@mixin xl {
  @media (min-width: ($xl)) {
    @content;
  }
}
@mixin lg {
  @media (min-width: ($lg)) {
    @content;
  }
}
@mixin md {
  @media (min-width: ($md)) {
    @content;
  }
}
@mixin sm {
  @media (min-width: ($sm)) {
    @content;
  }
}

.window {
  margin: 16px;
  @include lg {
    margin: 0px;
  }
}

上記のコードは、ブレイクポイントごとの調整を、ミックスインを利用してメンテナンス性を高めたものです。

まず、変数を4つ$xl$lg$md$sm宣言して、メディアクエリ(@media)で使用するレスポンシブのサイズを宣言しています。
そして4つのミックスインを定義して、その内部に先ほど宣言した変数を用いてメディアクエリ@mediaを定義して、4つのブレイクポイントを設定しています。
さらにその中に@contentを記述しています。ここが各呼び出し先で自由に展開できる領域となります。

そして、@include ミックスイン名で呼び出した際に、通常の呼び出し方とは違い@include ミックスイン名のあとに波括弧({})を用いてスタイルを記述しています。このスタイルが@contentを定義した箇所に適用されます。

上の例では.windowはブレイクポイント992px以上だとmargin0pxになり、992px未満だとmargin16pxになるように書いています。
下が変換のCSSです。

.window {
  margin: 16px; 
}
@media (min-width: 992px) {
  .window {
    margin: 0px; 
  } 
}

変数や引数を柔軟に使用する(インターポレーション)

変数や引数は、基本的にプロパティの値として使いますが、値の一部として用いたり、セレクタとして利用したいといったことがあるかと思います。そうした場合はインターポレーションを利用することで変数や引数を様々な箇所に呼び出せるようになります。

インターポレーションは変数や引数を#{$変数名}の形にすることで使用できます。

下記の例ではミックスインの引数をセレクタの一部に用いています。

@mixin window($model) {
  h1 {
    margin: 0px;
  }
  .#{$model}-window-heading {
    margin-bottom: 32px;
  }
  .#{$model}-window-close-button {
    width: 120px;
  }
}

.tag-select-window {
  @include window(tag-select);
}

継承

継承はスタイルの再利用ができるという点ではミックスインと似た機能ですが、他のセレクタを呼び出すこと、引数が使えないこと、またトランスパイル後のセレクタのまとまり方が異なるなど、いくつか違いがあります。

継承は@extend セレクタ名;で、他のセレクタが持っているスタイルを再利用することができます。

.window {
  padding: 16px;
  .heading {
    font-size: 2rem;
  }
}
.box {
  @extend .window;
}

.windowクラスを.boxが継承しています。
このコードをCSSに変換すると下記になります。

.window, .box {
  padding: 16px;
}
.window .heading, .box .heading {
  font-size: 2rem;
}

ミックスインとは違い、各セレクタごとにスタイルが出力されずにグルーピングされています。
しかも、継承元の.windowがネストで指定していた.headingクラスも.boxクラスに継承されています。

継承で利用できないセレクタ

通常の要素セレクタをはじめ.class#id.class1.class2などの連結セレクタなど色々なセレクタを継承に利用することができますが、空白があるセレクタ指定のものは継承に使用することができません。

下記は継承に使用できないセレクタの例です。

.window p {
  // 子孫セレクタ
}
main > article {
  // 子セレクタ
}
p + ol {
  // 隣接セレクタ
}
h2 ~ h3 {
  // 間接セレクタ
}

また、メディアクエリのブロック内部から、メディアクエリの外側にあるセレクタを継承することはできません。

継承の雛型

ミックスインの定義のように継承の雛型をあらかじめ作成しておくこともできます。

雛型を作成するには、セレクタ名の先頭にパーセント(%)を付けます。

%window {
  padding: 16px;
}
.box {
  @extend %window;
}

この雛型自体はCSSに変換された際には残りません。ミックスインのように使用することができます。

関数

関数は非常にたくさんの種類が用意されていますが、ここでよく使うものをピックアップします。

lighten

指定した基準色から明るい色を作れます。どれくらい明るくするかは、第2引数にパーセントで指定します。

.alert {
  border-left: 4px solid #ec6f6b;
  background: lighten(#ec6f6b, 20%);
}

darken

指定した基準色から暗い色を作れます。どれくらい暗くするかは、第2引数にパーセントで指定します。

.button {
  background: #4c9aee;
}
.button:hover {
  background: darken(#4c9aee, 20%);
}

mix

二つの色の中間色が作成できます。色を混ぜる割合を第3引数にパーセントで指定します。

.gray {
  background: mix(#000, #fff, 50%);
}

関数を自作することもできる

下記のように自作関数を定義して使うこともできます。

@function 関数名($引数名) {
  @return 戻り値;
}

制御構文

Sassはプログラミング言語のように制御構文を用いてスタイルを指定することができます。いくつかの制御構文を紹介します。

if

@if 条件式 {
  スタイル
}
@else if 条件式 {
  スタイル
}
@else {
  スタイル
}

for

for文にはthroughを用いるものとtoを用いるものがあります。

@for $カウンタ変数名 from 開始の数値 through 終了の数値 {
  スタイル
}

throughを用いた場合は、終了の数値までを含んで繰り返します。

@for $カウンタ変数名 from 開始の数値 to 終了の数値 {
  スタイル
}

toの場合は、終了の数値未満まで繰り返します。

@for $i from 1 to 4 {
  .margin-#{$i * 16} {
    margin-bottom: 16px * $i;
  }
}

上のコードをCSSに変換すると下記になります。

.margin-16 {
  margin-bottom: 16px; 
}
.margin-32 {
  margin-bottom: 32px; 
}
.margin-48 {
  margin-bottom: 48px; 
}

each

eachfor同様繰り返しの制御構文ですが、$変数に配列(リスト)やマップ型変数を格納しておき、それらから要素を順番に取り出して処理するのに向いています。

@each $ブロック内変数名 in $配列名 {
  スタイル
}
// 配列(リスト)
$変数名: 値, 値, 値;

// マップ型変数
$変数名: (
  キー: 値,
  キー: 値,
  キー: 値
)

下記の例では、レイアウトごとの背景色をマップ型変数で管理しており、それらをeach文でまとめてスタイリングしています。

$layout-color: (
  'wrapper': #f6f7f7,
  'header': #fefefe,
  'main': #fefefe,
  'sidebar': #f8fafa,
  'footer': #2f495e,
);
@each $layout, $color in $layout-color {
  .#{$layout} {
    background-color: $color;
  }
}

上記のコードをCSSに変換すると下記になります。

.wrapper {
  background-color: #f6f7f7;
}

.header {
  background-color: #fefefe;
}

.main {
  background-color: #fefefe;
}

.sidebar {
  background-color: #f8fafa;
}

.footer {
  background-color: #2f495e;
}