🐣

Sass の基本を振り返ってみました

2021/04/26に公開1

これまで Sass を使っていたものの、CSS の延長という感覚でした。ここで基本に立ち返り、Sass について文章として残すことにしました。初歩的な内容ですので気軽に読んでいただけると嬉しいです。

Sass とは

CSS を便利にしたメタ言語だそうです。Sass について調べてみるとよく目にすると思いますが、正式には Syntactically Awesome StyleSheet といい、直訳すると構文的に素晴らしいスタイルシートを意味します。まさにスタイルを書くにあたって CSS よりも素晴らしいコーディング体験ができそうですね。

また、Sass の記法には SASS 記法と SCSS 記法がありますが、今は一般的に SCSS 記法がよく使われているとのことです。

Sass の基本機能

Sass の基本機能について調べてみると以下の機能がありました。
ドキュメントはこちら

  • 変数 (Variables)
  • ネスト (Nesting)
  • パーシャル (Partials)
  • モジュール (Modules)
  • ミックスイン (Mixins)
  • 拡張 / 継承 (Extend/Inheritance)
  • 演算子 (Operators)

それでは各機能について簡単に解説していきます。尚、Sass のコード例については SCSS 記法を用いています。もし SASS 記法が気になる方は Sass のドキュメント(こちら)で確認できるので見てみてください。
※ SCSS ファイル及び CSS ファイルを並べて表示している箇所については SCSS ファイルのビルド後の CSS ファイルを想定した表記としています

変数 (Variables)

色やフォント、幅や高さなどの CSS で利用したい値を $ で定義することで変数として利用できる機能です。CSS だと同じ値をまとめて変更することができないのでひとつずつ書き換える必要があったと思いますが、変数化してしまうと一箇所を変更するだけで済みます。

/* SCSS */
$font-stack: Helvetica, sans-serif;
$primary-color: #333;

body {
  font: 100% $font-stack;
  color: $primary-color;
}

/* CSS */
body {
  font: 100% Helvetica, sans-serif;
  color: #333;
}

ネスト (Nesting)

ネストとはセレクタの親子関係を入れ子構造にする機能です。HTML と同じようにセレクタをネストさせることで視覚的にセレクタの階層構造が理解できます。実際に CSS と Sass のコードを比較してみると、Sass の場合は nav の配下に ul li a があるということが視覚的に理解できると思います。

/* SCSS */
nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { 
    display: inline-block; 
  }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}
/* CSS */
nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

nav li {
  display: inline-block;
}

nav a {
  display: block;
  padding: 6px 12px;
  text-decoration: none;
}

パーシャル (Partials)

パーシャルとは Sass のファイルを分割して利用できる機能です。Sass ファイルの先頭に _(アンダースコア) をつけて利用します。例えば _partial.scss となります。このあとの モジュール (Modules) と併用して利用します。

/* SCSS */
@import "base";  // _base.scss を読み込む 

モジュール (Modules)

モジュールとはパーシャルで分割した Sass ファイルの集合体をまとめる機能です。コード例にも書いてある通り、@import を利用することでパーシャルで分割したファイルをインポートすることができます。尚、@import のあとに書くファイル名には拡張子は不要です。

@import@use についての補足:Sass の公式サイトでは @import の代わりに @use を利用することが推奨されています。@import 自体が今後数年の間に完全に削除されるとまで書かれています。ただし、@use は現時点(2021年4月現在)では Dart Sass のみでのサポートとなっていますので、ご自身の環境に合わせて選択してください。

/* SCSS */
// _base.scss
$font-stack: Helvetica, sans-serif;
$primary-color: #333;

body {
  font: 100% $font-stack;
  color: $primary-color;
}
/* SCSS */
// styles.scss
// @import の場合
@import 'base';

.inverse {
  background-color: $primary-color;
  color: white;
}

// @use の場合
@use 'base';

.inverse {
  background-color: base.$primary-color;
  color: white;
}
/* CSS */
body {
  font: 100% Helvetica, sans-serif;
  color: #333;
}

.inverse {
  background-color: #333;
  color: white;
}

ミックスイン (Mixins)

ミックスインは定義した関数を利用できる機能です。コード例を見ていただくとわかりやすいかもしれませんが、@mixin で定義した関数を @include + 関数名(引数) で呼び出すと引数に応じた結果を受け取ることができます。(関数を呼び出すだけの利用でも可能です)

ミックスインを利用することでコードの再利用を可能にし、プログラミング的な書き方を実現します。記述箇所が多くなる場合は特に変更箇所が一箇所で済むので保守性の向上も期待できます。

/* SCSS */
@mixin transform($property) {
  -webkit-transform: $property;
  transform: $property;
}

.box { 
  @include transform(rotate(30deg)); 
}
/* CSS */
.box {
  -webkit-transform: rotate(30deg);
  transform: rotate(30deg);
}

拡張 / 継承 (Extend/Inheritance)

拡張 / 継承 とは @extend を用いてセレクタを共通利用できる機能です。SCSS と CSS のコード例を見ていただくとわかりやすいかもしれません。一度使ったセレクタを何度も使うことができるので記述量を抑えることができます。また、変更箇所も一箇所で済むので保守性の向上も見込めます。

%(プレースホルダセレクタ)@extend で利用したいセレクタの先頭につけることで CSS(コンパイル後)へは出力されないという機能を持ちます。なので、@extend としてのみ利用するセレクタの場合は % で定義すると良いかもしれません。

/* SCSS */
%box-base {
  width: 200px;
  height: 100px;
  border: 4px solid gray;
}

.box1 {
  @extend %box-base;
}

.box2 {
  @extend %box-base;
  background-color: yellow;
}

.box3 {
  @extend .box2;
  color: red;
}
/* CSS */
.box1, .box2, .box3 {
  width: 200px;
  height: 100px;
  border: 4px solid gray;
}

.box2, .box3 {
  background-color: yellow;
}

.box3 {
  color: red;
}

演算子 (Operators)

演算子はその名の通り演算子を利用できる機能です。CSS で演算子を利用しようとすると calc() で実現することもできますが、Sass だとコード例のように記述を行うことができます。用意されている演算子は +(加算)-(減算)*(乗算)/(除算)%(余り) です。
尚、異なる単位同士での計算だとエラーが出る場合があったり、 /(除算) は括弧が必要なケースがあったりするのでご注意ください。

/(除算) の補足: $box-width / 2 のように変数に対しての計算では括弧は不要ですが、100px / 2 のように変数ではない場合は計算されません。この場合は (100px / 2) とする必要があります。

/* SCSS */
$box-width: 100px;
$box-height: 100px;

.box-regular {
  width: $box-width;
  height: $box-height;
  background-color: green;
}

.box-small {
  width: $box-width / 2;
  height: $box-height / 2;
  background-color: blue;
}

.box-large {
  width: $box-width * 2;
  height: $box-height * 2;
  background-color: red;
}

.box-tall {
  width: $box-width - 50px;
  height: $box-height + 200px;
  background-color: yellow;
}
/* CSS */
.box-regular {
  width: 100px;
  height: 100px;
  background-color: green;
}

.box-small {
  width: 50px;
  height: 50px;
  background-color: blue;
}

.box-large {
  width: 200px;
  height: 200px;
  background-color: red;
}

.box-tall {
  width: 50px;
  height: 300px;
  background-color: yellow;
}

最後に

Sass についての記事を書いてみたことで、これまでは Sass を使っているつもりだったことがわかりました。また、今回取り上げた機能は基本的な機能でしたので、もっと Sass が知りたくなった方は Sass のドキュメント(こちら)を見てみてください。日本語のネット記事も豊富にあるのでそちらを読んでみても良いかも知れないですね。

参考資料

Discussion

nap5nap5

@function等も交えて簡単にデモを作ってみました。

demo code.
https://codesandbox.io/p/sandbox/dazzling-sid-8setpx?file=%2Fsrc%2Findex.scss

@use "sass:math";
@use "sass:list";
@use "sass:map";

@function scaler($domain, $range, $input) {
  $m: math.div(
    nth($range, 2) - nth($range, 1),
    nth($domain, 2) - nth($domain, 1)
  );
  @return nth($range, 1) + $m * ($input - nth($domain, 1));
}

// Input
$lists: (
  (
    "x": 1,
    "y": 1,
  ),
  (
    "x": 2,
    "y": 4,
  ),
  (
    "x": 3,
    "y": 9,
  )
);
$results: () !default;
@each $item in $lists {
  $map: (
    "x": scaler((0, 20), (0, 120), map-get($item, "x")),
    "y": scaler((0, 20), (0, 120), map-get($item, "y")),
  );
  $results: list.append($results, $map);
}

// Output
@debug $results; // ("x": 6, "y": 6) ("x": 12, "y": 24) ("x": 18, "y": 54)

簡単ですが、以上です。