Dart Sass (scss) の基本的な使い方

Sass の公式サイトの Dart Sass のドキュメントを元に作成した基本的な使い方に関する覚書です。

公式に推奨されている実装環境が Dart Sass になって、@import や除算演算子としてのスラッシュの使用が非推奨(将来的には廃止)になり、@use や @forward が導入され、Sass 関数からビルトインモジュールへ移行されるなどの変更(Breaking Changes)があったため内容を書き換えました。

2021年12月21日

作成日:2016年5月21日

Dart Sass (scss) の基本的な使い方

Sass は Syntactically Awesome Style Sheets (構文的に素晴らしいスタイルシート) の略で、CSS を便利に使えるように拡張した言語です。

SASS Official Site

Sass には SCSS 構文とインデント構文(Sass 構文)の二つの記述方法があります。SCSS 構文の方が CSS と似ているため人気があります。

構文 拡張子 説明
SCSS .scss CSS によく似た構文で、いくつかの例外を除いて CSS のスーパーセット(上位互換)です。拡張子が .scss のファイルに記述します。有効な CSS は有効な SCSS でもあります。
Sass .sass インデント構文。Sass のオリジナルの構文で、中括弧やセミコロンの代わりにインデントを使用します。拡張子が .sass のファイルに記述します。

以下の内容は SCSS 構文(拡張子が .scss のファイルに記述する Sass)についてになります。

SCSS を CSS ファイルに記述することができませんが、通常の CSS を SCSS のファイルに記述することは問題ありません(有効な CSS は有効な SCSS でもあります)。

CSS ファイルの拡張子を「.css」から「.scss」に変更して SCSS ファイルにすることができます。

Sass の導入

Sass は実装により以下の3つに分類されますが、現在公式に推奨されている実装環境は Dart Sass です。

Dart Sass Sass の主要な実装で現在の公式推奨環境(Dart 言語で書かれた実行環境)。
LibSass C++ ベースの実行環境(2020年10月に非推奨 メンテナンスリリースなどは続いている)
Ruby Sass Sass の最初の実装。2019年3月26日にサポート終了。

Sass のインストールや設定方法は環境や使用しているエディタにより異なります。

例えば、Dreamweaver CC の場合は「CSSプリプロセッサー機能」が予め組み込まれているのでインストールは不要ですし、他のエディタでもプラグインが用意されているものもあるのでそれらを利用できます(但し、Dart Sass がサポートされているかどうかはそれぞれで確認が必要です)。

環境に合わせてインストールや設定方法を検索してみてください。

関連ページ

文字コード

Dart Sass は UTF-8 エンコーディングのみをサポートしているので、全ての Sass ファイルのエンコーディングを UTF-8 とするのが安全です。

ファイルのエンコーディングの設定はエディタにより異なりますが、例えば Dreamweaver の場合は、「環境設定」→「新規ドキュメント」→「エンコーディング初期設定」やファイルごとに指定するのであれば「ファイル」→「ページプロパティ」→「タイトル/エンコーディング」で設定できます。

@charset "UTF-8"; の記述はしてもしなくてもあまり変わらないようです。コンパイルされ出力される CSS にマルチバイト文字(日本語)が含まれている場合は、コンパイル時に自動的に @charset "UTF-8"; が出力されます(アウトプットスタイルを compressed に指定した場合は出力されません)。

例えば、以下のような日本語が含まれる SCSS ファイルの場合

sass/style.scss
h1 {
  font-family: "メイリオ" ;
}

コンパイルする際にアウトプットスタイルを指定しない(または expanded を指定する)と、@charset "UTF-8"; が出力されますが、compressed を指定すると出力されません。

以下は出力先を省略しているのでコンパイルされた CSS はターミナルに出力されます。

$ sass sass/style.scss  return
@charset "UTF-8";
h1 {
  font-family: "メイリオ";
}

//compressed を指定
$ sass --style=compressed sass/style.scss  return
h1{font-family:"メイリオ"}

コメント

SASS では通常の CSS のコメント /* ..... */ 以外に、JavaScript などで使用する // ..... のような1行コメント(Single-line comments)も使用できます。

.sample {
  /* 通常のコメント */
  //1行コメント (コンパイル時に削除される)
  width: 300px;
}

但し、1行コメントはコンパイルされる際に削除され、CSS には出力されません。

通常の CSS のコメント /* ..... */ はデフォルトではコンパイル時に削除されませんが、アウトプットスタイルに compressed を指定すると削除されます。

--style=compressed の場合でもコメントが消えないようにするには /*! */ で囲むようにします。

.sample {
  /*! compressed の場合でも削除されないコメント */
  width: 300px;
}

Sass: Comments

ネスト

SASS では CSS をHTML 構造のようにネストして(入れ子で)記述することができます。

例えば、以下のような HTML の場合

<div class="sample">
  <h3>Title</h3>
  <div class="content">
    <p>paragraph</p>
    <p>paragraph</p>
  </div>
</div>  

SASS では以下のように入れ子にしてスタイルを記述することが可能です(通常の CSS では空白で連結する子孫セレクタで個々に記述する必要があります)。

Sass (.scss)
.sample {
  border: 1px solid #999;
  background-color: #EEE;
  h3 {
    margin: 20px;
    font-size: 24px;
  }
  .content p {
    color: green;
  }
}

Sassは 外側のルールのセレクターと内側のルールのセレクターを空白で連結する子孫セレクタで自動的に結合し、コンパイル後の CSS は以下のようになります。

もしクラス名が変わった場合、SASS なら1箇所(上記1行目の .sample)を修正するだけで済みます。

コンパイルして出力される CSS
.sample {
  border: 1px solid #999;
  background-color: #EEE;
}
.sample h3 {
  margin: 20px;
  font-size: 24px;
}
.sample .content p {
  color: green;
}

セレクターリスト

カンマ区切りの複数のセレクター(セレクターリスト)をネストすると、個別にネストされてからそれらが結合されてセレクターリストに戻されます。

Sass (.scss)
.alert, .warning {
  ul, p {
    margin-right: 0;
    margin-left: 0;
    padding-bottom: 0;
  }
}
コンパイルして出力される CSS
.alert ul, .alert p, .warning ul, .warning p {
  margin-right: 0;
  margin-left: 0;
  padding-bottom: 0;
}

セレクターコンビネータ

子セレクタ(>)や隣接兄弟セレクタ(+)、間接セレクタ(~)などのコンビネータを使用するセレクタをネストすることもできます。

コンビネータは外側のセレクターの後や内側のセレクターの前、または2つの間に単独で配置できます。

Sass (.scss)
ul > {  /*外側のセレクターの後*/
  li {
    list-style-type: none;
  }
}

h2 {
  + p {  /*内側のセレクターの前*/
    border-top: 1px solid gray;
  }
}

p {
  ~ {  /*2つの間に単独で*/
    span {
      opacity: 0.8;
    }
  }
}
コンパイルして出力される CSS
ul > li {
  list-style-type: none;
}

h2 + p {
  border-top: 1px solid gray;
}

p ~ span {
  opacity: 0.8;
}

Sass: Style Rules/Nesting

プロパティのネスト

多くの CSS プロパティは(一種の名前空間として機能する)同じプレフィックスで始まります。 例えば、font-family、font-size、font-weight はすべて font- で始まります。

Sassは 同じプレフィックスで始まるこれらのプロパティ宣言をネストすることができます。ネストしたプロパティ名はハイフンで区切られて追加されます。

Sass (.scss)
.foo {
  font: {
    family: Arial, Helvetica, "sans-serif";
    size: 16px;
    style: italic;
    weight: bold;
  }
}
コンパイルして出力される CSS
.foo {
  font-family: Arial, Helvetica, "sans-serif";
  font-size: 16px;
  font-style: italic;
  font-weight: bold;
}

以下は transition のプロパティをネストする例です。 9行目の & は親セレクタの参照で、この場合 .enlarge を表します。

Sass (.scss)
.enlarge {
  font-size: 14px;
  transition: {
    property: font-size;
    duration: 4s;
    delay: 2s;
  }

  &:hover { font-size: 36px; }
}

ネストしたプロパティ名(property、duration、delay)はハイフンで区切られて追加されます。

コンパイルして出力される CSS
.enlarge {
  font-size: 14px;
  transition-property: font-size;
  transition-duration: 4s;
  transition-delay: 2s;
}
.enlarge:hover {
  font-size: 36px;
}

ショートハンドで記述できるプロパティ(ハイフンがあるプロパティ)でもネストを使うことが可能です。

Sass (.scss)
.foo {
  border: {
    top: 1px solid #999;
    bottom: 2px dotted #666;
  }
}
コンパイルして出力される CSS
.foo {
  border-top: 1px solid #999;
  border-bottom: 2px dotted #666;
}

また、下記のようにショートハンドで一度スタイルを指定してから、プロパティのネストで上書きすることも可能です。

Sass (.scss)
.info-page {
  margin: auto {
    bottom: 10px;
    top: 2px;
  }
}
コンパイルして出力される CSS
.info-page {
  margin: auto;
  margin-bottom: 10px;
  margin-top: 2px;
}

Sass: Property Declarations/Nesting

@media のネスト

メディアクエリもネストして使うことができます。

Sass (.scss)
.sidebar {
  width: 300px;
  @media screen and (orientation: landscape) {
    width: 500px;
  }
}
コンパイルして出力される CSS
.sidebar {
  width: 300px;
}
@media screen and (orientation: landscape) {
  .sidebar {
    width: 500px;
  }
}

親セレクタの参照 (&)

セレクタに「&」を使うとネストしている親セレクタを参照することができます。

Sass (.scss)
a {
  font-weight: bold;
  text-decoration: none;
  &:hover { text-decoration: underline; }
  .foo & { font-weight: normal; }
}

この場合 & は a を参照します。

コンパイルして出力される CSS
a {
  font-weight: bold;
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}
.foo a {
  font-weight: normal;
}

以下のようにネストが深くなっても、親セレクタを参照できます。

#main {
  color: black;
  a {
    font-weight: bold;
    &:hover { color: red; } //& は a を参照
  }
}
コンパイルして出力される CSS
#main {
  color: black;
}
#main a {
  font-weight: bold;
}
#main a:hover {
  color: red;
}

親セレクターを使用して、外側のセレクターにサフィックスを追加することもできます。

Sass (.scss)
.accordion {
  max-width: 600px;
  margin: 4rem auto;
  width: 90%;

  &__copy {
    display: none;
    padding: 1rem 1.5rem 2rem 1.5rem;

    &--open {
      display: block;
    }
  }
}
コンパイルして出力される CSS
.accordion {
  max-width: 600px;
  margin: 4rem auto;
  width: 90%;
}
.accordion__copy {
  display: none;
  padding: 1rem 1.5rem 2rem 1.5rem;
}
.accordion__copy--open {
  display: block;
}

& を組み合わせて以下のような使い方もできます。

Sass (.scss)
.foo {
  & & {
    margin-top: 1rem;
  }
  & + & {
    margin-top: 2rem;
  }
  &,
  &--wide {
    margin-top: 3rem;
  }
}

.bar, .baz {
  & & {
    padding-bottom: 0;
    padding-left: 0;
  }
}
コンパイルして出力される CSS
.foo .foo {
  margin-top: 1rem;
}
.foo + .foo {
  margin-top: 2rem;
}
.foo, .foo--wide {
  margin-top: 3rem;
}

.bar .bar, .bar .baz, .baz .bar, .baz .baz {
  padding-bottom: 0;
  padding-left: 0;
}

Sass: Parent Selector

Partials(部分ファイル)

Sass では部分的な Sass ファイルを作成して他の Sass ファイルに含めることができます。

言い換えると、全ての Sass を1つのファイルに記述する必要はなく、必要に応じて分割した Sass ファイルをモジュールとしてロードすることができ、コンパイルする際に CSS ファイルをまとめることができます。

分割した部分的な Sass ファイルを読み込む(ロードする)には @use を使用します。

通常、分割してロードした Sass ファイルをコンパイルすると、その Sass ファイルの CSS の他に、ロードした部分的な Sass ファイルも別の CSS ファイルとして生成されます。

Sass ではファイル名の先頭にアンダースコアを付けると、そのファイルが部分的なファイルにすぎないことを意味し、コンパイルしても CSS ファイルが生成されないようになっています。この仕組を利用して分割した Sass ファイルを最終的に1つの CSS ファイルにまとめることができます。

このファイル名の先頭にアンダースコアのついた部分的な Sass ファイルをパーシャル(partial = 部分的)と呼びます。

アンダースコアと拡張子の省略

パーシャルを読み込む際には、ファイル名の先頭のアンダーバーと拡張子を省略することができます。

以下は style.scss で2つのパーシャル(_variables.scss と _base.scss)を読み込んでコンパイルする例です。以下の場合、_base.scss では _variables.scss を読み込んでもいます。

.
├── css
│   └── style.css
└── sass
    ├── _base.scss
    ├── _variables.scss
    └── style.scss
_variables.scss(部分的な Sass ファイル:パーシャル)
$primary-color: #333;  /*変数の定義*/
_base.scss (部分的な Sass ファイル:パーシャル)
@use "variables";

$font-stack: Helvetica, sans-serif;  /*変数の定義*/

body {
  font-family: $font-stack;
  color: variables.$primary-color;  /*別ファイルのメンバーは namespace.変数名で参照*/
}

別の Sass ファイルを読み込み、ファイル名に基づく名前空間(namespace)を使用して、Sass ファイル内の変数、ミックスイン、および関数を参照できます。詳細は @use を参照。

style.scss
@use 'base';
@use "variables";

.inverse {
  background-color: variables.$primary-color;  /*namespace.変数名で参照*/
  color: white;
}

コンパイルされた出力には生成された CSS も含まれます。

style.css (コンパイルされた出力の CSS)
body {
  font-family: Helvetica, sans-serif;
  color: #333;
}

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

もし、_variables.scss と _base.scss をパーシャルにしない(ファイル名の先頭にアンダーバーを付けない)と、上記の場合、以下のようにそれぞれに対応する CSS ファイルも生成されてしまいます。

.
├── css
│   ├── base.css  //CSS ファイルが生成される
│   ├── variables.css  //CSS ファイルが生成される
│   └── style.css
└── sass
    ├── base.scss //先頭にアンダーバーなし
    ├── variables.scss //先頭にアンダーバーなし
    └── style.scss

Sass: Sass Basics

変数(Variables)

変数(variable)は、データ(値)を一時的に記憶しておくための仕組みで、任意の名前を付けておき、必要に応じてデータ(値)を呼び出すことができます。

Sass の変数は $ から始まる変数名にコロン( : )で区切って値を指定します。

$名前 : 値 ; 

また、変数名には以下のような決まりがあります。

  • 変数名は半角英数字の他にアンダースコア「_」とハイフン「-」を使うことができます()。
  • 数字から始まる変数名はエラーになります。

以下は基本的な使い方です。

Sass (.scss)
$my-width: 5em;  /*変数の宣言( 変数名 : 値 ; )*/

#main {
  width: $my-width;  /*変数の使用*/
}
コンパイルして出力される CSS
#main {
  width: 5em;
}

Sass: Variables

以下の例では変数の定義(宣言)をまとめて先頭で記述していますが、変数の定義はどこでも可能です。また、通常、変数はプロパティの値として使用します。

Sass (.scss)
/*変数を定義(宣言)*/
$base-font: "メイリオ", "Meiryo", verdana, "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", Osaka, "MS Pゴシック", "MS PGothic", Sans-Serif;

$base-body-color: #333;

$link-color: #06f;
$link-color-hover: rgba($link-color, 0.8);

$main-width: 960px;

/*定義した変数をプロパティの値として使用*/
body {
  color: $base-body-color;
  font-family: $base-font;
}
#main {
  width: $main-width;
  a:link {
    color: $link-color;
  }
  a:hover {
    color: $link-color-hover;
  }
}

この例の場合、マルチバイト文字(日本語)が含まれているので、コンパイルする際にアウトプットスタイルを省略または expanded を指定すると、@charset "UTF-8"; が出力されます(compressed を指定すると出力されません)。

コンパイルして出力される CSS
@charset "UTF-8";
body {
  color: #333;
  font-family: "メイリオ", "Meiryo", verdana, "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", Osaka, "MS Pゴシック", "MS PGothic", Sans-Serif;
}

#main {
  width: 960px;
}
#main a:link {
  color: #06f;
}
#main a:hover {
  color: rgba(0, 102, 255, 0.8);
}

CSS カスタムプロパティとの違い

CSS にも CSS 変数(CSS カスタムプロパティ)がありますが、Sass の変数とは異なります。

Sass の変数はコンパイル時に値に変換され(取り除かれ)、CSS には出力されません。

また、Sass の変数の場合、変数を使用してからその値を変更しても、その変更の記述以前で使用している値はそのままですが、CSS 変数は値を変更すると全体に影響します。

Sass (.scss)
$my-color: green;
.foo {
  color: $my-color;
}
$my-color: blue;  /* 値を変更 */
.bar {
  color: $my-color;
}
.baz {
  color: $my-color;
}
コンパイルして出力される CSS
.foo {
  color: green;
}
/* 値を変更 */
.bar {
  color: blue;
}
.baz {
  color: blue;
}

CSS 変数の場合、以下のように値を変更すると、全ての値が blue に変更されます(ブロック内で局所的に変更することはできます)。

CSS 変数(CSS カスタムプロパティ)
/* CSS 変数を:root 擬似クラス(グローバル)に定義 */
:root {
  --my-color: green;
}

.foo {
  color: var(--my-color); /* blue */
}
/* CSS 変数の値を変更(.foo を含む全てが変更される) */
:root {
  --my-color: blue;
}
.bar {
  color: var(--my-color); /* blue */
}
.baz {
  color: var(--my-color); /* blue */
}

アンダースコアとハイフン

Sass の歴史的な経緯から Sass 変数はすべての Sass 識別子と同様、アンダースコア(_)とハイフン(-)を同一として扱います。$font-size と $font_size の両方が同じ変数を参照する($font-size を $font_size で参照できる)ことを意味します。

Sass variables, like all Sass identifiers, treat hyphens and underscores as identical. This means that $font-size and $font_size both refer to the same variable. This is a historical holdover from the very early days of Sass, when it only allowed underscores in identifier names. Once Sass added support for hyphens to match CSS’s syntax, the two were made equivalent to make migration easier.
Sass (.scss)
$main_width: 30px;  /*アンダースコアを使った変数名*/

.foo {
  width: $main-width;  /*ハイフンを使った変数名で参照できる*/
}
コンパイルして出力される CSS
.foo {
  width: 30px;
}

変数を使用できる場所

基本的に変数はプロパティの値として使用(参照)しますが、セレクタ名や画像のパスの一部として使用する場合や、CSS カスタムプロパティの値として変数を使う場合は、インターポレーション(補完)を使います。

!defaut デフォルト値の設定

!default フラグは、変数にまだ値が設定されていないか値が null の場合にのみ値を設定するフラグです。

通常、変数の値は後から宣言された変数の値で上書きされますが、!defaut フラグを使用すると、同じ変数が先に宣言されていた場合にはそちらが優先(適用)されます。

もし変数に既に値が設定されている場合はその値が使用され、まだ値が設定されていない場合は !default フラグで指定された値が設定されます。

Sass (.scss)
$font-color: blue;
$font-color: green !default;

.foo {
  color:$font-color;
}

上記の場合、2行目の変数の宣言には !default フラグが指定されているので、コンパイルされる際に先に宣言されている値(blue)が適用されます。

コンパイルして出力される CSS
.foo {
  color: blue;
}

!default フラグは、一般的にはライブラリなどで使われる仕組みです。

ライブラリ側で変数に !default が指定されていれば、利用する側でライブラリを読み込む前にその変数に独自の値を設定することでスタイルを変更することができます。

例えば、Bootstrap のスタイルをカスタマイズする場合、変更したい変数に値を設定して、その後で Bootstrap を読み込みます。

ライブラリ側で変数に !default が指定されていれば、利用する側でライブラリを読み込む前にその変数に独自の値を設定することでスタイルを変更することができます。

以下は Bootstrap をカスタマイズする例ですが、これらの変数は Bootstrap 側で !default フラグが指定されています。変数の記述は、Bootstrap の @import よりも前に記述する必要があります。

custom.scss
// body の背景色と文字色を上書き
$body-bg: #fefefe;
$body-color: #777;

//フォントを変更
$font-family-base: "ヒラギノ角ゴ ProN W3", "Hiragino Kaku Gothic ProN", Meiryo, メイリオ, Verdana, Arial, sans-serif;

//角丸設定を上書き
$enable-rounded: false;

//$theme-colors の $light を上書き
$light: #ccc;

/* Bootstrap の読み込み(@import は非推奨ですが、この場合は使っています) */
@import "~bootstrap/scss/bootstrap.scss";

@use を使ってモジュールを読み込んで変数を変更(設定)する場合は、with を使います。

@use 'モジュールの URL' with (
  変数: 値,
  変数: 値,
  ・・・
);

トップレベルで !default フラグを指定している変数のみを変更できます。

_library.scss
$border-radius: 0.25rem !default;
$padding: 1rem !default;

.code {
  border-radius: $border-radius;
  padding: $padding;
}
style.scss
@use 'library' with (
  $border-radius: 10px,
  $padding: 10px
);
コンパイルして出力される CSS
.code {
  border-radius: 10px;
  padding: 10px;
}

参考:Sassの!defaultフラグの使い方と使われ方

Sass: Default Values

CSS カスタムプロパティ

現在の Sass は CSS カスタムプロパティ(CSS 変数)の宣言を他のプロパティ宣言とは異なる方法で解析し、CSS カスタムプロパティの値はそのまま CSS に渡されます。

動的な値(Sass 変数)を CSS カスタムプロパティに挿入するにはインターポレーションを使う必要があります。

以下の場合、 --accent-color-wrong の値は文字列 $accent-color として CSS に渡されます。

Sass (.scss)
$accent-color: #fbbc04;

:root {
  // 現在の Sass のバージョンでは機能しない
  --accent-color-wrong: $accent-color;

  // 全ての Sass のバージョンで正しく機能する
  --accent-color-right: #{$accent-color};
}
コンパイルして出力される CSS
:root {
  --accent-color-wrong: $accent-color; /* そのまま渡されている */
  --accent-color-right: #fbbc04;
}

変数の有効範囲(スコープ)

  • 変数には有効範囲(スコープ)があり、トップレベルの位置で書いた変数はどこでも有効ですが、波括弧の中(ルールセット内)で変数を定義すると、その括弧の中のみが有効範囲になります。(例外として !global フラグの使用があります)
  • 波括弧の中(ルールセット内)の変数は波括弧の外からはアクセスできませんが、ネストでどれだけ入れ子が深くなっても利用することができます。
  • トップレベルで定義されたものをグローバル変数、波括弧の中(ルールセット内)で定義されたものをローカル変数と呼ぶこともあります。

以下の場合、トップレベルで定義した $padding はどこからでもアクセス(参照)できますが、.foo のルールセット内で定義した $value は .foo のルールセット内でのみアクセス可能です。

Sass (.scss)
$padding: 10px;  /*トップレベルで定義*/

.foo {
  $value : 30px; /*ルールセット内で定義*/
  margin: $value;  /*参照可能*/
  p {
    padding: $padding; /*参照可能 */
    margin: $value;  /*参照可能*/
  }
}

.bar {
  margin: $value;  /*参照不可(エラー)*/
}

Sass: Scope

Shadowing

ローカル変数をグローバル変数と同じ名前で宣言することもできます。

この場合、1つはローカルで、もう1つはグローバルの同じ名前の2つの異なる変数となります。これにより、グローバル変数の値を誤って変更(上書き)しないようにすることができます。

Sass (.scss)
$var: gold; /*グローバル*/

.content {
  $var: silver;  /*ローカル*/
  color: $var;  /*ローカルを参照(silver)*/
}

.sidebar {
   color: $var;  /*グローバルを参照(gold)*/
}
コンパイルして出力される CSS
.content {
  color: silver;
}

.sidebar {
  color: gold;
}

Sass: Shadowing

!global フラグ

波括弧の中(ルールセット内)で変数を定義すると、その括弧の中のみが有効範囲になりますが、「!global」フラグを付けると、その変数はどこからでも参照可能(グローバル)になります。

Sass (.scss)
$var: gold;  /*グローバル*/

.content {
  $var: silver !global;  /*ローカルで !global フラグを指定*/
  color: $var;
}

.sidebar {
   color: $var;
}
.content {
  color: silver;
}

.sidebar {
  color: silver; /*!global フラグを指定した変数を参照*/
}

!global で新しい変数を宣言(非推奨→エラー)

Dart Sass 2.0.0 以降では!global フラグはファイルのトップレベルですでに宣言されている変数を設定するためにのみ使用できます。新しい変数を宣言するために使用することはできません。

Older Sass versions allowed !global to be used for a variable that doesn’t exist yet. This behavior was deprecated to make sure each stylesheet declares the same variables no matter how it’s executed.(Compatibility: Dart Sass since 2.0.0)

現時点(Dart Sass 1.43.5)では、トップレベルで宣言されていない変数をローカルで新たに宣言するとコンパイル時に警告が表示されます。

sass/style.scss
.content {
  /*新たな変数をローカルで !global フラグを指定して宣言(非推奨)*/
  $var: silver !global;
  color: $var;
}

.sidebar {
   color: $var;
}
出力先を指定せず標準出力にコンパイル
$ sass sass/style.scss  return
Deprecation Warning: As of Dart Sass 2.0.0, !global assignments won't be able to declare new variables.

Recommendation: add `$var: null` at the stylesheet root.

  ╷
4 │   $var: silver !global;  //ローカルで !global フラグを指定
  │   ^^^^^^^^^^^^^^^^^^^^
  ╵
    sass/style2.scss 4:3  root stylesheet

.content {
  color: silver;
}

.sidebar {
  color: silver;
}

インターポレーション

インターポレーションは Sass の式(SassScript expression)の結果を CSS に埋め込む(挿入する)ための構文で、シャープ記号を前に置いた波括弧 #{ } で式を囲んで使います。

通常、変数に入った値はプロパティの値にしか使用できませんが、インターポレーションを使えばセレクタやプロパティ名などにも変数を展開することができます。

Sass: Interpolation

セレクタ

以下のようにセレクタに変数を記述するとエラーになってしまいます。

Sass (.scss)
$className: alert;

p.$className {  /*エラーになる*/
  color: red;
}

#{ } を使って以下のように記述すれば、問題なくコンパイルされます。

Sass (.scss)
$className: alert;

p.#{$className} {
  color: red;
}
コンパイルして出力される CSS
p.alert {
  color: red;
}

プロパティ名

以下はプロパティ名に変数を展開しようというつもりですが、$prop というローカル変数の定義として認識されされ、コンパイル後の CSS には何も出力されません。

Sass (.scss)
$prop: color;

p {
  $prop: red; /*ローカル変数の定義として認識される*/
}

この場合も #{ } を使って以下のように記述すれば、意図した結果になります。

Sass (.scss)
$prop: color;

p {
  #{$prop}: red; /*ローカル変数の定義として認識される*/
}
コンパイルして出力される CSS
p {
  color: red;
}

以下の例ではプロパティ名の一部に変数を使おうとしているつもりですが、$attr-color というローカル変数の定義として認識され、前述同様、コンパイル後の CSS には何も出力されません。

Sass (.scss)
$attr: border;

p {
  $attr-color: red; /*ローカル変数の定義として認識される*/
}

この場合も #{ } を使って以下のように記述すれば、意図した結果になります。

Sass (.scss)
$attr: border;

p {
  #{$attr}-color: red;
}
コンパイルして出力される CSS
p {
  border-color: red;
}

url()

CSS の url() 関数は他の関数とは異なり、引数に引用符で囲まれた URL または引用符で囲まれていない URL のいずれかを取ることができます。そのため、変数を挿入するにはインターポレーションを使います。

Sass (.scss)
$img_path: "../common/images/foo/";

.icon {
  /*引用符で囲まれた URL*/
  background: url("#{$img_path}icon.gif") no-repeat;
}

.icon {
  /*引用符で囲まれていない URL*/
  background: url(#{$img_path}icon.gif) no-repeat;
}

以下は文字列を連結する演算子(+)を使用する場合の例です。10行目の場合、連結する文字列が引用符で囲まれていないのでエラーになります。

Sass (.scss)
$img_path: "../common/images/foo/";

.icon {
  /*引用符で囲まれた URL(文字列を連結する演算子を使用)*/
  background: url($img_path + "icon.gif") no-repeat;
}

.icon {
  /*エラーになる(icon.gif が引用符で囲まれていない)*/
  background: url($img_path + icon.gif) no-repeat;
}

Sass: Special Functions/url()

演算しないようにする

スラッシュなどを使う際に意図しない計算が行われないようにするため、インターポレーションを使用して値をそのまま出力することができます。

以下は演算(除算)しないようにする例です。

Sass (.scss)
p.foo {
  $font-size: 16px;
  $line-height: 24px;
  font: $font-size/$line-height monospace;  /*演算されてしまう*/
}

p.bar {
  $font-size: 16px;
  $line-height: 24px;
  font: #{$font-size}/#{$line-height} monospace;  /*演算されない*/
}
コンパイルして出力される CSS
p.foo {
  font: 0.6666666667 monospace;
}

p.bar {
  font: 16px/24px monospace;
}

スラッシュを除算に使うのは非推奨

現時点でのバージョン(1.43.5)で上記の Sass をコンパイルすると以下のような警告が表示されます。

Dart Sass では除算にラッシュ使うのは非推奨で、2.0 からはこの機能は削除されるようです。※ calc() 内でのスラッシュによる除算は問題なく使えます。

Deprecation Warning: Using / for division is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($font-size, $line-height)

More info and automated migrator: https://sass-lang.com/d/slash-div

  ╷
4 │   font: $font-size/$line-height;
  │         ^^^^^^^^^^^^^^^^^^^^^^^
  ╵

Sass: Breaking Change: Slash as Division

スラッシュが除算に使用できなくなるまでの一時的な解決策として list.slash() を使って、スラッシュ / を区切り文字として使用するように強制することができます。

Sass (.scss)
@use "sass:list";

.foo {
  $font-size: 16px;
  $line-height: 24px;
  font: list.slash($font-size, $line-height) monospace;
}
コンパイルして出力される CSS
.foo {
  font: 16px / 24px monospace;
}

Sass: Division

演算できない場所で演算する

以下は演算できない場所で演算する例です。セレクタやプロパティ名に変数を使って演算をする場合に利用できます。

Sass (.scss)
@for $i from 0 to 3 {
  .marginTop#{$i * 10} {
    margin-top: 10px * $i;
  }
}
コンパイルして出力される CSS
.marginTop0 {
  margin-top: 0px;
}

.marginTop10 {
  margin-top: 10px;
}

.marginTop20 {
  margin-top: 20px;
}

数値

インターポレーションは(それ以上の計算に使用できない)引用符で囲まれていない文字列を返すため、ほとんどの場合、数値を扱うのに適していません

また、例えば、#{$width}px と書く代わりに、単位演算を使って $width * 1px と書いたほうが、もし $width に単位の文字が入っている場合にコンパイル時にエラーを検出できるので安全です。

Sass (.scss)
@mixin double-width($width) {
  width: ($width * 2) * 1px;
}

.foo {
  @include double-width(100);
}
コンパイルして出力される CSS
.foo {
  width: 200px;
}

もし誤って @include double-width(100px) と記述すると、コンパイル時に以下のようなエラーが表示されますが、($width * 2) * 1px を #{$width * 2}px としてしまうとエラーは発生せず、width: 200pxpx となってしまいます。

Sass (.scss)
Error: 200px*px isn't a valid CSS value.
  ╷
4 │   width: ($width * 2) * 1px;
  │          ^^^^^^^^^^^^^^^^^^
  ╵

引用符は取り除かれる

インターポレーションは引用符で囲まれた文字列から引用符を取り除きます。

Sass (.scss)
$className: "foo";

p.#{$className} {
  color: gold;
}

.#{'bar'} {
  color: silver;
}
コンパイルして出力される CSS
p.foo {
  color: gold;
}

.bar {
  color: silver;
}

この機能を使用して引用符で囲まれた文字列を引用符で囲まれていない文字列に変換できますが、単に引用符を取り除くだけなら #{$string} の代わりに string.unquote($string) とした方が明確になります。

引用符を保持

インターポレーションにより引用符で囲まれた文字列から引用符が削除されるため、以下のような場合、引用符を保持するには、meta.inspect() 関数でラップします。

Sass (.scss)
@use "sass:meta";

$font-family-monospace: Menlo, Consolas, "Courier New", monospace;

.foo{
  font-family: #{$font-family-monospace}; /*引用符は取り除かれる*/
  font-family: #{meta.inspect($font-family-monospace)}; /*引用符を保持*/
}
コンパイルして出力される CSS
.foo {
  font-family: Menlo, Consolas, Courier New, monospace;
  font-family: Menlo, Consolas, "Courier New", monospace;
}

Sass の値の型(value types)

Sass には以下のような値の型(value types)があります。

type 説明
Numbers 数値。12 や 100px などの単位がある場合とない場合があります。Sass の数値には、数値自体とその単位の2つの要素があります。
Strings 文字列。引用符(ダブルクォーテーションやシングルクォーテーション)が含まれる場合と含まれない場合があります。
Colors 色の値。16進コード(例 #f2ece4)やカラーネーム(transparent や red など)、またはカラー関数 rgb()、rgba()、hsl() 、hsla() として記述できます。
List of values 値のリスト。カンマやスペースで区切った値(角カッコ [ ] で囲むことも可能)。foo, bar, baz や foo bar baz、[foo bar baz] など
boolean 真偽値。値は true と false の2種類。※ Sass では false と null のみが falsey とみなされ(条件式で false と判定され)、それ以外の空文字列や空のリスト、数値のゼロ(0)は truthy とみなされます。
null null 型の値は null のみ。null は値がないことを表し、結果がないことを示すために関数によって返されることもあります。Sass は値が null の場合、プロパティを書き出さないようになっています。また、null も false であり、真偽値をとるすべてのルールや演算子に対して false として扱われます。
Map 値をキーに関連付けるマップ(キーと値のペアが集まったもの)。例 ("background": red, "foreground": pink)

値の型(value types)の確認

sass:meta ビルトインモジュールの type-of() 関数で値の型を確認することができます。

@debug を使うとコンパイルする際に値をターミナル(コマンドライン)に出力します。

Sass (.scss)
@use "sass:meta";  //meta モジュールの読み込み

@debug meta.type-of(100px);  //number
@debug meta.type-of('true');  //string(引用符で囲まれているので文字列)
@debug meta.type-of(#fff);  //color
@debug meta.type-of([foo, bar, baz]);  //list
@debug meta.type-of(true);  //bool
@debug meta.type-of(null);  //null
@debug meta.type-of((foo:100, bar:200, baz:300));  //map

Lists リスト

リストは複数のデータ(値)をカンマやスペース、スラッシュ(※)で区切ったものです。他の言語とは異なり、Sass のリストには括弧は必要ありません(角括弧を使用してリストを作成することもできます)。

スペースまたはカンマで区切られた式はすべてリストとしてカウントされます。

以下はいずれも同じ値を持つリストです。

Sass (.scss)
//リストの定義
$classList: top, about, contact;
$classList: top about contact;
$classList: (top) (about) (contact);
$classList: (top, about, contact);
$classList: [top, about, contact];

※ スラッシュ区切りのリスト

現時点(v1.43.5 )では、スラッシュで区切られたリストを直接記述することはできません。現時点でスラッシュ区切りのリストを記述するには list.slash() を使用する必要があります。

Sass (.scss)
@use "sass:list";  // list モジュールの読み込み

$classList:list.slash(top, about, contact);

@debug $classList;
//Debug: top / about / contact (コンパイル時のコンソールへの出力)

空のリスト

空(要素数が0)のリストは () または [] のいずれかで記述できます。

リストの関数

Sass ではリストを使用するための関数が用意されています。また、関数ではありませんが、@each を使ってリストの全ての要素に対して繰り返し処理を行うことができます。

インデックス(Index)

リストの関数の多くは、リスト内の要素を参照するインデックスと呼ばれる数値を取得または返します。

リストの最初の要素のインデックスは 1 になります(インデックスが 0 から始まる多くのプログラミング言語とは異なります)。

インデックス -1 はリストの最後の要素を示し、-2 は最後から2番目の要素を示します。

要素の取得

list.nth($list, $n) 関数を使用して、リスト内の特定のインデックスにある要素を取得できます。 最初の引数($list)はリスト自体、2番目の引数($n)は取得する値のインデックスです。

Sass (.scss)
@use "sass:list";  //list モジュールの読み込み

@debug list.nth(10px 12px 16px, 2);
//Debug: 12px(コンパイル時のコンソールへの出力)
@debug list.nth([line1, line2, line3], -1);
//Debug: line3(コンパイル時のコンソールへの出力)

Sass: Lists

Maps マップ

マップは任意の名前(キー)と値のペアが集まったものです。リストは値の集合ですが、マップはの各要素をコロン(:)区切りで名前(キー)と値のペアで記述したものです。

リストとは異なり、括弧は省略できず、区切りもカンマに限られます。

マップの値は、データ型を問わずどのようなデータ型でも記述することができ、マップやリストを指定してネストすることも可能です。但し、値は重複しても構いませんが、キーは一意である必要があります。

以下は、クラスごとの背景色のマップ(キーがクラス名で値が背景色)の例です。

Sass (.scss)
$class_bg: (
  home: #E8E4E4,
  about: #EFF6FB,
  contact: #E4F8EF,
  news: #F8FBE3
);

@each を使うと簡単に各クラスの背景色を書き出すことができます。

Sass (.scss)
$class_bg: (
  home: #E8E4E4,
  about: #EFF6FB,
  contact: #E4F8EF,
  news: #F8FBE3
);

@each $class, $bg in $class_bg {
  .#{$class} {
    background-color: $bg;
  }
}
コンパイルして出力される CSS
.home {
  background-color: #E8E4E4;
}
.about {
  background-color: #EFF6FB;
}
.contact {
  background-color: #E4F8EF;
}
.news {
  background-color: #F8FBE3;
}

空のマップ

空のマップは () と記述します(括弧を使った空のリストと同じ)。Sass ではマップはリストの特殊なバージョンのようなものです。

キーは引用符で囲む

マップのキーは引用符で囲むことが推奨されています(問題が起こりにくくなります)。

マップの関数

Sass ではマップを利用するための関数が用意されています。また、関数ではありませんが、リスト同様、@each を使ってマップの全ての要素に対して繰り返し処理を行うことができます。

キーから値を取得

キーに関連付けられた値を取得するには map.get($map, $key) 関数を使います。この関数は指定されたキーに関連付けられたマップの値を返し、マップにキーが含まれていない場合は null を返します。

最初の引数($map)はマップ自体、2番目の引数($key)は取得する値のキーです。

Sass (.scss)
@use "sass:map";  //map モジュールの読み込み

$font-weights: ("regular": 400, "medium": 500, "bold": 700);  //マップの定義

@debug map.get($font-weights, "medium");
//Debug: 500(コンパイル時のコンソールへの出力)
@debug map.get($font-weights, "extra-bold");
//Debug: null(コンパイル時のコンソールへの出力)

Sass: Maps

演算子(Operators)

Sass では演算子を使って、四則演算や文字列の連結、色の演算等を行うことが可能です。

Dart Sass では色の演算は廃止になりました。代わりに Color functions が追加されています。

Sass: Operators

数値の操作

Sass では数値型の値(単位あり&なし)に記号(演算子)を使って計算をすることができます。

Sass (.scss)
.thumb {
  width: 200px - (5 * 2) - 2;
  padding: 5px + 3px;
  border: 1px * 2 solid #ccc;
}
コンパイルして出力される CSS
.thumb {
  width: 188px;
  padding: 8px;
  border: 2px solid #ccc;
}

計算で使える演算子(記号)には以下のようなものがあります。

演算子 説明
+ 足し算(加算)
- 引き算(減算)
* 掛け算(乗算)
% 余り(剰余)
/ 割り算(除算) ※ Dart Sass では非推奨(将来的には廃止)。math.div() を使用するか乗算で代用

単位に関しては以下のような特徴があります。

  • 単位なしの数値は任意の単位の数値と使用できます(その単位にあわせて計算されます)。
  • 互換性のない単位を持つ数値は、加算、減算、または余りの計算(モジュロ)で使用できません。

実際には、以下のように変数を使って計算することが多いと思います。

Sass (.scss)
$main-width: 600px;
$border-width: 2px;

.foo {
  $padding: 5px;
  width: $main-width - $padding * 2 - $border-width *2;
}
コンパイルして出力される CSS
.foo {
  width: 586px;
}

マイナス記号(-)の注意点

マイナス(-)とハイフンは同じ記号なので、引き算や負の値の記号(単項演算子)、文字としてのハイフンなどの意味があります。そのため、確実に引き算にするには、マイナス(-)記号の前後に半角のスペースを入れるようにします。

単項演算子のマイナスの場合は、マイナス(-)記号の前にスペースを入れますが、後にはスペースを入れないようにします。

除算とスラッシュ

Sass での除算は math.div() 関数を使用するか、代わりに乗算を使います。

Sass は除算演算子としてのスラッシュ(/)の使用を現時点(v1.43.5 )ではサポートしていますが、これは非推奨であり、将来のバージョン(2.0.0)で削除される予定です。

math.div() を使用するには、@use を使ってモジュールの sass:math を読み込む必要があります。

Sass (.scss)
@use "sass:math";

$base-width: 600px;

.foo {
  width: math.div($base-width, 2);
}
コンパイルして出力される CSS
.foo {
  width: 300px;
}

現時点では、まだ、スラッシュ(/)を除算演算子として使用することがサポートされているため、以下のような場合は割り算が実行されます。

  • 値が変数に格納されている
  • 丸括弧の中で使われている
  • 値が別の計算の一部になっている

list.slash() を使用して、スラッシュ(/)を区切り文字として使用するように強制できます。

乗算で代用

除算に math.div() 関数を使用するのが面倒な場合は、代わりに乗算(掛け算)を使う方法もあります。この方法なら @use を使って sass:math を読み込む必要はありません。

例えば、1/2 や 1/4 にするには 0.5 や 0.25 をかけるのと同じなので乗算でも可能です。

Sass (.scss)
$base-width: 600px;

.foo {
  width: $base-width * .5;  /*0.5 をかけて 1/2 に*/
}
.bar {
  width: $base-width * .25;  /*0.25 をかけて 1/4 に*/
}
コンパイルして出力される CSS
.foo {
  width: 300px;
}
.bar {
  width: 150px;
}

Sass: Division

文字列の連結

プラス(+)は文字列を連結する演算子としても使うことができます。

Sass (.scss)
p {
  cursor: e + -resize;
}
p {
  cursor: e-resize;
}

引用符ありとなしの文字列を連結する場合は、最初の文字列の形式(引用符あり・なし)に変換されます。

Sass (.scss)
p::before {
  content: "Foo " + Bar;
  font-family: sans- + "serif";
}
コンパイルして出力される CSS
p::before {
  content: "Foo Bar";
  font-family: sans-serif;
}

Sass: String Operators

ブール演算子

以下は Sass のブール演算子です。

演算子 説明
not 式が false の場合は true
and 左右の式が共に true の場合は true。どちらかが false の場合は false
or 左右の式のどちらかが true の場合は true。左右の式が共に false の場合は false

Sass の true と false

true または false が許可されている場所では、他の値を使用することもできます。

Sass では false と null のみが false と判定されます。その他は全て true と判定されます(空文字列や空のリスト、数字のゼロも true)。

Sass: Boolean Operators

@use

@use ルールは、他の Sass ファイルからメンバー(変数やミックスイン、関数)をロードするためのルールで、複数のファイルの CSS を結合します。

@use によってロードされたファイルは「モジュール」と呼ばれます。

記述位置

@use は @forward 以外のルールやスタイルの前に配置する必要があります(@forward と併用する場合は @forward を @use より前に記述)。

モジュールのロード

@use "モジュール の url" と記述すると、指定された URL のモジュール(Sass ファイル)をロードします。この方法でロードしたスタイルは(それらのスタイルが何度ロードされても)コンパイルされた CSS の出力に1回だけ含まれます。

以下は2つの Sass ファイルを @use を使ってロードする(読み込む)例です。

sass
├── _code.scss
├── _lists.scss
└── style.scss
_code.scss
code {
  padding: .25em;
  line-height: 0;
}
_lists.scss
ul {
  text-align: left;
  list-style-type: none;

  & & {
    padding: {
      bottom: 0;
      left: 0;
    }
  }
}

style.scss では単純に上記2つの Sass ファイル(_code.scss と _lists.scss)を読み込んでいます。

パーシャルのファイル名の先頭のアンダーバーと拡張子は省略できます。

style.scss
@use 'code';
@use 'lists';
コンパイルして出力される CSS(style.css)
code {
  padding: 0.25em;
  line-height: 0;
}

ul {
  text-align: left;
  list-style-type: none;
}
ul ul {
  padding-bottom: 0;
  padding-left: 0;
}

Sass: @use

meta.load-css() を使ってもモジュールをロードすることができます。

メンバーの参照

@use は分割された Sass ファイルを読み込むことができますが、メンバー(変数、ミックスイン、および関数)はカプセル化されるのでグローバルにはならず、読み込んだファイル内でしか参照できません。

読み込んだ Sass ファイル内のメンバーを参照するには、ファイル名に基づく名前空間(namespace)を使用して、namespace.$variable や namespace.function() または @include namespace.mixin() で参照します。

デフォルトでは @use で読み込んだファイル名(モジュールの URL の最後のコンポーネントの拡張子を除いた部分)が namespace になります。

以下の例では style.scss で2つの Sass ファイル(モジュール)を @use で読み込んで、変数とミックスインを参照しています。

この例の場合、読み込むモジュールは同じ階層にあるのとパーシャルなので名前空間(namespace)は指定した URL(先頭のハイフンと拡張子を省略したファイル名)になります。

_variables.scss
$theme-color: #049A36;
_corners.scss
$radius: 3px;

@mixin rounded {
  border-radius: $radius;
}

_corners.scss を読み込んでそのミックスイン rounded には @include corners.rounded で、変数 $radius には corners.$radius でアクセスし、_variables.scss を読み込んでその変数 $theme-color には variables.$theme-color でアクセスします。

style.scss
@use "corners";
@use "variables";

.button {
  @include corners.rounded;   /*名前空間(corners)を指定*/
  padding: 5px + corners.$radius;  /*名前空間(corners)を指定*/
  background-color: variables.$theme-color; /*名前空間(variables)を指定*/
  color: #fff;
}
コンパイルして出力される CSS
.button {
  border-radius: 3px;
  padding: 8px;
  background-color: #049A36;
  color: #fff;
}

Sass: Loading Members

名前空間の変更

デフォルトの名前空間は読み込んだファイルの名前ですが、ファイル名が長い場合や同じ名前のファイルを読み込む場合は as を使って任意の名前空間に変更することができます。

_variables.scss
$theme-color: #049A36;
_corners.scss
$radius: 3px;

@mixin rounded {
  border-radius: $radius;
}

名前空間をそれぞれ corners から c へ、variables から v へ変更する例。

style.scss
@use "corners" as c;   /*名前空間を変更*/
@use "variables" as v;

.button {
  @include c.rounded;    /*変更した名前空間でアクセス*/
  padding: 5px + c.$radius;
  background-color: v.$theme-color;
  color: #fff;
}
as *(名前空間なしで参照)

as * と記述して、名前空間なしでモジュールをロードすることもできます。但し、これは名前の競合を引き起こす可能性があるので、自分で作成したスタイルシートに対してのみ行うことが推奨されています。

_variables.scss
$theme-color: #049A36;
_corners.scss
$radius: 3px;

@mixin rounded {
  border-radius: $radius;
}
Sass (.scss)
@use "corners" as *;
@use "variables" as *;

.button {
  /*名前空間なしでアクセス*/
  @include rounded;
  padding: 5px + $radius;
  background-color: $theme-color;
  color: #333;
}

Sass: Choosing a Namespace

プライベートメンバー

定義したメンバーをそのスタイルシートの外部からアクセスできないようにするには、名前を - または _ (ハイフンまたはアンダースコア)で始めます。

名前が - または _ で始まっているメンバーはプライベートメンバーとなり、それらを定義するスタイルシート内で通常どおりに機能しますが、外部からはアクセスできません。

_corners.scss
$-radius: 3px; /*プライベートメンバー*/

@mixin rounded {
  border-radius: $-radius;
}

以下の場合、$-radius にアクセスすると Error: Private members can't be accessed from outside their modules. のようなエラーになります(5行目を削除すれば、corners.rounded は参照できます)。

style.scss
@use "corners";

.button {
  @include corners.rounded;
  padding: 5px + corners.$-radius; /*Error: Private members can't be accessed...*/
}

Sass: Private Members

デフォルト値の変更(上書き)

!default フラグを使用して定義した変数は、@use でファイルの読み込む際に with を使って上書きして変数のデフォルトを変更することができます。

デフォルト値を変更してモジュールをロードするには、@use "url" with (変数: 値, 変数: 値, ...) のように記述します。

_library.scss
/* !default フラグを指定して定義 */
$black: #000 !default;
$border-radius: 0.25rem !default;
$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default;

code {
  border-radius: $border-radius;
  box-shadow: $box-shadow;
}
style.scss
/* with を使って変数の値を上書き */
@use 'library' with (
  $black: #666,
  $border-radius: 0.1rem
);
コンパイルして出力される CSS
code {
  border-radius: 0.1rem;
  box-shadow: 0 0.5rem 1rem rgba(102, 102, 102, 0.15);
}

Sass: Configuration

_index.scss

フォルダの中に _index.scss というファイルを作成してフォルダの URL を指定してロードすると、_index.scss が自動的にロードされます。

言い換えると、_index.scss という名前の Sass ファイル(インデックスファイル)を読み込む際は _index.scss というファイル名の部分を省略することができます

例えば以下のようなファイル構成がある場合

.
├── css
│   └── style.css
└── sass
    ├── foundation
    │   ├── _code.scss
    │   ├── _lists.scss
    │   └── _index.scsss /*インデックスファイル*/
    └── style.scss
_code.scss
code {
  padding: .25em;
  line-height: 0;
}
_lists.scss
ul, ol {
  text-align: left;

  & & {
    padding: {
      bottom: 0;
      left: 0;
    }
  }
}

_index.scss でフォルダ内の _code.scss と _lists.scss をロード

_index.scss
@use 'code';
@use 'lists';

style.scss ではフォルダ foundation を指定して _index.scss をロードすれば、 _code.scss と _lists.scss をロードすることができます。

style.scss
@use 'foundation';
コンパイルして出力される CSS(style.css)
code {
  padding: .25em;
  line-height: 0;
}

ul, ol {
  text-align: left;
}
ul ul, ol ol {
  padding-bottom: 0;
  padding-left: 0;
}

Sass: Index Files

CSS の読み込み

Sass は @use を使って Sass ファイルの他に CSS ファイルもロードすることができます。

code.css(CSS ファイル)
code {
  padding: .25em;
  line-height: 0;
}

CSS ファイルの読み込みでも拡張子は省略できます。

style.scss
@use 'code';
コンパイルして出力される CSS(style.css)
code {
  padding: .25em;
  line-height: 0;
}

モジュールとしてロードされた CSS ファイルは Sass 機能を使えません。誤って CSS に Sass を記述しないように、Sass の記述や有効な CSS でない記述はコンパイル時にエラーを生成します。

Sass: Loading CSS

@forward

@forward ルールは @use と同じように、指定された URL のモジュールをロードしますが、ロードされたモジュールのメンバーは、@forward を記述したファイルを読み込んだ側で参照できるようになります。

但し、これらのメンバーは @forward を記述したモジュール(ファイル)内では使用できません。モジュール内でメンバーを参照するには、別途 @use ルールを追加する必要があります。

言い換えると、@forward ルールは指定されたモジュール(のメンバー)を読み込み、それらを別のモジュールに転送(forward)してアクセス可能にします。

@use ルールで読み込んだ場合は、ロードしたファイルにスコープが生成され、変数やミックスインなどのメンバーはそのファイルでしか参照できないため、以下の style.scss ではエラーになります。

_variables.scss
$theme-color: #049A36;
_foo.scss
@use "variables"; /* variables はこのファイルでのみ参照可能*/
style.scss
@use 'foo';

.foo {
  color: foo.$theme-color; /* エラー Undefined variable(参照できない)*/
}

_foo.scss で @forward を使って _variables.scss を読み込むと、_foo.scss を @use で読み込んだファイルでは _variables.scss のメンバーを参照できるようになります。

_foo.scss
@forward "variables"; /* @forward ルールに変更 */

style.scss で @use を使って _foo.scss を読み込むと _variables.scss のメンバーが転送(forward)されてアクセス可能になります。

style.scss
@use 'foo';

.foo {
  color: foo.$theme-color; /* variables の値を foo 経由でアクセスできる */
}
コンパイルして出力される CSS(style.css)
.foo {
  color: #049A36;
}

@use と併用

@use ルールとは異なり、@forward ルールを使って読み込んでいるファイル内ではそのモジュールのメンバーを参照できません。

例えば、上記の _foo.scss で _variables.scss のメンバーにアクセスしようとするとエラーになります。

_foo.scss
@forward "variables";

.bar {
  color: variables.$theme-color;  /* エラー There is no module with the namespace "variables".*/
}

@use を追加して @forward と併用すればアクセスできるようになります。

※ @use と併用する場合は @forward を先に記述します。

_foo.scss
@forward "variables";
@use "variables"; /* @use を追加 */

.bar {
  color: variables.$theme-color;  /* @use を追加して variables のメンバーにアクセス*/
}
コンパイルして出力される CSS
.bar {
  color: #049A36;
}

.foo {
  color: #049A36;
}

プレフィックスの追加

モジュールのメンバーは通常名前空間と使用されるため、短くて単純な名前が使いやすいですが、これらの名前はそれらが定義されているモジュールの外部では意味をなさない可能性があります。

例えば、以下はリストのモジュールの中でリスト要素をリセットするミックスイン reset ですが、モジュールの外部では何のリセットなのかはわかりません。

_list.scss
@mixin reset {
  margin: 0;
  padding: 0;
  list-style: none;
}

このため、@forward には転送するすべてのメンバーにプレフィックスを追加するオプションがあります。

@forward "url" as prefix-* と記述すると、モジュールによって転送されるすべてのミックスイン、関数、および変数名の先頭に指定されたプレフィックスを追加します。

例えば、モジュールが $color と reset という名前のメンバーを定義し、それらが as list-* として転送される場合、名前空間と $list-color や list-reset として参照します。

_list.scss
$color: #333;

@mixin reset {
  margin: 0;
  padding: 0;
  list-style: none;
}
_foo.scss
@forward "list" as list-*; /* プレフィックスを指定 */
styles.scss
@use 'foo';

li {
  @include foo.list-reset;
  color: foo.$list-color;
}
コンパイルして出力される CSS
li {
  margin: 0;
  padding: 0;
  list-style: none;
  color: #333;
}

hide と show

モジュールからすべてのメンバーを転送したくない場合など、一部のメンバーを非公開にして、パッケージのみがそれらを使用できるようにすることができます。

hide と show を使って @forward "url" hide member, ... や @forward "url" show member, ...のように記述して、どのメンバーが転送されるかを制御できます。

hide は指定されたメンバーは転送されるべきではなく、他のすべてが転送されるべきであることを意味します。 show は指定されたメンバーのみを転送することを意味します。 どちらの形式でも、ミックスイン、関数、または変数($を含む)の名前をリストします。

_variables.scss
$theme-color: #049A36;
$blue-color: blue;
$red-color: red;

以下は $theme-color のみを転送するので、@use で _foo.scss を読み込んだファイルでは、$theme-color にはアクセスできますが、$blue-color や $red-color にはアクセスできません。

_foo.scss
@forward "variables" show $theme-color;

以下は $blue-color と $red-color を転送しないので、@use で _foo.scss を読み込んだファイルでは、$blue-color や $red-color にはアクセスできませんが、$theme-color にはアクセスできます(上記と同じことになります)。

_foo.scss
@forward "variables" hide $blue-color, $red-color;

デフォルト値の変更(上書き)

@forward でも @use と同じように!default フラグを使用して定義した変数は、ロードする際に with を使って上書きして変数のデフォルトを変更することができます。

_library.scss
$black: #000 !default;
$border-radius: 0.25rem !default;
$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default;

code {
  border-radius: $border-radius;
  box-shadow: $box-shadow;
}
_foo.scss
@forward "library" with (
  $black: #999,
  $border-radius: 0.1rem
);
style.scss
@use 'foo';
コンパイルして出力される CSS
code {
  border-radius: 0.1rem;
  box-shadow: 0 0.5rem 1rem rgba(153, 153, 153, 0.15);
}

with で !default を使用

@use の場合とほとんど同じように機能しますが、@forward ルールでは、with で !default フラグを使用できます。これにより、モジュールは元のスタイルシートのデフォルトを変更しながら、ロードする側でそれらをオーバーライドできるようになります。

_foo.scss
@forward 'library' with (
  /* !default フラグを使用 */
  $black: #999 !default,
  $border-radius: 0.1rem !default
);

ロードする側でデフォルトをオーバーライドすることができます。

style.scss
@use 'foo' with ($black: #333); /* デフォルトをオーバーライド */
コンパイルして出力される CSS
code {
  border-radius: 0.1rem;
  box-shadow: 0 0.5rem 1rem rgba(51, 51, 51, 0.15);
}

Sass: @forward

@mixin と @include ミックスイン

ミックスインはよく利用する CSS のスタイルを定義しておいて、別の場所でそのスタイルを使い回せるようにする機能です。CSS では、一度定義したスタイルの再利用は難しいですが、Sass ではミックスインを使うことでスタイルの再利用が可能になります。

また、ミックスインでは引数を取ることができるので、より柔軟な使い回しが可能になります。

ミックスインは @mixin の後に半角スペースを置いて任意の名前()で定義します。

ミックスインの定義
@mixin ミックスイン名 {
  /* ミックスインの定義を記述 */
}

そして使いたい場所で @include で定義したミックスインを呼び出します。

ミックスインの呼び出し
セレクタ {
  @include ミックスイン名;
}

以下は grayBox という名前のミックスインを定義して呼び出す例です。

Sass (style.scss)
/* ミックスインの定義 */
@mixin grayBox {
  margin: 20px 0;
  padding: 10px;
  border: 1px solid #999;
  background-color: #EEE;
  color: #333;
}

.foo {
  /* 定義したミックスインの呼び出し */
  @include grayBox;  /* ここにコードが展開される */
}

ミックスインは、@include で挿入した箇所で展開されるコード片で、ミックスイン自体のコード(定義)は CSS としてコンパイルされず、@include されてはじめて実体を持ちます。

コンパイルして出力される CSS (style.css)
.foo {
  margin: 20px 0;
  padding: 10px;
  border: 1px solid #999;
  background-color: #EEE;
  color: #333;
}

ミックスインの定義の中で、別のミックスインを呼び出すこともできます。

Sass (style.scss)
@mixin reset-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

@mixin horizontal-list {
  @include reset-list; /* 上記で定義したミックスインの呼び出し */

  li {  /* ネスト */
    display: inline-block;
    margin: {
      left: -2px;
      right: 2em;
    }
  }
}

nav ul {
  @include horizontal-list;
}

@include で horizontal-list を呼び出すことで、その定義の中で @include されている reset-list も展開されます。

コンパイルして出力される CSS (style.css)
nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
nav ul li {
  display: inline-block;
  margin-left: -2px;
  margin-right: 2em;
}

ミックスイン名

ミックスイン名も変数名などの他の全ての Sass 識別子と同様に、ハイフンとアンダースコアを同一として扱います。例えば、reset-list と reset_list の両方が同じミックスインを参照します。

別ファイルのミックスインを使う

前述の例では同じファイル内でミックスインの定義と呼び出しを行っていますが、別ファイルに定義してあるミックスインを読み込んで使うこともよくあります。

以下は _corners.scss に定義してあるミックスイン(rounded)を呼び出す例です。

_corners.scss
$radius: 3px !default; /* デフォルト値の設定 */

@mixin rounded {
  border-radius: $radius;
}

ミックスインを利用するファイルでは @use でミックスインの定義してある _corners.scss を読み込みます。この例では with を使ってデフォルトを上書きしています。

また、読み込んだミックスインには名前空間を指定して @include corners.rounded でアクセスします。

style.scss
@use "corners" with ( $radius: 8px );

@mixin grayBox {
  margin: 20px 0;
  padding: 10px;
  border: 1px solid #999;
  background-color: #EEE;
  color: #333;
}

.foo {
  @include grayBox;
  @include corners.rounded; /* _corners.scss で定義してあるミックスインの呼び出し */
}
コンパイルして出力される CSS
.foo {
  margin: 20px 0;
  padding: 10px;
  border: 1px solid #999;
  background-color: #EEE;
  color: #333;
  border-radius: 8px;
}

Sass: @mixin and @include

引数を使ったミックスイン

ミックスインは引数を取ることができ、呼び出されるたびに動作をカスタマイズすることができます。

引数はミックスイン名の後に括弧(カッコ)で囲んで記述します。引数が複数ある場合は、カンマで区切ってリストとして指定します(末尾にカンマを含めることもできます)。

引数も変数なので、通常の変数名と同様、名前は $ から始めます。

ミックスインの定義
@mixin ミックスイン名(引数) {
  /* ミックスインの定義を記述 */
}
ミックスインの呼び出し
セレクタ {
  @include ミックスイン名(引数);
}

指定された引数は、対応する変数としてミックスインの本体内で利用できます。

呼び出す際には、ミックスインの定義で指定した引数と同じ数の引数を同じ順番で指定します。

Sass (.scss)
@mixin my-border($color, $width, $radius) {
  border: {
    color: $color;
    width: $width;
    radius: $radius;
  }
}

p {
  @include my-border(blue, 1px, 3px);
}
コンパイルして出力される CSS
p {
  border-color: blue;
  border-width: 1px;
  border-radius: 3px;
}

以下は受け取った第1引数($property)はプロパティ名としてインターポレーションで出力し、第2及び第3引数はプロパティの値として利用しています。

Sass (.scss)
@mixin rtl($property, $ltr-value, $rtl-value) {
  #{$property}: $ltr-value;

  [dir=rtl] & {
    #{$property}: $rtl-value;
  }
}

.sidebar {
  @include rtl(float, left, right);
}
コンパイルして出力される CSS
.sidebar {
  float: left;
}
[dir=rtl] .sidebar {
  float: right;
}

引数がない場合でもミックスイン名の後に括弧を付けても問題ありません(引数がない場合は括弧を省略できます)。

Sass (.scss)
@mixin clearfix() {
  &::after {
    display: block;
    clear: both;
    content: "";
  }
}

.clearfix {
  @include clearfix();
}
コンパイルして出力される CSS
.clearfix::after {
  display: block;
  clear: both;
  content: "";
}

Sass: Mixins/Arguments

引数にデフォルト値を設定

通常、ミックスインを呼び出す際には、定義で宣言したすべての引数を渡す必要がありますが、デフォルト値(初期値)を定義することにより、引数をオプションにすることができます。

引数のデフォルト値は、変数と同じ書式($引数名 : デフォルト値)で記述します。

呼び出す際は、指定する引数がデフォルト値と同じ場合は、カッコや値は省略することができます。デフォルト値と値が異なる場合には、引数の値を指定します。

Sass (.scss)
@mixin kadomaru($radius: 5px) {
  border-radius: $radius;
}

.foo {
  @include kadomaru; /* カッコと値を省略 */
}
.bar {
  @include kadomaru(); /* 値を省略 */
}
.baz {
  @include kadomaru(10px);
}
コンパイルして出力される CSS
.foo {
  border-radius: 5px;
}
.bar {
  border-radius: 5px;
}
.baz {
  border-radius: 10px;
}

デフォルト値を設定した引数を複数指定

以下のように2つのデフォルト値を設定した引数がある場合、2つ目の値がデフォルト値と同じ場合は、省略することができます。

但し、1つ目の値がデフォルト値と同じで、2つ目が異なる場合は、1つ目を省略することができません。以下のように1つ目の値にデフォルト値と同じ値を指定する必要があります(10行目)。

Sass (.scss)
@mixin kadomaruBox($radius: 5px, $bgColor: #EEE) {
  border-radius: $radius;
  background-color: $bgColor;
}

.foo {
  @include kadomaruBox(4px);
}
.bar {
  @include kadomaruBox(5px, #DDDDDD);
}

/* 一つ目の値を省略するとエラーになります */
.baz {
  @include kadomaruBox(, #DDDDDD);  //エラー
}

/* カンマも含めて省略するとコンパイル時にエラーにならないが意味をなさない*/
.baz {
  @include kadomaruBox(#DDDDDD);  //border-radius:#DDDDDD となる
}

キーワード引数

引数に引数名(キーワード)を付けて渡すこともできます。「引数名:値」の形式で引数を渡せば、順序を気にしないで必要な引数のみを渡すことができます。

Sass (.scss)
@mixin kadomaruBox($radius: 5px, $bgColor: #EEE) {
  border-radius: $radius;
  background-color: $bgColor;
}

.foo {
  @include kadomaruBox(4px);
}
.bar {
  @include kadomaruBox(5px, #DDDDDD);
}

.baz {
  @include kadomaruBox($bgColor:#DDDDDD);  //エラーにならない
}
コンパイルして出力される CSS
.foo {
  border-radius: 4px;
  background-color: #EEE;
}

.bar {
  border-radius: 5px;
  background-color: #DDDDDD;
}

.baz {
  border-radius: 5px;
  background-color: #DDDDDD;
}

以下は @if を使って、指定された引数を判定して出力を変える例です。

第3引数の $active にはデフォルト値として null を設定しているので、第3引数を指定しなければ、:active は出力されません(Sass では false と null のみが false と判定され、その他は全て true と判定されます)。

Sass (.scss)
@mixin link-color($normal, $hover, $active: null){
  color: $normal;
  &:hover {
    color: $hover;
    text-decoration: none;
  }
  @if $active {
    &:active {
      color: $active;
      text-decoration: none;
    }
  }
}

.foo a {
  @include link-color(#2B69C7, #365DA0);
}

.bar a {
  @include link-color(#666, #365DA0, #2B69C7);
}
コンパイルして出力される CSS
.foo a {
  color: #2B69C7;
}
.foo a:hover {
  color: #365DA0;
  text-decoration: none;
}

.bar a {
  color: #666;
}
.bar a:hover {
  color: #365DA0;
  text-decoration: none;
}
.bar a:active {
  color: #2B69C7;
  text-decoration: none;
}

カンマ(,)を使うプロパティ

基本的にミックスインには引数1つに対して1つの値しか渡すことができません。

但し、box-shadow, text-shadow などのプロパティのようにカンマ区切りで複数の値を指定できるものがあります。

以下の例では、複数の影を指定した .bar はエラーになってしまいます(1つの引数のミックスインに対して、2つの引数を指定したことになるため)。

Sass (.scss)
@mixin boxShadow($values) {
  box-shadow: $values;
}

.foo {
  @include boxShadow(3px 3px 8px #999);
}

.bar {
  /* エラーになる Error: Only 1 argument allowed, but 2 were passed.*/
  @include boxShadow(3px 3px 8px #999, -3px -3px 8px #CCC);
}

リストを使う

回避策の1つはリストを使う方法です。複数の値を ( ) または [ ] で囲って明示的にリストにして1つの値として渡します。

Sass (.scss)
@mixin boxShadow($values) {
  box-shadow: $values;
}

.foo {
  @include boxShadow(3px 3px 8px #999);
}

.bar {
  /* ( ) または [ ] で囲んでリストで渡す */
  @include boxShadow((3px 3px 8px #999, -3px -3px 8px #CCC));
  // または @include boxShadow([3px 3px 8px #999, -3px -3px 8px #CCC]);
}

Sass: Lists

可変長引数を使う

もう一つの回避策は、可変長引数を使う方法です。可変長引数を使うには、引数名の後に「...」(3つのドット)を記述します。

/* 可変長引数(引数名の後に ... )を使う */
@mixin boxShadow($values...) {
  box-shadow: $values;
}

.foo {
  @include boxShadow(3px 3px 8px #999);
}

//エラーにならない
.bar {
  @include boxShadow(3px 3px 8px #999, -3px -3px 8px #CCC);
}

可変長引数(引数リスト)

@mixin 宣言の最後の引数が...(3つのドット)で終わる場合、追加の引数はリストとして渡されます。この引数は可変長引数や引数リストと呼ばれ、任意の数の引数を取ることができます。

以下は2つ目の引数 $selectors... を可変長引数とする例で、2番目以降にはセレクタのリストを引き取り、それらを順番に垂直方向に絶対配置します。

リストに含まれる数を取得する length() を使って可変長引数に指定されている引数の数を取得し、@for ~ to でその数だけ繰り返し処理を行っています。

nth() は第1引数に指定したリストの第2引数に指定した $i + 1 番目の位置の値を取得します。これにより可変長引数に渡された値を取得してインターポレーションを使ってセレクタとして出力しています。

@mixin order($height, $selectors...) {
  @for $i from 0 to length($selectors) {
    #{nth($selectors, $i + 1)} {
      position: absolute;
      height: $height;
      margin-top: $i * $height;
    }
  }
}

@include order(150px, "input.name", "input.address", "input.zip");

以下は length() と nth() の代わりに、 @use でビルトインモジュールの sass:list を読み込んで list.length() と list.nth() を使用する場合です。

@use "sass:list"; /* list モジュールの読み込み */

@mixin order($height, $selectors...) {
  @for $i from 0 to list.length($selectors) {
    #{list.nth($selectors, $i + 1)} {
      position: absolute;
      height: $height;
      margin-top: $i * $height;
    }
  }
}

@include order(150px, "input.name", "input.address", "input.zip");
コンパイルして出力される CSS
input.name {
  position: absolute;
  height: 150px;
  margin-top: 0px;
}

input.address {
  position: absolute;
  height: 150px;
  margin-top: 150px;
}

input.zip {
  position: absolute;
  height: 150px;
  margin-top: 300px;
}

可変長引数にキーワード引数を使う

可変長引数(引数リスト)にも「引数名:値」の形式のキーワード引数を指定することができます。

ユーザーがキーワード引数を渡した場合、引数リストを meta.keywords() 関数に渡すことにより、それらにマップとしてアクセスできます(Argument Lists)。

meta.keywords() 関数はキーワード引数の引数リストを受け取り、引数名($を含まない)と値のマップを返します。

以下では引数に渡されたリスト $args を meta.keywords() 関数に渡して、返されるマップの各要素を @each で処理しています。

マップの各要素に対して引数名(キーワード)を $name に受け取りインターポレーションでセレクタ名の一部として出力し、引数の値を $color に受け取り、プロパティの値に出力しています。

@use "sass:meta"; /* meta モジュールの読み込み */

@mixin syntax-colors($args...) {
  @each $name, $color in meta.keywords($args) {
    pre span.stx-#{$name} {
      color: $color;
    }
  }
}

@include syntax-colors(
  /* キーワード引数を渡す */
  $string: #080,
  $comment: #800,
  $variable: #60b,
)
コンパイルして出力される CSS
pre span.stx-string {
  color: #080;
}

pre span.stx-comment {
  color: #800;
}

pre span.stx-variable {
  color: #60b;
}

ミックスインの呼び出しに可変長引数を使う

ミックスインを呼び出す(@include する)際にも可変長引数を使うことができます。

例えば以下のように変数に値を格納して、ミックスインを呼び出すとエラーになってしまいます。

Sass (.scss)
@mixin colors($text, $background, $border) {
  color: $text;
  background-color: $background;
  border-color: $border;
}
$values: #ff0000, #00ff00, #0000ff;

.foo {
  /*エラーになる Error: Missing argument $background*/
  @include colors($values);
}

この場合、以下のように可変長引数にすることでエラーになりません。

Sass (.scss)
@mixin colors($text, $background, $border) {
  color: $text;
  background-color: $background;
  border-color: $border;
}
$values: #ff0000, #00ff00, #0000ff;

.foo {
  @include colors($values...);  //OK
}
コンパイルして出力される CSS
.foo {
  color: #ff0000;
  background-color: #00ff00;
  border-color: #0000ff;
}

ミックスインのスコープ

ミックスインにも有効範囲(スコープ)があります。そのため、ルールセット内でミックスインを定義すると、そのルールセット内でしか利用できなくなります(利用できる範囲を制限することができます)。

以下の例ではクラス foo の中でミックスインを定義しているので、クラス bar の中で使おうとするとエラーになります。

Sass (.scss)
.foo {
  @mixin kadomaru {
    border-radius: 6px;
  }
  .rc {
    @include kadomaru; /* ここは OK */
  }
}

.bar {
  /*エラーになる Error: Undefined mixin.*/
  @include kadomaru;
}

ミックスインにコンテンツを渡す @content

@content はルールセットやスタイルなどのコンテンツ(記述した内容)をミックスインに渡す機能です。

ミックスインの定義では、@include の呼び出しの際に渡されるコンテンツを展開したい場所に @content と記述します。

そして @include でそのミックスインを呼び出す際に波括弧 { } で括ってコンテンツを記述すると、ミックスインの定義で @content を記述した場所にそのコンテンツが展開されます。

Sass (.scss)
@mixin box {
  width: 300px;
  border: 1px solid #999;
  background: #EEE;
  @content;  /* ここにコンテンツが展開される */
}

.alert {
  @include box {
    /* コンテンツ を記述 */
    color: #F00;
    font-weight: bold;
  }
}

.normal {
  @include box {
    /* コンテンツ を記述 */
    color: #666;
  }
}
コンパイルして出力される CSS
.alert {
  width: 300px;
  border: 1px solid #999;
  background: #EEE;
  color: #F00; /* 展開されたコンテンツ */
  font-weight: bold; /* 展開されたコンテンツ */
}

.normal {
  width: 300px;
  border: 1px solid #999;
  background: #EEE;
  color: #666; /* 展開されたコンテンツ */
}

Sass: Content Blocks

メディアクエリ(ブレークポイント)

ブレークポイントをマップで定義しておき、ミックスインでメディアクエリを出力する例です。

map.get() と meta.inspect() を使用するので map と meta モジュールをロードします。

ブレークポイントを定義する変数 $breakpoints はサイズを表すキーとメディアクエリに出力する値のペアからなるマップで、!default フラグを指定しています。

ミックスインの引数 $name にマップのキーに対応する値を指定すると、map.get() でブレークポイントのマップ $breakpoints から対応する値を取得して出力します。

但し、以下の場合、ブレークポイントの値をそのまま出力するとマップとして認識され、コンパイル時に Error: (min-width: 576px) isn't a valid CSS value (出力が CSS として有効でない値)というエラーになるので、meta.inspect() を使って文字列に変換してインターポレーションで出力しています。

関連項目:@debug 出力の確認

また、この例ではミックスインの引数を省略した場合のデフォルト値を lg に設定していますが、環境に応じて変更します。

_breakpoints.scss
@use "sass:map";
@use "sass:meta";

$breakpoints: (
  'xs': (min-width: 0),
  'sm': (min-width: 576px),
  'md': (min-width: 768px),
  'lg': (min-width: 992px),
  'xl': (min-width: 1200px),
  'xxl': (min-width: 1400px)
) !default;

@mixin bp-mq($name: lg) {
  @media screen and #{meta.inspect(map.get($breakpoints, $name))} {
    @content;
  }
}

以下は meta.inspect() を使わなくてもコンパイル時にエラーにならないように書き換えたものです。

_breakpoints.scss
@use "sass:map";

$breakpoints: (
  'xs': '(min-width: 0)',
  'sm': '(min-width: 576px)',
  'md': '(min-width: 768px)',
  'lg': '(min-width: 992px)',
  'xl': '(min-width: 1200px)',
  'xxl': '(min-width: 1400px)'
) !default;

@mixin bp-mq($name: lg) {
  @media screen and #{map.get($breakpoints, $name)} {
    @content;
  }
}

または以下のように記述することもできます。

_breakpoints.scss
@use "sass:map";

$breakpoints: (
  'xs': 0,
  'sm': 576px,
  'md': 768px,
  'lg': 992px,
  'xl': 1200px,
  'xxl': 1400px
) !default;

@mixin bp-mq($name: lg) {
  @media screen and (min-width: #{map.get($breakpoints, $name)})  {
    @content;
  }
}

以下は上記ミックスインを呼び出す例です。@use でミックスインの記述してある _breakpoints.scss を読み込んで名前空間を変更 bp に変更しています。

style.scss
@use "breakpoints" as bp;

.logo {
  width: 130px;
  @include bp.bp-mq(sm) {
    width: 150px;
  }
  @include bp.bp-mq(md) {
    width: 170px;
  }
  @include bp.bp-mq(lg) {
    width: 200px;
  }
}
コンパイルして出力される CSS(style.css)
.logo {
  width: 130px;
}
@media screen and (min-width: 576px) {
  .logo {
    width: 150px;
  }
}
@media screen and (min-width: 768px) {
  .logo {
    width: 170px;
  }
}
@media screen and (min-width: 992px) {
  .logo {
    width: 200px;
  }
}

定義されていない値を指定した場合はエラーにする

以下は引数に定義されていないブレークポイントの値を指定した場合はエラーにする例です。

map.has-key() で引数に指定された値がブレークポイントのキーに存在するかを調べて、存在しない場合は @error でエラーを表示するようにしています。

また、この例ではミックスインの引数を省略した場合は、メディアクエリは出力せずに @content の値のみを出力するようにしています。

_breakpoints.scss
@use "sass:map";

$breakpoints: (
  'xs': 0,
  'sm': 576px,
  'md': 768px,
  'lg': 992px,
  'xl': 1200px,
  'xxl': 1400px
) !default;

@mixin bp-mq($name: null) {
  @if $name {
    @if map.has-key($breakpoints, $name) {
      @media screen and (min-width: #{map.get($breakpoints, $name)})  {
        @content;
      }
    }@else {
       @error "breakpoint #{$name} is not defined. use: #{map.keys($breakpoints)}";
    }
  } @else {
    /* 引数を省略した場合はメディアクエリを出力しない*/
    @content;
  }
}

以下は上記ミックスインを呼び出す例です。前述の例とほぼ同じですが、引数を省略した場合はコンテンツのみが出力されます。以下の場合、6〜8行目は不要です。

style.scss
.@use "breakpoints" as bp;

.logo {
  width: 130px;
  /* 引数を省略するとミックスインを使わない場合と同じ */
  @include bp.bp-mq() {
    width: 130px;
  }
  @include bp.bp-mq(sm) {
    width: 150px;
  }
  @include bp.bp-mq(md) {
    width: 170px;
  }
  @include bp.bp-mq(lg) {
    width: 200px;
  }
}

コンパイルして出力される CSS(style.css)
.logo {
  width: 130px;
  width: 130px; /*同じ内容が出力されている(不要)*/
}
@media screen and (min-width: 576px) {
  .logo {
    width: 150px;
  }
}
@media screen and (min-width: 768px) {
  .logo {
    width: 170px;
  }
}
@media screen and (min-width: 992px) {
  .logo {
    width: 200px;
  }
}

参考サイト:Sassの変数とmixinで変更に強いメディアクエリをつくる

max-width や両方を使った例

前述の例は min-width を使ってメディアクエリを指定していますが、以下は max-width や両方を使って指定するミックスインを追加した例です。

以下の場合、min-width や max-width を使ったミックスインでは引数を省略するとコンテンツのみを出力しますが、両方を使ったミックスインでは引数を省略できません(エラーになります)。

また max-width の値にはブレークポイントの値から 0.2 を引いた値を使っています。

_breakpoints.scss
@use "sass:map";

$breakpoints: (
  'xs': 0,
  'sm': 576px,
  'md': 768px,
  'lg': 992px,
  'xl': 1200px,
  'xxl': 1400px
) !default;

/* min-width での指定 */
@mixin bp-mq-up($name: null) {
  @if $name {
    @if map.has-key($breakpoints, $name) {
      @media screen and (min-width: #{map.get($breakpoints, $name)})  {
        @content;
      }
    }@else {
       @error "breakpoint #{$name} is not defined. use: #{map.keys($breakpoints)}";
    }
  } @else {
    @content;
  }
}

/* max-width での指定 */
@mixin bp-mq-down($name: null) {
  @if $name {
    @if map.has-key($breakpoints, $name) {
      @media screen and (max-width: #{map.get($breakpoints, $name) - 0.2})  {
        @content;
      }
    }@else {
       @error "breakpoint #{$name} is not defined. use: #{map.keys($breakpoints)}";
    }
  } @else {
    @content;
  }
}

/* min-width と max-width の両方での指定 */
@mixin bp-mq-between($min: null, $max: null ) {
  @if $min != null and $max != null  {
    @if map.has-key($breakpoints, $min) and map.has-key($breakpoints, $max) {
      @media screen and (min-width: #{map.get($breakpoints, $min)}) and (max-width: #{map.get($breakpoints, $max) - 0.2}) {
        @content;
      }
    }@else {
      @error "breakpoint is not defined. use: #{map.keys($breakpoints)}";
    }
  } @else {
    @error "need two breakpoints";
  }
}

以下は上記ミックスインを呼び出す例です。

@use "breakpoints" as bp;

.logo {
  width: 130px;
  @include bp.bp-mq-up(sm) {
    width: 150px;
  }
  @include bp.bp-mq-up(md) {
    width: 170px;
  }
  @include bp.bp-mq-up(lg) {
    width: 200px;
  }
}

.logo2 {
  width: 220px;
  @include bp.bp-mq-down(xl) {
    width: 200px;
  }
  @include bp.bp-mq-down(lg) {
    width: 180px;
  }
  @include bp.bp-mq-down(md) {
    width: 150px;
  }
}

.logo-text {
  background-color: white;
  @include bp.bp-mq-between(md, lg) {
    background-color: silver;
  }
  @include bp.bp-mq-between(lg, xxl) {
    background-color: gold;
  }
}
コンパイルして出力される CSS
.logo {
  width: 130px;
}
@media screen and (min-width: 576px) {
  .logo {
    width: 150px;
  }
}
@media screen and (min-width: 768px) {
  .logo {
    width: 170px;
  }
}
@media screen and (min-width: 992px) {
  .logo {
    width: 200px;
  }
}

.logo2 {
  width: 220px;
}
@media screen and (max-width: 1199.8px) {
  .logo2 {
    width: 200px;
  }
}
@media screen and (max-width: 991.8px) {
  .logo2 {
    width: 180px;
  }
}
@media screen and (max-width: 767.8px) {
  .logo2 {
    width: 150px;
  }
}

.logo-text {
  background-color: white;
}
@media screen and (min-width: 768px) and (max-width: 991.8px) {
  .logo-text {
    background-color: silver;
  }
}
@media screen and (min-width: 992px) and (max-width: 1399.8px) {
  .logo-text {
    background-color: gold;
  }
}

関連項目:Bootstrap 5 のブレークポイントのミックスイン

@content に引数を渡す

ミックスインに引数を渡すのと同様にコンテンツブロックに引数を渡すことができます。

コンテンツブロックを記述する側(ミックスインを呼び出す側)では using を使ってそれらの引数を受け入れることを宣言する必要があります。

以下はミックスインに指定した引数をそのままコンテンツブロックに渡す例です。

ミックスインの呼び出しでは、using で @content で引数を受け取ることを宣言し、受け取った引数を使って値を設定しています。

Sass (.scss)
@mixin hover($color) {
  &:not([disabled]):hover {
    @content($color);
  }
}

.button {
  display: inline-block;
  padding: 3px 10px;
  border: 1px solid lightgreen;
  @include hover(green) using ($color){
    border-width: 2px;
    border-color: $color;
    color: $color;
  }
}
コンパイルして出力される CSS
.button {
  display: inline-block;
  padding: 3px 10px;
  border: 1px solid lightgreen;
}
.button:not([disabled]):hover {
  border-width: 2px;
  border-color: green;
  color: green;
}

以下は可変長の引数 $types を受け取り、@each を使って引数の各要素($type)を @media の後にインターポレーションで挿入し、@content に引数として $type を渡しています。

ミックスインの呼び出しでは、using ($arg) で @content で引数を受け取ることを宣言し、受け取った引数の値が print の場合は font-family を出力しています。

Sass (.scss)
@mixin media($types...) {
  @each $type in $types {
    @media #{$type} {
      @content($type);
    }
  }
}

@include media(screen, print) using ($arg) {
  h1 {
    font-size: 40px;
    @if $arg == print {
      font-family: Verdana, Arial, sans-serif;
    }
  }
}
コンパイルして出力される CSS
@media screen {
  h1 {
    font-size: 40px;
  }
}
@media print {
  h1 {
    font-size: 40px;
    font-family: Verdana, Arial, sans-serif;
  }
}

Sass: Passing Arguments to Content Blocks

以下は引数に指定された数の背景色を指定したクラス(.color-1〜.color-n)を生成するミックスインです。

生成するクラスの数はミックスインの引数に指定しています。背景色の色は 360deg * math.div($i, $length) で色相の値を算出してクラス名の数値の部分と共に @content に渡しています。

呼び出し側ではミックスインの引数に作成するクラスの数を指定し、コンテンツブロックで受け取る1つ目の引数(クラス名に使う数値)でクラス名を出力し、2つ目の引数($hue)を hsl() の第一引数(色相)に指定して背景色を設定しています。

Sass (.scss)
@use "sass:math";

@mixin bgcolors($length:5) {
  @for $i from 1 through $length {
    @content($i, 360deg * math.div($i, $length));
  }
}

@include bgcolors(3) using ($number, $hue) {
  .color-#{$number} {
    background-color: hsl($hue, 75%, 90%);
  }
}
コンパイルして出力される CSS
.color-1 {
  background-color: #d2f9d2;
}

.color-2 {
  background-color: #d2d2f9;
}

.color-3 {
  background-color: #f9d2d2;
}

github: sass/accepted/content-args.md

@extend セレクタの継承(拡張)

@extend は既存の(または継承されることを前提に定義された)スタイルに、特定のスタイルを追加して新たなスタイルを作成する(拡張する)機能です。

別のクラスの全てのスタイルに特定のスタイルを追加して新たなクラスを作成するような場合があります。

以下は、.box で定義したスタイルに特定のスタイルを追加したクラス .box--primary を作成する例です。

スタイルを継承するには、@extend の後に継承するセレクタ名を記述します。

Sass (.scss)
/* 基底のクラス */
.box {
  margin: 20px 0;
  padding: 10px;
  border: 1px solid #999;
}

/* 基底のクラスを拡張して新たなクラスを作成 */
.box--primary {
  @extend .box; /* .box のスタイルを全て継承 */
  border-color: blue; /* スタイルを追加したり特定のスタイルを上書き */
  background-color: #CDEBF8;
}

.box--error {
  @extend .box;
  border-color: red;
  background-color: #F8D0D1;
}

コンパイルすると以下のように、共通するプロパティはひとつのルールセットにまとめられ(グループ化され)、差分が新たなルールセットとして生成されます。

コンパイルして出力される CSS
.box, .box--error, .box--primary {
  margin: 20px 0;
  padding: 10px;
  border: 1px solid #999;
}

.box--primary {
  border-color: blue;
  background-color: #CDEBF8;
}

.box--error {
  border-color: red;
  background-color: #F8D0D1;
}

% プレースホルダーセレクタ

@extend を使ってスタイルを定義すると、コンパイル後の CSS には継承元のセレクタも生成されます。

@extend のためだけに宣言する場合など継承元のセレクタが不要な場合は、% をセレクタ名の先頭に付けることでそのセレクタを生成させないことができます。

以下は前述の例と同じ内容ですが、継承元のセレクタのクラスを表す . をプレースホルダーを意味する % に変更しています。

Sass (.scss)
/* セレクタ名を % で始める */
%box {
  margin: 20px 0;
  padding: 10px;
  border: 1px solid #999;
}

.box--primary {
  @extend %box; /* %box を継承 */
  border-color: blue;
  background-color: #CDEBF8;
}

.box--error {
  @extend %box;  /* %box を継承 */
  border-color: red;
  background-color: #F8D0D1;
}}

継承元の %box のセレクタは生成されません。

コンパイルして出力される CSS
.box--error, .box--primary {
  margin: 20px 0;
  padding: 10px;
  border: 1px solid #999;
}

.box--primary {
  border-color: blue;
  background-color: #CDEBF8;
}

.box--error {
  border-color: red;
  background-color: #F8D0D1;
}

@extend の使いどころ

スタイルを継承する @extend は便利な機能ですが、使い方には注意が必要です。

共通部分を何でも @extend を使って継承してしまうと、コンパイルされて出力される CSS のソースコードが読みづらくなってしまったり、大量のセレクタが生成される可能性があります。

基本的には同じコンポーネント内など限られた範囲内で似たようなスタイルを作成する際に、共通のスタイルを定義してそれを @extend して拡張するのが良いとされています。

以下はプレースホルダーを使って共通のスタイルを作成し、共通ではない部分を個別に指定してスタイルのバリエーションを作成する例です。

但し、ミックスインを使ったほうが引数を指定できるなど、より柔軟にバリエーションを作成できます。

Sass (.scss)
/* コンポーネントの共通スタイルをプレースホルダーを使って作成 */
%btn {
  display: inline-block;
  position: relative;
  cursor: pointer;
  padding: 10px 20px;
  border: 1px solid #999;
}

/* 色の異なるバリエーションを作成 */
.btn {
  @extend %btn;
  background-color: #fff;
}

.btn--primary {
  @extend %btn;
  border-color: blue;
  background-color: blue;
  color: #fff;
}
.btn--caution {
  @extend %btn;
  border-color: red;
  background-color: red;
  color: #fff;
}
コンパイルして出力される CSS
.btn--caution, .btn--primary, .btn {
  display: inline-block;
  position: relative;
  cursor: pointer;
  padding: 10px 20px;
  border: 1px solid #999;
}

.btn {
  background-color: #fff;
}

.btn--primary {
  border-color: blue;
  background-color: blue;
  color: #fff;
}

.btn--caution {
  border-color: red;
  background-color: red;
  color: #fff;
}

@extend が適さない例

サイト全体のいろいろな場所から継承するような目的で @extend を使うべきではなく、以下のような @extend の使い方は適していません(@mixin の方が適しています)。

Sass (.scss)
/* @extend が適さない例 */
%clearfix {
  &::after {
    display: block;
    clear: both;
    content: "";
  }
}

.wrapper {
  @extend %clearfix;
  //その他のスタイルの設定
}

.header {
  @extend %clearfix;
  //その他のスタイルの設定
}

.nav {
  @extend %clearfix;
  //その他のスタイルの設定
}

.card {
  @extend %clearfix;
  //その他のスタイルの設定
}

.list {
  @extend %clearfix;
  //その他のスタイルの設定
}

・・・

参考サイト:現場で役立つ実践Sass(4)MixinとExtendの使いどころ

@extend の制限事項

許可されていないセレクター

@extend は単純なセレクター(.info や a などの個々のセレクター)のみで使用できます。

以下の例のような合成セレクタ(compound selector)や複合セレクタ(complex selector)を @extend しようとするとエラーになります。

Sass (.scss)
.alert {
  @extend .message.info; /* 合成セレクタは使えない */
  /* Error: compound selectors may no longer be extended.
  Consider `@extend .message, .info` instead. */

  @extend .main .info; /* 複合セレクタは使えない */
  /* Error: complex selectors may not be extended. */
}

Sass: @extend/Limitations

@media 内での @extend

@media 内では @extend は使用できません。以下のように記述すると「You may not @extend selectors across media queries.」のようなエラーとなり、コンパイルされません。

Sass (.scss)
%foo {
  border: 1px solid #999;
  padding: 10px;
  background: #EEE;
}

@media screen and (min-width:960px){
  .bar {
    @extend %foo; /* エラーになる */
  }
}

@media 内で使用するには、@media 内に継承したいセレクタを記述します。

Sass (.scss)
@media screen and (min-width:960px){
  %foo {
    border: 1px solid #999;
    padding: 10px;
    background: #EEE;
  }
  .bar {
    @extend %foo;
  }
}
コンパイルして出力される CSS
@media screen and (min-width: 960px) {
  .bar {
    border: 1px solid #999;
    padding: 10px;
    background: #EEE;
  }
}

制御構文(条件分岐・繰り返し)

Sassでは、条件分岐や繰り返し処理のための以下のような構文をサポートしています。

制御構文 説明
@if 条件分岐。ブロックを評価するかどうかを制御します。
@each 繰り返し処理。リスト内の各要素またはマップ内の各ペアのブロックを評価します。
@for 繰り返し処理。ブロックを特定の回数評価します。
@while 繰り返し処理。特定の条件が満たされるまでブロックを評価します。

@if や @else を使った条件分岐

@if は指定された式(条件)が true の場合に記述されているブロックを評価(実行・適用)します。

式とは値を返すもののことで、具体的には値や変数、演算子、関数、またはそれらの組み合わせで、通常、true または false のいずれかを返します。

ブロックを評価するとは、ブロックに記述されている Sass や CSS の内容を適用することです。

@if 式 {
  適用するスタイルなどの記述(ブロック)
}

@else を使って、式が条件に合わない(false の)場合の処理を設定することもできます。

@if 式 {
  true の場合に適用する記述(ブロック)
}@else {
  false の場合に適用する記述(ブロック)
}

@else if を使って別の条件(式)を追加することもできます。

@if 式1 {
  式1が true の場合に適用するブロック
}@else if 式2 {
  式1が false で、式2が true の場合に適用するブロック
}@else {
  式1及び式2が false の場合に適用するブロック
}

Sass: @if and @else

以下は変数 $useBGC (式)が true の場合は、ブロックに記述されたスタイル(background-color: xxxx)が適用され、コンパイルする際に出力されます。

$useBGC が false の場合は適用されないため出力されません。

Sass (.scss)
$useBGC: true;

.foo {
  @if $useBGC {
    background-color: blue; /* $useBGC は true なので適用される */
  }
  font-size: 14px;
}

$useBGC: false;

.bar {
  @if $useBGC {
    background-color:green; /* $useBGC は false なので適用されない */
  }
  font-size: 16px;
}
コンパイルして出力される CSS
.foo {
  background-color: blue;
  font-size: 14px;
}

.bar {
  font-size: 16px;
}

以下はミックスインで @if を使う例です。

この例のミックスインでは、3番目の引数 $active にデフォルト値 null が設定されているので、呼び出しの際に3番目の引数を省略すると、デフォルト値の null が適用されます。

Sass では null は false と判定されるので、呼び出しの際に3番目の引数を省略すると7行目の $active は false と判定され7〜12行目のブロックは適用されません。

3番目の引数に何らかの値が指定されていれば、7行目の $active は true と判定され7〜12行目のブロックが適用されます。

※ Sass では false と null のみが false と判定され、その他は全て true と判定されます(空文字列や空のリスト、数字のゼロも true)。

Sass (.scss)
@mixin link-color($normal, $hover, $active: null){
  color: $normal;
  &:hover {
    color: $hover;
    text-decoration: none;
  }
  @if $active { /* $active が true の場合はこのブロックが適用される */
    &:active {
      color: $active;
      text-decoration: none;
    }
  }
}

.foo a {
  @include link-color(green, darkgreen); /* 3番目の引数を省略($active は null) */
}

.bar a {
  @include link-color(blue, darkblue, lightblue);
}
コンパイルして出力される CSS
.foo a {
  color: green;
}
.foo a:hover {
  color: darkgreen;
  text-decoration: none;
}

.bar a {
  color: blue;
}
.bar a:hover {
  color: darkblue;
  text-decoration: none;
}
.bar a:active {  /* $active は true と判定される */
  color: lightblue;
  text-decoration: none;
}

@else if や @else を組み合わせることで条件を増やすことが可能です。

Sass (.scss)
$type: tree;

p {
  @if $type == ocean {
    color: blue;
  } @else if $type == fire {
    color: red;
  } @else if $type == tree {
    color: green;
  } @else {
    color: black;
  }
}

この例の場合、$type: tree; と宣言されているので、式「$type == tree」が true になり、以下のようにコンパイルされます。

コンパイルして出力される CSS
p {
  color: green;
}

「==」は等しいという意味の等値演算子です。

以下は、@if で使える等値演算子関係演算子(比較演算子)です。

@if で使える等値演算子と比較演算子
演算子 説明
A==B AとBは等しい
A!=B AとBは等しくない
A>B AはBより大きい
A<B AはBより小さい
A>=B AはB以上
A<=B AはB以下

式ではブール演算子も使用できます。

@each リストやマップの繰り返し処理

@each を使用すると、リストの各要素やマップの各ペアを順番に処理することができます。

リスト

以下はリストで @each を使う書式です。

Sass (.scss)
@each $変数名 in リスト {
  適用するスタイルなどの記述(ブロック)
}

リストの各要素は順番に指定された変数($変数名)に割り当てられ、ブロックが評価されて記述されているスタイルなどが適用されます。

以下はリストの各要素を使ってセレクタ .icon-#{$size} とプロパティの値 $size を設定する例です。

セレクタに変数を直接記述するとエラーになるのでインターポレーションを使います。

Sass (.scss)
$sizes: 40px, 50px, 80px;

@each $size in $sizes {
  .icon-#{$size} {
    font-size: $size;
    height: $size;
    width: $size;
  }
}

リスト($sizes)の各要素(40px, 50px, 80px)は変数 $size に順番に割り当てられ、その値を使ってスタイルのセレクタ名とプロパティの値に適用されます。

コンパイルして出力される CSS
.icon-40px {
  font-size: 40px;
  height: 40px;
  width: 40px;
}

.icon-50px {
  font-size: 50px;
  height: 50px;
  width: 50px;
}

.icon-80px {
  font-size: 80px;
  height: 80px;
  width: 80px;
}

以下はリストの各要素の値をセレクタ(クラス名)と画像の URL に使って、クラスごとに異なる背景画像を設定する例です。URL の値に変数を挿入するにはインターポレーションを使います。

Sass (.scss)
$classList: top, about, contact;

@each $class in $classList {
  .#{$class} {
    background-image: url(../images/bg-#{$class}.png);
  }
}
コンパイルして出力される CSS
.top {
  background-image: url(../images/bg-top.png);
}

.about {
  background-image: url(../images/bg-about.png);
}

.contact {
  background-image: url(../images/bg-contact.png);
}

以下は、リストの n 番目の値を取得する list.nth() 関数とリストの中の特定の値のインデックスを返す list.index() 関数を使う例です(以下は マップを使うともっと簡単に記述できます)。

以下のような li と a 要素からなる HTML がある場合

<ul>
  <li class="primary"><a href="main">Main</a></li>
  <li class="secondary"><a href="info">Info</a></li>
  <li class="warning"><a href="warning">Warning</a></li>
</ul>

クラス名と対応する色の値のリストを用意して、@each を使ってクラスごとに文字色を設定します。

Sass (.scss)
@use "sass:list"; /*list モジュールの読み込み*/

$classList: primary, secondary, warning;  /*クラス名のリスト*/
$colorList: #1639D1, #0B8404, #E36707;  /*色の値のリスト*/

ul{
  li{
    @each $class in $classList{
      /* 要素のインデックスを取得して変数 $index に設定*/
      $index: list.index($classList, $class);
      &.#{$class}{
        a{
          /* 取得したインデックスを使って色の値のリストから $index 番目の色を取得*/
          color: list.nth($colorList, $index);
          text-decoration: none;
        }
      }
    }
  }
}
コンパイルして出力される CSS
ul li.primary a {
  color: #1639D1;
  text-decoration: none;
}
ul li.secondary a {
  color: #0B8404;
  text-decoration: none;
}
ul li.warning a {
  color: #E36707;
  text-decoration: none;
}
マップ

マップの各要素(キーと値)に対しても @each を使って反復処理ができます。以下が書式です。

Sass (.scss)
@each $キーの変数名, $値の変数名 in マップ {
  適用するスタイルなどの記述(ブロック)
}

マップの各キーと値のペアは順番に指定された変数($キーの変数名, $値の変数名)に割り当てられ、ブロックが評価されて記述されているスタイルなどが適用されます。

前述の例は、マップを利用すると簡単に記述できます。

Sass (.scss)
/*クラス名と色のマップ*/
$colorMap: (
  primary:#1639D1,
  secondary:#0B8404,
  warning:#E36707
);

ul{
  li{
    /*キーと値をそれぞれ変数 $class, $color に受け取る*/
    @each $class, $color in $colorMap{
      &.#{$class}{
        a{
          color: $color;
          text-decoration: none;
        }
      }
    }
  }
}
コンパイルして出力される CSS
ul li.primary a {
  color: #1639D1;
  text-decoration: none;
}
ul li.secondary a {
  color: #0B8404;
  text-decoration: none;
}
ul li.warning a {
  color: #E36707;
  text-decoration: none;
}

以下は基準となるスペースの値を設定して、それを元に複数のスペースの値を記述したマップを使って、マージンとパディングのクラスを作成する例です。

除算にスラッシュを使うのは非推奨なので math モジュールを読み込んで math.div() で除算をします。

Sass (.scss)
@use "sass:math"; /* math モジュールの読み込み */

$spacer: 1rem; /* 基準となる値を設定 */

/* スペースを表すマップ */
$spacers: (
  0: 0,
  1: math.div($spacer, 4),
  2: math.div($spacer, 2),
  3: $spacer,
  4: $spacer * 1.5,
  5: $spacer * 3,
);

/* マージンとパディングのクラスを作成 */
@each $key, $val in $spacers {
  .m-#{$key} {
    margin: $val;
  }
  .p-#{$key} {
    padding: $val;
  }
}

この例の場合は、除算の代わりに乗算を使用するほうが math モジュールも不要なので簡単です。

Sass (.scss)
$spacer: 1rem; /* 基準となる値を設定 */

/* スペースを表すマップ */
$spacers: (
  0: 0,
  1: $spacer * .25,  /* 除算の代わりに乗算を使用 */
  2: $spacer * .5,   /* 除算の代わりに乗算を使用 */
  3: $spacer,
  4: $spacer * 1.5,
  5: $spacer * 3,
);

/* マージンとパディングのクラスを作成 */
@each $key, $val in $spacers {
  .m-#{$key} {
    margin: $val;
  }
  .p-#{$key} {
    padding: $val;
  }
}
コンパイルして出力される CSS
.m-0 {
  margin: 0;
}
.p-0 {
  padding: 0;
}
.m-1 {
  margin: 0.25rem;
}
.p-1 {
  padding: 0.25rem;
}
.m-2 {
  margin: 0.5rem;
}
・・・中略・・・
.p-4 {
  padding: 1.5rem;
}
.m-5 {
  margin: 3rem;
}
.p-5 {
  padding: 3rem;
}
分割代入 Destructuring

リストのリスト(要素がリストから成るリスト)の場合は、以下のように記述することで、要素のリストの各値に変数を自動的に割り当てることができます。

Sass (.scss)
@each $各値の変数名, ・・・  in リストのリスト {
  適用するスタイルなどの記述(ブロック)
}

Sass (.scss)
/* リストのリスト */
$buttons:
  "primary" #0739C1 0.25rem,  //リストの要素もリスト
  "secondary" #037711 0.25rem,
  "warning" #D96304 0;

/*内部のリストの要素の各値は変数に割り当てられる*/
@each $name, $bg-color, $radius in $buttons {
  .btn-#{$name} {
    display: inline-block;
    padding: 0.5rem 1rem;
    color: #fff;
    background-color: $bg-color;
    border-radius: $radius;
  }
}
コンパイルして出力される CSS
.btn-primary {
  display: inline-block;
  padding: 0.5rem 1rem;
  color: #fff;
  background-color: #0739C1;
  border-radius: 0.25rem;
}

.btn-secondary {
  display: inline-block;
  padding: 0.5rem 1rem;
  color: #fff;
  background-color: #037711;
  border-radius: 0.25rem;
}

.btn-warning {
  display: inline-block;
  padding: 0.5rem 1rem;
  color: #fff;
  background-color: #D96304;
  border-radius: 0;
}

Sass: @each/Destructuring

@for を使った繰り返し処理

@for は、あらかじめ指定された回数だけ繰り返し処理を実行します。

繰り返しの処理は、from で指定した「開始の番号」から through または to で指定した「終了の番号」まで値を1ずつ増やし(または減らし)ながら行われます。途中の各番号は、指定された変数名に割り当てられます。

@for には以下の2つの構文があります。

@for ~ through

指定した終了の番号を含んで繰り返し処理

Sass (.scss)
@for $変数名 from 開始の番号 through 終了の番号 {
  適用するスタイルなどの記述(ブロック)
}

@for ~ to

指定した終了の番号を含まずに繰り返し処理

Sass (.scss)
@for $変数名 from 開始の番号 to 終了の番号 {
  適用するスタイルなどの記述(ブロック)
}

以下は @for ~ through の例です。「through」なので、1,2,3 がカウンタ変数「$i」に代入されて処理が実行されます。

カウンタ変数の名前は任意に付けることができます。また、クラス名(セレクタ)にもインターポレーションを使って、カウンタ変数の値を利用しています。

Sass (.scss)
@for $i from 1 through 3 {
  .item-#{$i} { width: 2em * $i; }
}
コンパイルして出力される CSS
.item-1 {
  width: 2em;
}
.item-2 {
  width: 4em;
}
.item-3 {
  width: 6em;
}

カウンタ変数は1ずつ増加(または減少)しますが、以下のように演算を利用することにより10ずつ増やす等が可能です。以下は @for ~ to の例です。

Sass (.scss)
@for $value from 1 to 5 {
  .mt-#{$value * 10} {
    margin-top: 10px * $value;
  }
}

「to」なので、1,2,3,4 がカウンタ変数「$value」に代入されて処理が実行されます(5は含まれない)。

コンパイルして出力される CSS
.mt-10 {
  margin-top: 10px;
}
.mt-20 {
  margin-top: 20px;
}
.mt-30 {
  margin-top: 30px;
}
.mt-40 {
  margin-top: 40px;
}

@for と list.append()

@for と list.append() を使うとリストに規則性を持った値を任意の数だけ追加することができます。

Sass (.scss)
@use "sass:list"; /* list モジュールの読み込み */

$new-list: (); /* 空のリストを作成 */

@for $i from 1 through 5 {
  /* リストに値を追加 */
  $new-list: list.append($new-list, $i * 10 + px, $separator: comma);
}

@debug $new-list; /* 10px, 20px, 30px, 40px, 50px */

以下は3D のように見せるテキストシャドウのミックスインを作成する例です。

引数のリスト($args)を定義して、$repeat の値が1より大きければ、@for と list.append() を使って引数のリストに異なるオフセットのシャドウを追加しています。

以下の引数の定義(7行目)では、最後にカンマを付けないとスペース区切りのリストとして扱われてしまいます。

また、シャドウの色は color.scale() を使って明るさを調整しています。

Sass (.scss)
@use "sass:color";  /* color モジュールの読み込み */
@use "sass:list";  /* list モジュールの読み込み */

/* mixin の定義 */
@mixin txt-shadow-3d($color: #999, $lightness: -30%, $opacity: 70%, $repeat:5) {
  /* 引数のリスト(最後にカンマを付ける) */
  $args: 1px 1px $color,;

  @if $repeat > 1 {
    @for $i from 2 through $repeat {
      $args: list.append($args, $i + px $i + px color.scale($color, $lightness: $lightness, $alpha: $opacity), $separator: comma);
    }
  }
  color: $color;
  text-shadow: $args;
}

/* mixin の呼び出し */
.foo {
  font-size: 40px;
  font-weight: bold;
  @include txt-shadow-3d();
}

.bar {
  font-size: 50px;
  @include txt-shadow-3d($color: #EF787A, $lightness: -50%);
}
コンパイルして出力される CSS
.foo {
  font-size: 40px;
  font-weight: bold;
  color: #999;
  text-shadow: 1px 1px #999, 2px 2px #6b6b6b, 3px 3px #6b6b6b, 4px 4px #6b6b6b, 5px 5px #6b6b6b;
}

.bar {
  font-size: 50px;
  color: #EF787A;
  text-shadow: 1px 1px #EF787A, 2px 2px #a01315, 3px 3px #a01315, 4px 4px #a01315, 5px 5px #a01315;
}

関連項目:任意の数のカラーストップを追加できるグラデーションのミックスイン

Sass: @for

@while を使った繰り返し

@while は、与えられた条件が true(真)である間、ループを繰り返します。以下が書式です。

Sass (.scss)
@while 繰り返しを継続する条件 {
  適用するスタイルなどの記述
  繰り返しの条件を更新(必要に応じて)
}

@while では、「繰り返しを継続する条件」がどこかの時点で false(偽)になるように繰り返しの条件を設定します。

以下は前述の例(@for ~ to)を @while で記述した例です。

Sass (.scss)
$value: 10;

@while $value < 50 {
  .mt-#{$value} {
    margin-top: $value + px;
  }
  $value: $value + 10;
}

$value は10ずつ増加して、50に達すると終了します。

コンパイルして出力される CSS
.mt-10 {
  margin-top: 10px;
}
.mt-20 {
  margin-top: 20px;
}
.mt-30 {
  margin-top: 30px;
}
.mt-40 {
  margin-top: 40px;
}

可能であれば @each または @for を使用

@while の代わりに @each または @for で記述することが可能な場合はそれらを使用することが推奨されています。理由としてはコードを見る場合に処理内容がより明確であり、多くの場合、コンパイルも高速なためとのことです。

Sass: @while

関数 ビルトインモジュール

関数とは、定められた一連の処理(機能)を定義して名前を付けたもので、その関数を呼び出すことで一連の処理が実行される仕組みになっています。

Dart Sass からの変更点

Dart Sass からは今までの Sass 関数の使用は推奨されておらず、最終的には非推奨になるようです。

今までのグローバル関数は「ビルトインモジュール」となり、各モジュールを読み込んで使用します。

但し、if() 関数や rgb()、hsl() などは新しいモジュールシステムでもグローバル関数として使用でき、これからも非推奨になることはなく引き続き使用できます。

Sass には、便利な関数を含む多くのビルトイン(組み込み)モジュールが用意されています。

これらのモジュールは、他のユーザー定義のスタイルシートと同じように @use ルールを使用してロードでき、それらの関数は他のモジュールメンバーと同じように呼び出すことができます。

すべてのビルトインモジュールの URL は sass: で始まり、それらが Sass の一部であることを示します。

以下は Sass の提供するビルトインモジュールです。

モジュール 含まれる関数
sass:math 数値関連の関数
sass:string 文字列関連の関数
sass:color 色関連の関数
sass:list リスト関連の関数
sass:map マップ関連の関数
sass:selector セレクタを操作する関数
sass:meta Sass の内部動作に関連する関数

Sass: Built-In Modules

グローバル関数

if() 関数や rgb()、hsl() などは新しいモジュールシステムでもグローバル関数として使用できます。

Sass: Global Functions

if() 関数

以下が if() 関数の構文です。

if() 関数は第1引数の条件式($condition)が true の場合は第2引数の値($if-true)を返し、 false の場合は第3引数の値($if-false)を返します。

if($condition, $if-true, $if-false);
  • $condition:条件式
  • $if-true:条件式が true (真)の場合に返される値
  • $if-false:条件式が false (偽)の場合に返される値

以下のコードの場合、

Sass (.scss)
$width: 200px;

.foo  {
  @if($width > 300px) {
    padding: 10px;
  } @else {
    padding: 5px;
  }
}

if() 関数を使うと簡潔に書くことができます。

Sass (.scss)
$width: 200px;

.foo  {
  padding: if($width > 300px, 10px, 5px);
}
コンパイルして出力される CSS
.foo {
  padding: 5px;
}

以下は変数 $width が存在すれば、その値を使用し、存在しなければ 100% を適用する例です。

meta.variable-exists() は指定された変数が現在のスコープに存在すれば true を、存在しなければ false を返す関数です。※引数には $ なしの変数名を指定します。

Sass (.scss)
@use "sass:meta"; /* meta モジュールの読み込み */

.foo  {
  width: if(meta.variable-exists(width), $width, 100%);
}

この例の場合、変数 $width は定義されていないので、100% が適用されます。

コンパイルして出力される CSS
.foo {
  width: 100%;
}
rgb() と rgba()

rgb() は RGB の各チャネルを0から255の単位なしまたは0%から100%のパーセンテージで指定した RGB 値を16進数の RGB 値に変換する関数です。

rgb() の書式
rgb($red $green $blue)
Sass (.scss)
.foo {
  color: rgb(118, 157, 243); /* 0から255の単位なしで指定 */
}

.bar {
  color: rgb(18%, 25%, 32%); /* 0%から100%のパーセンテージで指定 */
}
コンパイルして出力される CSS
.foo {
  color: #769df3;
}

.bar {
  color: #2e4052;
}

rgba()

rgba() は指定された RGBA 値を10進数の RGBA 値に変換する関数です。

rgba() の書式
rgba($red, $green, $blue, $alpha) /* RGBの各チャンネルと透過度を指定 */
rgba($color, $alpha)  /* 16進数の RGB 値やカラーキーワードと透過度を指定 */
  • $red, $green, $blue:各チャネルを0〜255の単位なし、または0%〜100%のパーセンテージで指定
  • $alpha(透過度):0〜1の単位なし、または0%〜100%のパーセンテージで指定
  • $color:16進数の RGB 値やカラーキーワード
Sass (.scss)
.foo {
  color: rgba(10%, 20%, 30%, 0.5); /* パーセンテージで指定 */
}
.bar {
  color: rgba(#769df3, 0.7); /* 16進数の RGB 値で指定 */
}
.baz {
  color: rgba(lightblue, 0.9); /* カラーキーワードで指定 */
}
コンパイルして出力される CSS
.foo {
  color: rgba(26, 51, 77, 0.5);
}
.bar {
  color: rgba(118, 157, 243, 0.7);
}
.baz {
  color: rgba(173, 216, 230, 0.9);
}

CSS の rgba() は16進数の RGB 値やカラーキーワードを指定することができませんが、Sass の rgba() は第1引数に16進数の RGB 値やカラーキーワードを指定することができます。

Sass (.scss)
$my-color: #038F34;

div {
  background-color: rgba($my-color, 0.5);
}
コンパイルして出力される CSS
div {
  background-color: rgba(3, 143, 52, 0.5);
}

$alpha を省略するか、$alpha に1または100%を指定すると rgb() 関数と同様、16進数の RGB 値に変換されます。

Sass (.scss)
.foo {
  color: rgba(118, 157, 243);  /* $alpha を省略 */
}
.bar {
  color: rgba(118, 157, 243, 1);  /* $alpha に1または100%を指定 */
}
.baz {
  color: rgba(#769df3, 1);  /* $alpha に1または100%を指定 */
}

コンパイルして出力される CSS
.foo {
  color: #769df3;
}
.bar {
  color: #769df3;
}
.baz {
  color: #769df3;
}
hsl() と hsla()

hsl() は HSL 形式の値を16進数の RGB 値に変換する関数です。

hsl() の書式
hsl($hue $saturation $lightness)
hsl($hue, $saturation, $lightness)
  • $hue(色相):0deg から 360deg の数値で指定(単位は省略可能)
  • $saturation(彩度):0%から100%のパーセンテージで指定(%を省略するのは非推奨)
  • $lightness(輝度):0%から100%のパーセンテージで指定(%を省略するのは非推奨)

以下はいずれも同じ結果になります。

Sass (.scss)
.foo {
  color: hsl(210deg 100% 20%); /* スペース区切り */
}
.bar {
  color: hsl(210deg, 100%, 20%); /* カンマ区切り */
}
.baz {
  color: hsl(210 100% 20%); /* $hue の単位を省略 */
}
コンパイルして出力される CSS
.foo {
  color: #003366;
}
.bar {
  color: #003366;
}
.baz {
  color: #003366;
}

hsla()

hsla() は HSLA 形式の値を RGBA 値に変換する関数です。

hsla() の書式
hsla($hue, $saturation, $lightness, $alpha)
  • $hue(色相):0deg から 360deg の数値で指定(単位は省略可能)
  • $saturation(彩度):0%から100%のパーセンテージで指定(%を省略するのは非推奨)
  • $lightness(輝度):0%から100%のパーセンテージで指定(%を省略するのは非推奨)
  • $alpha(透過度):0から1の単位なし、または0%から100%のパーセンテージで指定

$alpha を指定する場合は、カンマ区切りで指定する必要があります。

Sass (.scss)
.foo {
  color: hsla(210deg, 100%, 20%, 70%);
}
.bar {
  color: hsla(210, 100%, 20%, 0.7);
}
コンパイルして出力される CSS
.foo {
  color: rgba(0, 51, 102, 0.7);
}

.bar {
  color: rgba(0, 51, 102, 0.7);
}

$alpha を省略するか、$alpha に1または100%を指定すると hsl() 関数と同様、16進数の RGB 値に変換されます。

Sass (.scss)
.foo {
  color: hsla(210deg, 100%, 20%); /* $alpha を省略(この場合はカンマを省略可能) */
}
.bar {
  color: hsla(210, 100%, 20%, 1);  /* $alpha に1を指定 */
}
.baz {
  color: hsla(210, 100%, 20%, 100%);  /* $alpha に100%を指定 */
}
コンパイルして出力される CSS
.foo {
  color: #003366;
}
.bar {
  color: #003366;
}
.baz {
  color: #003366;
}

sass:math 数値関連の関数

数値や計算、単位に関連する関数や変数は sass:math モジュールに含まれています。

sass:math モジュールにある関数の一部
関数 意味
math.div($n1, $n2) 除算($n1 ÷ $n2) ※ math.div(100px, 5px) → 20
math.round($number) 小数点以下を四捨五入 math.round(10.6px) → 11px
math.ceil($number) 小数点以下を切り上げ math.ceil(10.4px) → 11px
math.floor($number) 小数点以下を切捨て math.floor(10.6px) → 10px
math.clamp($min, $number, $max) $numberを$minから$maxの範囲に制限 math.clamp(-1, 5, 1) → 1
math.abs($number) 絶対値を返す math.abs(-10px) → 10px
math.min($numbers…) 最小の数値を返す math.min(5em, 3em, 4em) → 3em
math.max($numbers…) 最大の数値を返す math.max(5em, 3em, 4em) → 5em
math.unit($number) 値の単位を返す math.unit(100px) → "px"
math.is-unitless($number) 単位がついていないかを返す math.is-unitless(100px) → false
math.compatible($num1, $num2) $num1と$num2の単位に互換性があるかどうかを返す math.compatible(100px, 3em) → false
math.percentage($number) パーセント形式に変換 math.percentage(math.div(10px, 5px)) → 200%
math.random($limit: null) 乱数を生成 math.random(1000) → 703(乱数)

※Dart Sass ではスラッシュ(/)を使った除算(割り算)は非推奨(将来的には廃止)なので、除算は math.div() を使用します。

上記関数を使用するには @use を使って sass:math モジュールを読み込む必要があります。

Sass (.scss)
@use "sass:math"; /* sass:math モジュールの読み込み */

$width: 100%;

div {
  width: math.div($width, 3);  /* 割り算 */
}

.foo {
  width: ceil(math.div($width, 3)); /* 切り上げ */
}

.bar {
  width: floor(math.div($width, 3)); /* 切捨て */
}

.baz {
  width: round(math.div($width, 3)); /* 四捨五入 */
}
コンパイルして出力される CSS
div {
  width: 33.3333333333%;
}

.foo {
  width: 34%;
}

.bar {
  width: 33%;
}

.baz {
  width: 33%;
}

単位が付いていないかを確認

math.is-unitless() は値に単位がついていないかどうかを調べ、付いていなければ true を、付いていれば false を返します。

Sass (.scss)
math.is-unitless($number)
Sass (.scss)
@use "sass:math"; /* sass:math モジュールの読み込み */

$width: 400;

/* 変数の値に単位がついていない場合は付ける */
@if(math.is-unitless($width)) {
  $width: $width + "px";
}

.foo {
  width: $width ;
}
コンパイルして出力される CSS
.foo {
  width: "400px";
}

単位に互換性があるかどうか

math.compatible() は2つの値の単位に互換性があるかどうかを真偽値で返します。

true を返す(互換性がある)場合、$number1 と $number2 を安全に加算、減算、および比較できます。 そうでない場合はエラーになります。

Sass (.scss)
math.compatible($number1, $number2)

Sass 関数(グローバル関数)では comparable() と名前が異なっていましたが、math モジュールでは compatible に変更されています。

Sass (.scss)
@use "sass:math";

@debug math.compatible(2px, 1px); // true
@debug math.compatible(100px, 3em); // false
@debug math.compatible(10cm, 3mm); // true

パーセント形式に変換

math.percentage() は値(通常は0から1までの小数)をパーセンテージに変換します。

Sass (.scss)
math.percentage($number)

この関数は $number * 100% と同じことです。

Sass (.scss)
@use "sass:math";

@debug math.percentage(0.2); // 20%
@debug math.percentage(math.div(100px, 50px)); // 200%

@debug 0.2 * 100%; // 20%
@debug math.div(100px, 50px) * 100%; // 200%

乱数を生成

math.random()はデフォルト($limit が null)では0から1までのランダムな10桁の小数を返し、$limit が1以上の場合、1から $limit までのランダムな整数を返します。

Sass (.scss)
math.random($limit: null)
Sass (.scss)
@use "sass:math";

@debug math.random(); // 0.2928238498
@debug math.random(); // 0.5194162379
@debug math.random(10); // 2
@debug math.random(10000); // 2063

Sass: sass:math

sass:color 色関連の関数

色関連の関数は sass:color モジュールに含まれています。

但し、値や形式を変換する rgba()hsla() はグローバル関数として使えます。

以下は色を操作する関数の一部抜粋です。

今までの Sass 関数の darken() や lighten()、desaturate() などは color.scale() や color.adjust() を使って書き換える(代用する)ことができます。

関数 意味 置き換え可能な関数
color.adjust() 色のプロパティの値を増減します adjust-hue()、darken()、lighten()、desaturate()、saturate()
color.scale() 色のプロパティの値を流動的にスケーリングします darken()、lighten()、desaturate()、saturate()
color.change() 色のプロパティの値を変更します
color.mix() 2つの色の混合色を作成します

置き換え可能な関数

上記表の「置き換え可能な関数」に記載されている関数は以下のように書き換えることができます。

関数 置き換え方法
adjust-hue() adjust-hue($color, $amount) → color.adjust($color, $hue: $amount)
darken() darken($color, $amount) → color.adjust($color, $lightness: -$amount) 同じこと
darken($color, $amount) → color.scale($color, $lightness: -$amount) ※ 推奨
lighten() lighten($color, $amount) → adjust($color, $lightness: $amount) 同じこと
lighten($color, $amount) → scale($color, $lightness: $amount) ※ 推奨
desaturate() desaturate($color, $amount) → color.adjust($color, $saturation: -$amount) 同じこと
desaturate($color, $amount) → color.scale($color, $saturation: -$amount) ※ 推奨
saturate() saturate($color, $amount) → color.adjust($color, $saturation: $amount) 同じこと
saturate($color, $amount) → color.scale($color, $saturation: $amount) ※ 推奨

例えば、既存の動作を維持する必要がある場合などは darken($color, $amount) は color.adjust($color, $lightness: -$amount) と書き換えることができます。

但し、color.adjust() は darken() 同様、指定された量を単純に増減するので、例えば一定の値以下になると真っ黒(black)になってしまい、必ずしも良い方法とは言えません。

color.scale() は最大値と最小値を考慮して増減するため、真っ黒や真っ白にはなりません。

Sass (.scss)
@use "sass:color"; /* sass:color モジュールの読み込み */

$color: #038F34;
$amount: 20%;

.foo {
  background-color: darken($color, $amount);
}
.bar {
  background-color: color.adjust($color, $lightness:  -($amount));
}
.baz {
  background-color: color.scale($color, $lightness: -($amount));
}
.qux {
  background-color: color.change($color, $lightness: calc(color.lightness($color) - $amount));
}
コンパイルして出力される CSS
.foo {
  background-color: #012b10;  /* darken() */
}
.bar {
  background-color: #012b10;  /* color.adjust() */
}
.baz {
  background-color: #02722a;  /* color.scale() */
}
.qux {
  background-color: #012b10;  /* color.change() */
}

#038F34#012b10#02722a

以下は増減する値を 20% から 30% に変更した場合のコンパイル結果です。

この例の場合、darken() と color.adjust() は真っ黒(black)になり、 color.change() に 30% 変更した値は範囲以外の値となるため、エラーになります。

コンパイルして出力される CSS
.foo {
  background-color: black;  /* darken() */
}
.bar {
  background-color: black;  /* color.adjust() */
}
.baz {
  background-color: #026424;  /* color.scale() */
}

#038F34black#026424

以下は指定した色のプロパティや対応する補色、グレースケールなどを取得する関数です。

関数 説明
color.alpha() アルファチャネル(透過度)の値を0から1までの数値として返します。
color.red() RGB Red チャンネルの値を0から255までの数値として返します。
color.green() RGB Green チャンネルの値を0から255までの数値として返します。
color.blue() RGB Blue チャンネルの値を0から255までの数値として返します。
color.hue() HSL 色相を0度から360度までの値として返します。
color.saturation() HSL 彩度を0%から100%までの値として返します。
color.lightness() HSL 明度を0%から100%の間の値として返します。
color.blackness() HWB カラーモデルの黒色度の値を0%から100%の間の数値として返します。
color.whiteness() HWB カラーモデルの白色度の値を0%から100%の間の数値として返します。
color.complement() RGB 補色を返します。
color.grayscale() 同じ明度の灰色(グレースケール)を返します。

以下は色 #038F34 のプロパティを取得してコンパイル時に @debug でコンソールへ出力する例です。

Sass (.scss)
@use "sass:color";

$color: #038F34;

@debug color.alpha(rgba($color, 50%));  //0.5(透過度)
@debug color.red($color); //3 (Red チャンネル)
@debug color.green($color); //143(Green チャンネル)
@debug color.blue($color); //52(Blue チャンネル)
@debug color.hue($color); // 141deg (色相)
@debug color.saturation($color); //95.8904109589%(彩度)
@debug color.lightness($color); //28.6274509804%(明度)
@debug color.complement($color); //#8f035e(補色)
@debug color.grayscale($color); //#494949(グレースケール)
@debug color.blackness($color); //43.9215686275%(黒色度)
@debug color.whiteness($color); //1.1764705882%(白色度)

参考: HSL カラー

成分 説明
Hue(色相) 0〜359の数値で指定。赤は0(360)、 緑は120、青は240 など
Saturation(彩度) 0%~100%で指定。0%は灰色で、100%に向かって純色になります。
Lightness(輝度) 0%~100%で指定。0%は黒、100%は白となり、純色を表現したい場合は50%を指定。

補色は、指定した Hue の値に 180 を足すことで求められます。

反転した色を返す関数の例

以下は引数に指定された色と値を元に反転させた色を返す独自関数の定義の例です。

Sass (.scss)
@use "sass:color";

@function invert($color, $amount: 100%) {
  $inverse: color.change($color, $hue: color.hue($color) + 180);
  @return color.mix($inverse, $color, $amount);
}

$primary-color: #02B054;

.foo {
  /* 100% が適用され補色になる */
  background-color: invert($primary-color);
}

.bar {
  background-color: invert($primary-color, 80%);
}

.baz {
  /* 0% が適用され元の色のまま */
  background-color: invert($primary-color, 0%);
}

上記では color.change() で Hue(色相)の値に180を加算して補色を取得して、color.mix() で補色と元の色を指定された $amount の割合で混合して返しています。

第2引数の $amount を省略した場合は、100% が適用されるので補色が返され、0%を指定すると元の色が返されます。

コンパイルして出力される CSS
.foo {
  background-color: #b0025e;
}

.bar {
  background-color: #8d255c;
}

.baz {
  background-color: #02b054;
}
color.scale()

color.scale() を使うと指定した色の明度や彩度、透過度などを変更することができます。

color.scale() の書式
color.scale($color,
  $red: null, $green: null, $blue: null,
  $saturation: null, $lightness: null,
  $whiteness: null, $blackness: null,
  $alpha: null)
引数(キーワード) 説明
$color 対象の色
$red RGB Red チャンネル(% で指定)
$green RGB Green チャンネル(% で指定)
$blue RGB Blue チャンネル(% で指定)
$saturation HSL 彩度(% で指定)
$lightness HSL 明度(% で指定)
$whiteness HWB 白色度(% で指定)
$blackness HWB 黒色度(% で指定)
$alpha アルファチャネル/透過度 (% で指定)

第1引数($color)に対象の色を指定し、1つ以上の変更したいプロパティを「キーワード:パーセンテージ」の形式で指定します。複数のプロパティを変更する場合はカンマで区切って指定します。

各キーワード引数は、-100%から100%の値である必要があります。これは対応するプロパティを元の値から最大値(引数が正の場合)または最小値(引数が負の場合)に向かってどれだけ変更する必要があるかを示します。例えば、$lightness: 50% を指定すると(完全に白にすることなく)最大明度に50%近づけることを意味します。

また、RGB プロパティ($red、$green、$blue)と HSL プロパティ($saturation、$lightness)を同時に指定したり、またはそれらのいずれかを HWB プロパティ($whiteness、$blackness)と同時に指定することはできません(エラーになります)。

以下はベースとなる色を受け取り、リンクの色とホバー時及び訪問済みの色をまとめて設定するミックスインの例です。

Sass (.scss)
@use "sass:color";

/* mixin の定義 */
@mixin link-colors($color) {
  color: $color;
  text-decoration: none;
  &:hover {
    /* 明度を変更(20% 明るく) */
    color: color.scale($color, $lightness: 20%);
    text-decoration: underline;
  }
  &:visited {
    /* 彩度を変更(55% 落とす) */
    color: color.scale($color, $saturation: -55%);
  }
}

/* mixin の呼び出し */
.foo a {
  @include link-colors(#029610);
}

コンパイルして出力される CSS
.foo a {
  color: #029610;
  text-decoration: none;
}
.foo a:hover {
  color: #03dd18;
  text-decoration: underline;
}
.foo a:visited {
  color: #2b6d31;
}

Sample Link

関連項目:color.mix() を使ったリンク

以下は @for を使って明度と彩度が5%ずつ異なる色を作成する例です。

Sass (.scss)
@use "sass:color";

$grd-color: #CEFFCA;

@for $i from 1 through 8 {
  .bg-#{$i} {
    background-color: color.scale($grd-color, $lightness: -(5% * $i), $saturation:  -(5% * $i));
  }
}
コンパイルして出力される CSS
.bg-1 {
  background-color: #bafdb5;
}
.bg-2 {
  background-color: #a8faa1;
}

・・・中略・・・

.bg-7 {
  background-color: #5ada4f;
}
.bg-8 {
  background-color: #4dd042;
}
color.adjust()

color.adjust() を使うと指定した色の色相や明度、彩度、透過度などを指定した量(固定量)だけ変更することができます。

color.scale() の方が扱いやすいですが、color.adjust() は色相(Hue)を変更することができます。

color.adjust() の書式
color.adjust($color,
  $red: null, $green: null, $blue: null,
  $hue: null, $saturation: null, $lightness: null,
  $whiteness: null, $blackness: null,
  $alpha: null)
引数(キーワード) 説明
$color 対象の色
$red RGB Red チャンネル(0〜255の単位なしの数値で指定)
$green RGB Green チャンネル(0〜255の単位なしの数値で指定)
$blue RGB Blue チャンネル(0〜255の単位なしの数値で指定)
$hue HSL 色相(単位 deg 付きまたは単位なしで指定)
$saturation HSL 彩度(-100%から100%のパーセンテージで指定)
$lightness HSL 明度(-100%から100%のパーセンテージで指定)
$whiteness HWB 白色度(-100%から100%のパーセンテージで指定)
$blackness HWB 黒色度(-100%から100%のパーセンテージで指定)
$alpha アルファチャネル/透過度(-1から1の数値で指定)

color.scale() 同様、RGB プロパティ($red、$green、$blue)と HSL プロパティ($hue、$saturation、$lightness)を同時に指定したり、またはそれらのいずれかを HWB プロパティ($whiteness、$blackness)と同時に指定することはできません(エラーになります)。

以下は @for を使って色相が60degずつ異なる色を作成する例です。

Sass (.scss)
@use "sass:color";

$base-color: #CEFFCA;

@for $i from 1 through 4 {
  .bg-#{$i} {
    background-color: color.adjust($base-color, $hue: 60 * $i);
  }
}
コンパイルして出力される CSS
.bg-1 {
  background-color: #cafffb;
}
.bg-2 {
  background-color: #caceff;
}
.bg-3 {
  background-color: #fbcaff;
}
.bg-4 {
  background-color: #ffcace;
}

以下は元になる色($color)と指定した値($amount)の分だけ異なる色相の色を使ったグラデーションを作成するのミックスインの例です。

$angle でグラデーションの角度を指定できます。

Sass (.scss)
@use "sass:color";

/* mixin の定義 */
@mixin bg-gradient($angle:180deg, $color: #CEFFCA, $amount: 90) {
  background: linear-gradient($angle, $color, color.adjust($color, $hue: $amount));
}

/* mixin の呼び出し(引数なし) */
.foo {
  @include bg-gradient;
}
/* mixin の呼び出し */
.bar {
  @include bg-gradient($angle:45deg, $color: #ffcace, $amount: 120);
}
コンパイルして出力される CSS
.foo {
  background: linear-gradient(180deg, #CEFFCA, #cae9ff);
}
.bar {
  background: linear-gradient(45deg, #ffcace, #ceffca);
}

以下は任意の数のカラーストップを追加できるようにしたミックスインの例です。

引数のリスト($args)を定義して、$stop の値が1以上であれば、@forlist.append() を使って引数のリストに異なる色相の色を追加しています。

Sass (.scss)
@use "sass:color";
@use "sass:list"; /* list モジュールの読み込み */

/* mixin の定義 */
@mixin bg-gradient2($angle: 180deg, $color: #CEFFCA, $amount: 90, $stop:0) {
  /* 引数のリスト */
  $args: $angle, $color, color.adjust($color, $hue: $amount);

  @if $stop > 0 {
    @for $i from 2 through $stop + 1 {
      $args: list.append($args, color.adjust($color, $hue: $amount * $i), $separator: comma);
    }
  }
  background: linear-gradient($args);
}

/* mixin の呼び出し */
.baz {
  @include bg-gradient2($angle: 90deg, $color: #ffcace, $amount: 60, $stop:3);
}
コンパイルして出力される CSS
.baz {
  background: linear-gradient(90deg, #ffcace, #fffbca, #ceffca, #cafffb, #caceff);
}
color.mix()

color.mix() は指定された2つの色をミックスした色を作成します。

第3引数に指定する $weight と各色の不透明度によって含まれる各色の量が決まります。

color.mix() の書式
color.mix($color1, $color2, $weight: 50%)

$color1、$color2 にはミックスする色(透明度も指定可能)を指定します。

$weight は、0%から100%の値で指定します。$weight の値が大きいほど $color1 を多く使用し、値が小さいほど $color2 を多く使用することを示します。デフォルトは50%です。

例えば 25% と指定すると、$color1 の色の割合が25%で $color2 の色の割合が75%になります。

以下は pink を65%と red を35%で中間色を作成する例です。

Sass (.scss)
@use "sass:color";

.foo {
  background: color.mix(pink, red, 65%);
}
コンパイルして出力される CSS
.foo {
  background: #ff7d84;
}
Pink
Red
#ff7d84

以下は Bootstrap で定義されている色をミックスする関数の例です。

引数に指定された色と割合により、白色及び黒色とミックスする関数をそれぞれ定義しています。

shift-color() では $weight の値が正の値の場合は黒色とミックスする関数を実行した値を返し、負の場合は白色とミックスする関数を実行した値を返します。

以下の場合、shift-color() の呼び出しでは $weight に 30% を指定しているので、指定した色に黒が30%の割合でミックスされます。

Sass (.scss)
@use "sass:color";

/* 白とミックスする関数 */
@function tint-color($color, $weight) {
  @return color.mix(white, $color, $weight);
}

/* 黒とミックスする関数 */
@function shade-color($color, $weight) {
  @return color.mix(black, $color, $weight);
}

/* $weight の値により上記いずれかを実行する関数*/
@function shift-color($color, $weight) {
  /* $weight が正であれば shade-color() を、負の場合は tint-color() を実行 */
  @return if($weight > 0, shade-color($color, $weight), tint-color($color, -$weight));
}

$link-color:            #03850F;
$link-decoration:       none;
$link-shade-percentage: 30%;
$link-hover-color:      shift-color($link-color, $link-shade-percentage);
$link-hover-decoration: underline;

a {
  color: $link-color;
  text-decoration: $link-decoration;
  &:hover {
    color: $link-hover-color;
    text-decoration: $link-hover-decoration;
  }
}
コンパイルして出力される CSS
a {
  color: #03850F;
  text-decoration: none;
}
a:hover {
  color: #025d0b;
  text-decoration: underline;
}

sass:string 文字列関連の関数

文字列関連の関数は sass:string モジュールに含まれており、以下のような関数があります(一部抜粋)。

関数 意味
string.unquote($string) $string の引用符を取り除く
string.quote($string) $string を引用符で囲まれた文字列として返す
string.length($string) $string の長さ(含まれる文字数)を返す
string.to-upper-case($string) 大文字に変換した $string のコピーを返す
string.to-lower-case($string) 小文字に変換した $string のコピーを返す
string.index($string, $substring) $substring の最初に現れる開始位置(インデックス)を返す
string.insert($string, $insert, $index) 指定したインデックスに指定した文字列を挿入したコピーを返す
string.slice($string, $start-at, $end-at) 指定した範囲を取り出す
Sass (.scss)
@use "sass:string";  /* string モジュールの読み込み */

@debug string.unquote("foo");  //foo
@debug string.quote(foo);  //"foo"
@debug string.length("foo");  //3
@debug string.to-upper-case("foo");  //FOO
@debug string.to-lower-case("FOO");  //foo
@debug string.index("Helvetica Neue", "Neue");  //11
@debug string.insert("foo", "X", 3);  //foXo
@debug string.slice("abcd", 2);  //bcd

文字列のインデックス

Sass ではインデックス 1 は、文字列の最初の文字を示します(インデックスが 0 から始まる多くのプログラミング言語とは異なります)。

インデックス -1 は文字列の最後の文字を示し、-2 は最後から2番目の文字を示します。

文字列のインデックス(開始位置)を取得

string.index()は、文字列($string)の中に指定された文字列($substring)が含まれている場合はその最初のインデックス(開始位置)を返します。

文字列($string)に指定された文字列($substring)が含まれていない場合は null を返します。

string.index()
string.index($string, $substring)
Sass (.scss)
@use "sass:string";

@debug string.index("Helvetica Neue", "Helvetica"); // 1
@debug string.index("Helvetica Neue", "Neue"); // 11
@debug string.index("Helvetica Neue", "Mono"); //null

指定した位置に文字列を挿入

string.insert()は、文字列($string)の中の指定した位置($index)に指定した文字列($insert)を挿入する関数です。

string.insert()
string.inser($string, $insert, $index)

第3引数の $index には負の値を指定することができます。その場合、文字列の末尾からの位置になります。

Sass (.scss)
@use "sass:string";

@debug string.insert("Roboto Bold", " Mono", 7); // "Roboto Mono Bold"
@debug string.insert("Roboto Bold", " Mono", -6); // "Roboto Mono Bold"

$index が $string の長さよりも大きい場合、$insert が最後に追加されます。$index が文字列の負の長さよりも小さい場合、$insert が先頭に追加されます。

Sass (.scss)
@use "sass:string";

@debug string.insert("Roboto", " Bold", 100); // "Roboto Bold"
@debug string.insert("Bold", "Roboto ", -100); // "Roboto Bold"

文字列から指定した範囲を取り出す

string.slice()は、文字列($string)から指定した範囲(インデックス $start-at で始まりインデックス $end-at 終わる)を取り出す関数です。

第3引数($end-at)はオプションで、省略すると範囲は末尾までになります。デフォルトの値は -1 です。

string.slice()
string.slice($string, $start-at, $end-at: -1)
Sass (.scss)
@use "sass:string";

@debug string.slice("Helvetica Neue", 11); // "Neue"
@debug string.slice("Helvetica Neue", 1, 3); // "Hel"
@debug string.slice("Helvetica Neue", 1, -6); // "Helvetica"
@debug string.slice("Helvetica Neue", -9, -7); // "tic"

第2引数($start-at)、第3引数($end-at)に負の値を指定すると、末尾からの位置になります。

Sass: sass:string

sass:list リスト関連の関数

リスト関連の関数は sass:list モジュールに含まれており、以下のような関数があります(一部抜粋)。

関数 意味
list.length($list) $list の長さ(項目数)を返す
list.index($list, $value) $list 内の $value のインデックス(位置)を返す
list.nth($list, $n) n番目(インデックス $n)の項目を返す
list.set-nth($list, $n, $value) n番目の要素が $value に置き換えられた $list のコピーを返す
list.join($list1, $list2, $separator: auto) $list1 と $list2 の要素を含む新しいリストを返す
list.append($list, $val, $separator: auto) $list の末尾に $val が追加されたコピーを返す
list.zip($lists...) 指定された複数のリストを一つの多次元リストに統合
list.slash($elements...) スラッシュ区切りのリストを返す

※ Sass ではリストの最初の要素のインデックスは 1 になります。

Immutability

Sassのリストは不変(immutable)で、リストの内容(値)は変更されません。

Sass のリスト関数はすべて、元のリストを変更するのではなく、新しいリストを返します。

要素の位置(インデックス)を取得

list.index() はリスト($list)の中の指定した値($value)の位置を返します。

指定した値がない場合は null を返し、複数回出現する場合は最初に出現したインデックスを返します。

list.index($list, $value)
Sass (.scss)
@use "sass:list";  /* list モジュールの読み込み */

@debug list.index(1px solid red, 1px); // 1
@debug list.index(1px solid red, solid); // 2
@debug list.index(1px solid red, dashed); // null
@debug list.index((width: 10px, height: 20px), (height 20px)); //2

n番目の要素を取得

list.nth() はリストの n 番目の要素を返します。

第2引数に負の値を指定した場合は文字列の末尾からのカウントします。インデックス $n に要素がない場合はエラーをスローします。

list.nth($list, $n)
Sass (.scss)
@use "sass:list";

@debug list.nth(10px 12px 16px, 2); // 12px
@debug list.nth([line1, line2, line3], -1); // line3

$list: foo, bar, baz;
@debug list.nth($list, -2); //bar
@debug list.nth($list, 5); //以下のエラーになる(該当する要素がない)
/*Error: $n: Invalid index 5 for a list with 3 elements.*/

n番目の要素を置き換え

list.set-nth() はインデックス $n の要素を $value に置き換えたリスト($list)のコピーを返します。

$n が負の場合、$list の最後から数えます。インデックス $n に既存の要素がない場合、エラーをスローします。

list.set-nth($list, $n, $value)
Sass (.scss)
@use "sass:list";

@debug list.set-nth(10px 20px 30px, 1, 2em); // 2em 20px 30px
@debug list.set-nth((10px 20px 30px), -1, 8em); // 10px, 20px, 8em

$font: Helvetica, Arial, sans-serif;
@debug list.set-nth($font, 3, Roboto); // Helvetica, Arial, Roboto

リストを結合

list.join() は $list1 の要素と $list2 の要素を含む新しいリストを返します。

list.join($list1, $list2, $separator: auto, $bracketed: auto)

オプションで $separator に区切り文字(comma か space または slash)を指定することができます。

デフォルト(auto)の場合、$list1 にセパレータがあればそれを、なければ $list2 のセパレータが使用されます。但し、両方のリストの項目が1つ以下の場合はスペースが使用されます。

$bracketed が true の場合、返されるリストは角括弧で囲まれます。false の場合、返されるリストには角括弧は付きません。デフォルト(auto)の場合、$list1 が角括弧で囲まれていれば、返されるリストは角括弧で囲まれます。

Sass (.scss)
@use "sass:list";

@debug list.join(10px 20px, 30px 40px); // 10px 20px 30px 40px
@debug list.join((blue, red), (#abc, #def)); // blue, red, #abc, #def
@debug list.join(10px, 20px); // 10px 20px
@debug list.join(10px, 20px, $separator: comma); // 10px, 20px
@debug list.join((blue, red), (#abc, #def), $separator: space); // blue red #abc #def
@debug list.join([10px], 20px); // [10px 20px]
@debug list.join(10px, 20px, $bracketed: true); // [10px 20px]

個々の値は単一要素のリストとしてカウントされるため、list.join() を使ってリストの最後に値を追加することができますが、正しい使い方ではありません。リストに単一の値を追加するには次項の list.append() を使用します。

リストの末尾に値を追加

list.append() はリストの末尾に値を追加します。オプションで $separator に区切り文字(comma か space または slash)を指定することができます。

デフォルト(auto)の場合、返されるリストは $list と同じ区切り文字を使用します。$list に区切り文字がない(リストの項目が1つだけの)場合はスペースが使用されます。

list.append($list, $val, $separator: auto)

list.join() とは異なり、$val がリストの場合、返されるリストにすべての要素が追加されるのではなく、返されるリスト内にネストされます。

Sass (.scss)
@use "sass:list";

@debug list.append(10px 20px, 30px); // 10px 20px 30px
@debug list.append((blue, red), green); // blue, red, green
@debug list.append(10px, 20px, $separator: comma); // 10px, 20px
@debug list.append((blue, red), green, $separator: space); // blue red green
/* リストを追加すると、リスト内にネストされる */
@debug list.append(10px 20px, 30px 40px); // 10px 20px (30px 40px)

以下は要素が1つだけのリストを作成して、要素を追加する例です。

この場合、$box-shadow の要素の後にカンマ(,)がないと、スペース区切りのリストとして扱われてしまいます。

Sass (.scss)
@use "sass:list";

$box-shadow: (10px 5px 5px #8D9EB8,);  /*または 10px 5px 5px #8D9EB8, */
$box-shadow2: 20px 10px 10px #B0F5C9;

.foo {
  box-shadow: list.append($box-shadow, $box-shadow2, comma);
}

.bar{
  box-shadow: $box-shadow;
}
コンパイルして出力される CSS
.foo {
  box-shadow: 10px 5px 5px #8D9EB8, 20px 10px 10px #B0F5C9;
}

.bar {
  box-shadow: 10px 5px 5px #8D9EB8;
}

複数のリストを一つの多次元リストに統合

list.zip() は指定された全てのリストを一つの多次元リスト(サブリストのリストとして)統合します。

list.zip($lists...) 

返されるリストの各要素(サブリスト)には、$lists のその位置にあるすべての要素が含まれています。 返されるリストは、$lists の最短リストと同じ長さになります。

また、返されるリストは常にカンマで区切られ、サブリストは常にスペースで区切られます。

Sass (.scss)
@use "sass:list";

@debug list.zip(10px 50px 100px, short mid long); // 10px short, 50px mid, 100px long
@debug list.zip(10px 50px 100px, short mid); // 10px short, 50px mid

以下は横と縦オフセット、ブラー、及び色のリストからテキストシャドウの値を生成する例です。

Sass (.scss)
@use "sass:list";

$x-c: 0 0 0 0 0;
$y-c: 0 1px 2px 3px 4px;
$blur: 0 0 0 0 1px;
$color: #ccc #c9c #bbb #b9b #aaa;

.foo {
  text-shadow: zip($x-c, $y-c, $blur, $color);
}
コンパイルして出力される CSS
.foo {
  text-shadow: 0 0 0 #ccc, 0 1px 0 #c9c, 0 2px 0 #bbb, 0 3px 0 #b9b, 0 4px 1px #aaa;
}

スラッシュ区切りのリストを返す

list.slash() はスラッシュ区切りのリストを返します。

※ この関数はスラッシュで区切られたリストを作成するための一時的なソリューションです。

現時点ではスラッシュが除算に使用されるため、Sass は古い構文が削除されるまでスラッシュを新しい構文に使用できない状況にあります。最終的(将来的)には、この関数を使わずに 1px / 2px / solid のようにスラッシュで記述できるようになります。

list.slash($elements...) 
Sass (.scss)
@use "sass:list";

@debug list.slash(1px, 50px, 100px); // 1px / 50px / 100px

Sass: sass:list

sass:map マップ関連の関数

マップ関連の関数は sass:map モジュールに含まれており、以下のような関数があります(一部抜粋)。

関数 意味
map.get($map, $key) マップから指定したキーの値を返す
map.has-key($map, $key) 特定のキーがあるかを調べて真偽値を返す
map.keys($map) すべてのキーのカンマ区切りのリストを返す
map.merge($map1, $map2) 2つのマップをマージ
map.remove($map, $keys...) 指定したキーのペアを削除
map.set($map, $key, $value) 指定したキーの値に $value を設定した $map のコピーを返す
map.values($map) すべての値のカンマ区切りのリストを返す

Immutability

リスト同様、Sass のマップは不変(immutable)でマップの内容(値)は変更されません。

Sass のマップ関数はすべて、元のマップを変更するのではなく、新しいマップを返します。

指定したキーの値を取得

map.get() は引数にマップと1つのキーのみを指定した場合は、指定したキーに対応する値を返します。指定したキーが存在しない場合は、null を返します。

map.get($map, $key)
Sass (.scss)
@use "sass:map";  /* map モジュールの読み込み */

$font-weights: ("light": 300, "regular": 400, "medium": 500, "bold": 700);

.foo {
  font-weight: map.get($font-weights, "light");
}
.bar {
  font-weight: map.get($font-weights, "heavy"); /* 存在しないキー */
}
コンパイルして出力される CSS
.foo {
  font-weight: 300;
}
/*.bar は存在しないキーを指定したので null が返りプロパティは書き出されません。*/

複数のキーを渡す

map.get() に複数のキーを渡すと、それらのキーに従って、目的のネストされたマップが検索されます。

map.get($map, $key, $keys...)
Sass (.scss)
@use "sass:map";  /* map モジュールの読み込み */

$fonts: (
  "Helvetica": (
    "weights": (
      "regular": 400,
      "medium": 500,
      "bold": 700
    )
  )
);

.foo {
  font-weight: map.get($fonts, "Helvetica", "weights", "regular");
}
.bar {
  font-weight: map.get($fonts, "Helvetica", "colors"); /* 存在しないキー */
}
コンパイルして出力される CSS
.foo {
  font-weight: 400;
}
/*.bar は存在しないキーを指定したので null が返りプロパティは書き出されません。*/

特定のキーがあるかを調べる

map.has-key() は指定したマップ($map)内に特定のキー($key)があるかどうか調べて、指定したキーが存在すれば true を返し、存在しなければ false を返します。

map.has-key($map, $key)
Sass (.scss)
@use "sass:map";

$font-weights: ("light": 300, "regular": 400, "medium": 500, "bold": 700);

.foo {
  @if map.has-key($font-weights, "light") {
    font-weight: map.get($font-weights, "light");
  } @else {
    font-weight: 400;
  }
}
.bar {
  @if map.has-key($font-weights, "bolder") {
    font-weight: map.get($font-weights, "bolder");
  } @else {
    font-weight: 700;
  }
}
コンパイルして出力される CSS
.foo {
  font-weight: 300; /* "light" は存在するのでその値 */
}
.bar {
  font-weight: 700; /* "bolder" は存在しないので @else の値*/
}

map.get() 同様、map.has-key() に複数のキーを渡すと、それらのキーに従って目的のネストされたマップが検索されます。

map.has-key($map, $key, $keys...)
@use "sass:map";

$fonts: (
  "Helvetica": (
    "weights": (
      "light": 300,
      "regular": 400,
      "medium": 500,
      "bold": 700
    )
  )
);

.foo {
  @if map.has-key($fonts, "Helvetica", "weights", "light") {
    font-weight: map.get($fonts, "Helvetica", "weights", "light");
  } @else {
    font-weight: 400;
  }
}
コンパイルして出力される CSS
.foo {
  font-weight: 300; /* "light" は存在するのでその値 */
}

すべてのキーを取得

map.keys() は指定したマップ内のすべてのキーのカンマ区切りリストを返します。

map.keys($map)
Sass (.scss)
@use "sass:map";

$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.keys($font-weights); /* "regular", "medium", "bold"*/

すべての値を取得

map.values() はマップ内のすべての値のカンマ区切りリストを返します。

map.values($map)
Sass (.scss)
@use "sass:map";

$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.values($font-weights); /* 400, 500, 700 */

2つのマップをマージ

map.merge() は2つのマップからのすべてのキーと値を含む新しいマップを返します。

1つ目のマップのキーと値の後に、2つ目のマップのキーと値が追加されます。それぞれのマップのキー・値の順番は保たれますが、もし同じキーがある場合は2つ目のマップの値で上書きされます。

map.merge($map1, $map2)
Sass (.scss)
@use "sass:map";

$light-weights: ("lightest": 100, "light": 300);
$heavy-weights: ("medium": 500, "bold": 700);

@debug map.merge($light-weights, $heavy-weights);
/*("lightest": 100, "light": 300, "medium": 500, "bold": 700)*/

以下の書式で、$keys が指定された場合は、$keys に従ってマージの対象となるネストされたマップを見つけます。

map.merge($map1, $keys..., $map2)
Sass (.scss)
@use "sass:map";

$fonts: (
  "Helvetica": (
    "weights": (
      "lightest": 100,
      "light": 300
    )
  )
);
$heavy-weights: ("medium": 500, "bold": 700);

@debug map.merge($fonts, "Helvetica", "weights", $heavy-weights);
/*
(
  "Helvetica": (
    "weights": (
      "lightest": 100,
      "light": 300,
      "medium": 500,
      "bold": 700
    )
  )
)
*/

指定したキーのペアを削除

map.remove() は指定したキー($keys…)と対応する値を削除し、新しいマップを返します。複数のキーを指定することが可能です。

指定されたキーに値が関連付けられていない場合、そのキーは無視されます。

map.remove($map, $keys...)
Sass (.scss)
@use "sass:map";

$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.remove($font-weights, "regular"); /* ("medium": 500, "bold": 700) */
@debug map.remove($font-weights, "regular", "bold"); /* ("medium": 500) */
@debug map.remove($font-weights, "bolder");
/* 指定されたキーが存在しない ("regular": 400, "medium": 500, "bold": 700)) */

値を変更(更新)

map.set() は指定したキーの値を更新したマップのコピーを返します。

map.set($map, $key, $value)
Sass (.scss)
@use "sass:map";

$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.set($font-weights, "regular", 300);
// ("regular": 300, "medium": 500, "bold": 700)

以下の書式で、$keys が指定された場合は、$keys に従って更新の対象となるネストされたマップを見つけます。

map.set($map, $keys..., $key, $value)
Sass (.scss)
@use "sass:map";

$fonts: (
  "Helvetica": (
    "weights": (
      "regular": 400,
      "medium": 500,
      "bold": 700
    )
  )
);

@debug map.set($fonts, "Helvetica", "weights", "regular", 300);
/*
(
  "Helvetica": (
    "weights": (
      "regular": 300,
      "medium": 500,
      "bold": 700
    )
  )
)
*/

Sass: sass:map

sass:meta

sass:meta モジュールには Sass の内部動作に関連する関数などが収容されています。 以下は、sass:meta に収容されている関数の一部です。

関数 意味
meta.inspect($value) 文字列表現を返す
meta.type-of($value) 値の型を返す
meta.keywords($args) 可変長引数を取るミックスインや関数に渡された引数をマップにして返す
meta.load-css($url, $with: null) $url で指定されたモジュールをロードして CSS 出力を含める

meta.inspect($value)

meta.inspect() は指定された値の文字列表現を返します(CSS で表現できる値だけでなく、任意の Sass 値の表現を返すため、その戻り値は有効な CSS であるとは限りません)。

meta.inspect($value)

CSS として有効でない値を指定するとコンパイルエラーになってしまいますが、この関数を使うとそのような場合でも処理結果を文字列として出力してくれます(使用例)。

また、インターポレーションは引用符で囲まれた文字列から引用符を削除するため、以下のような場合、引用符を保持するには、meta.inspect() 関数でラップする必要があります。

引用元:Custom Properties/Heads up!

Sass (.scss)
@use "sass:meta";

$font-family-monospace: Menlo, Consolas, "Courier New", monospace;

:root {
  --font-family-monospace: #{meta.inspect($font-family-monospace)};
}
コンパイルして出力される CSS
:root {
  --font-family-monospace: Menlo, Consolas, "Courier New", monospace;
}

meta.inspect() はデバッグを目的としているため、その出力形式は Sass のバージョンまたは実装間で一貫していることが保証されていません。

meta.type-of()

meta.type-of() は受け取った値の型(Type)を返します。Type には以下のようなものがあります。

  • number(数値)
  • string(文字列)
  • color(色)
  • list(リスト)
  • map(マップ)
  • calculation(計算)
  • bool(ブール値)
  • null
  • function(関数)
  • arglist(引数リスト)

将来、新しい値が追加される可能性があります。空の括弧 () は map 関数によって返されたかどうかに応じて、リストまたはマップのいずれかを返す場合があります。

Sass (.scss)
@use "sass:meta";

@debug meta.type-of(10px); // number
@debug meta.type-of(10px 20px 30px); // list
@debug meta.type-of((a:10px, b:20px)); // map
@debug meta.type-of(()); // list
@debug meta.type-of(true); // bool
@debug meta.type-of(green); // color

meta.keywords()

meta.keywords() は可変長引数を取るミックスインや関数に渡されたキーワードを返す関数で、可変長のキーワード引数を取るミックスインや関数で使います。

Sass (.scss)
meta.keywords($args)

可変長のキーワード形式の引数($引数名:値)を meta.keywords() に渡すと、$を含まない引数名と値のマップとして返されます。

以下の場合、ミックスインの引数に渡された引数リスト「$string: #080, $comment: #800, $variable: #60b」は meta.keywords() によりマップ (string: #080, comment: #800, variable: #60b) に変換されて @each に渡されます(10行目)。

Sass (.scss)
@use "sass:meta";

/*可変長のキーワード引数を受け取るミックスインの定義*/
@mixin syntax-colors($args...) {
  /* meta.keywords() の返す値をコンソールへ出力(デバッグ用) */
  @debug meta.keywords($args);
  /* 上記により以下の引数名と値のマップがコンソールへの出力される */
  // (string: #080, comment: #800, variable: #60b)

  @each $name, $color in meta.keywords($args) {
    pre span.stx-#{$name} {
      color: $color;
    }
  }
}

/*ミックスインの呼び出し(引数は $引数名:値 のキーワード形式で指定) */
@include syntax-colors($string: #080, $comment: #800, $variable: #60b);
コンパイルして出力される CSS
pre span.stx-string {
  color: #080;
}

pre span.stx-comment {
  color: #800;
}

pre span.stx-variable {
  color: #60b;
}
meta.load-css()

meta.load-css() ミックスインは $url で指定されたモジュールをロードし、生成された CSS 出力を含めることができます。また、オプションで $with にモジュールの設定用のマップを指定することができます。

このミックスインは @use と似たような機能ですが、コード内のどこでも動的に使用できます。

meta.load-css($url, $with: null) 

以下は style.scss で meta.load-css() を使ってモジュール _code.scss をロードする例です。

├── dark-theme
│   └── _code.scss
└── style.scss

_code.scss では変数 $border-contrast を変更できるように !default フラグを指定してあります。

_code.scss
$border-contrast: false !default;

code {
  background-color: #6b717f;
  color: #d2e1dd;
  @if $border-contrast {
    border-color: #dadbdf;
  }
}

style.scss では @include で meta.load-css() を呼び出し、$url に dark-theme/code を、$with に設定用のマップを指定しています。

※ $with に指定するマップのキーの変数名には $ は付けません。

style.scss
@use "sass:meta";

body.dark {
  @include meta.load-css(
    "dark-theme/code",
    $with: ("border-contrast": true) /* キーには $ は付けない */
  );
}

$with に指定したマップによりロードしたモジュールの変数の値が上書きされ、border-color が出力されています。

コンパイルして出力される CSS
body.dark code {
  background-color: #6b717f;
  color: #d2e1dd;
  border-color: #dadbdf;
}

以下のようにミックスインの呼び出しで、指定する $url に変数を使うこともできます。

style.scss
@use "sass:meta";

$url: "dark-theme/code";

body.dark {
  @include meta.load-css(
    $url,
    $with: ("border-contrast": true)
  );
}

Sass: sass:meta

@function 自作関数の定義

@function を使って、独自の関数を定義することができます。以下が書式です。

独自の関数を定義するには @function で関数の宣言をし、関数名を指定して引数を設定し、@return を使って戻り値を返します。

@function 関数名($引数) {
  // 処理の記述
  @return 戻り値;
}

引数は関数名の後に括弧で囲んで記述します。引数が複数ある場合は、カンマで区切ってリストとして指定します(末尾にカンマを含めることもできます)。引数も変数なので、通常の変数名と同様、名前は $ から始めます。

関数名は任意の名前を付けられますが、Sass や CSS で定義されている関数と同じ名前は使わないほうが無難です。また、関数名はすべての Sass 識別子同様、ハイフンとアンダースコアを同一として扱います。

以下は引数に指定した値を2倍にして返す独自関数 double() の例です。

Sass (.scss)
/* 関数 double() の定義 */
@function double($value) {
  @return $value * 2;
}

.foo {
  width: double(200px) ; /* 関数 double() の呼び出し */
}

定義した関数を呼び出す際には、引数が定義されていれば引数を指定します。引数が複数ある場合は、関数の定義で宣言した引数と同じ数の引数を同じ順番で指定します。

コンパイルして出力される CSS
.foo {
  width: 400px;
}

独自関数の中では、Sass の関数を利用することができます。以下は除算の関数 math.div() を利用して、引数に指定した値を半分(1/2)にして返す独自関数 half() の例です。

Sass (.scss)
@use "sass:math"; /* math.div() を利用するための math モジュールの読み込み */

/* 関数の定義 */
@function half($value) {
  /* Sass の math.div() を利用 */
  @return  math.div($value, 2);
}

.foo {
  width: half(200px) ; /* 関数の呼び出し */
}
コンパイルして出力される CSS
.foo {
  width: 100px;
}

引数のデフォルト値の設定

通常、関数を呼び出す際には、定義で宣言したすべての引数を渡す必要がありますが、デフォルト値(初期値)を定義することにより、引数をオプションにすることができます。

引数のデフォルト値は、変数と同じ書式($引数名 : 値)で記述します。

以下は引数 $color に指定された色と $amount に指定された値を元に反転させた色を返す関数の定義ですが、2番目の引数にデフォルト値を設定しています。

Sass (.scss)
@use "sass:color";

@function invert($color, $amount: 100%) {
  $inverse: color.change($color, $hue: color.hue($color) + 180);
  @return color.mix($inverse, $color, $amount);
}

$primary-color: #02B054;

.foo {
  /*$amount を省略しているので 100% が適用される*/
  background-color: invert($primary-color);
}
.bar {
  background-color: invert($primary-color, 80%);
}
コンパイルして出力される CSS
.foo {
  background-color: #b0025e;
}

.bar {
  background-color: #8d255c;
}

キーワード引数、可変長引数

ミックスインの定義同様、独自関数の定義でもキーワード引数可変長引数(引数リスト)を使用することができます。

有効な加算をする関数の例

以下は Bootstrap で定義されている有効な加算をする関数 add() をモジュールを使って書き換えた例です。

受け取った2つの引数のタイプを meta.type-of() と math.compatible() で確認して安全に加算できる場合は加算を実行して返しています。

そうでなければ if() 関数を使ってデフォルトでは CSS の calc() とインターポレーションを使って返し、第3引数が true でなければ「 $value1 + $value2」として返すようになっています。

Sass (.scss)
@use "sass:math";
@use "sass:string";
@use "sass:meta";

@function add($value1, $value2, $return-calc: true) {
  @if $value1 == null {
    @return $value2;
  }

  @if $value2 == null {
    @return $value1;
  }

  @if meta.type-of($value1) == number and meta.type-of($value2) == number and math.compatible($value1, $value2) {
    @return $value1 + $value2;
  }

  @return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + string.unquote(" + ") + $value2);
}

$padding-y: 0.25rem;
$border-width: 0.1rem;
$border-width2: 2px;

.foo {
  padding-top: add($padding-y, $border-width);
  padding-bottom: add($padding-y, $border-width);
}

.bar {
  padding-top: add($padding-y, $border-width2);
  padding-bottom: add($padding-y, $border-width2);
}
コンパイルして出力される CSS
.foo {
  padding-top: 0.35rem;
  padding-bottom: 0.35rem;
}

.bar {
  padding-top: calc(0.25rem + 2px);
  padding-bottom: calc(0.25rem + 2px);
}

ミックスインの中で独自関数を使う

独自に定義した関数をミックスインの中や他の独自に定義した関数の中で使うことができます。

以下は Bootstrap 5 のブレークポイントのマップとミックスインの抜粋です(グローバル関数ではなくモジュールの関数を使うように書き換えてあります)。@function と @mixin で作成されています。

_variables.scss(Bootstrap 5) ブレークポイントのマップ
$grid-breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px,
  xxl: 1400px
) !default;

引数に指定された $name(キー名)を使ってブレークポイントのマップから最小幅や最大幅を取得する関数などを定義しておき、各ミックスインで利用しています。

_breakpoints.scss(Bootstrap 5) ブレークポイントのミックスイン
@use "sass:map";
@use "sass:list";
@use "variables" as *; /* 名前空間なしで $grid-breakpoints を参照 */

/* $name は $grid-breakpoints のキー */

/*次のブレークポイントの名前を返す関数(最後のブレークポイントの場合はnull)*/
@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map.keys($breakpoints)) {
  /*第2引数をmap.keys()でキーのリストに変換(第3引数)して$nameに対応するインデックスを取得*/
  $n: list.index($breakpoint-names, $name);
  @if not $n {
    @error "breakpoint `#{$name}` not found in `#{$breakpoints}`";
  }
  @return if($n < list.length($breakpoint-names), list.nth($breakpoint-names, $n + 1), null);
}

/*
最小のブレークポイント幅を返す関数。 最初のブレークポイントの場合は null
例 breakpoint-min(sm, (xs:0, sm:576px, md:768px, lg:992px, xl:1200px))→ 576px
*/
@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {
  $min: map.get($breakpoints, $name);
  @return if($min != 0, $min, null);
}

/*
最大のブレークポイント幅(マップの値から .02 引いた値)を返す関数。
例 breakpoint-max(md, (xs:0, sm:576px, md:768px, lg:992px, xl:1200px))→767.98px
*/
@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {
  $max: map.get($breakpoints, $name);
  @return if($max and $max > 0, $max - .02, null);
}

/* min-width を使ったブレークポイントのメディアクエリを出力するミックスイン */
@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {
  $min: breakpoint-min($name, $breakpoints);
  @if $min {
    @media (min-width: $min) {
      @content;
    }
  } @else {
    @content;
  }
}

/* max-width を使ったブレークポイントのメディアクエリを出力するミックスイン */
@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {
  $max: breakpoint-max($name, $breakpoints);
  @if $max {
    @media (max-width: $max) {
      @content;
    }
  } @else {
    @content;
  }
}

/* $lower と $upper を指定したメディアクエリを出力するミックスイン */
@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {
  $min: breakpoint-min($lower, $breakpoints);
  $max: breakpoint-max($upper, $breakpoints);

  @if $min != null and $max != null {
    @media (min-width: $min) and (max-width: $max) {
      @content;
    }
  } @else if $max == null {
    @include media-breakpoint-up($lower, $breakpoints) {
      @content;
    }
  } @else if $min == null {
    @include media-breakpoint-down($upper, $breakpoints) {
      @content;
    }
  }
}

@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {
  $min:  breakpoint-min($name, $breakpoints);
  $next: breakpoint-next($name, $breakpoints);
  $max:  breakpoint-max($next);

  @if $min != null and $max != null {
    @media (min-width: $min) and (max-width: $max) {
      @content;
    }
  } @else if $max == null {
    @include media-breakpoint-up($name, $breakpoints) {
      @content;
    }
  } @else if $min == null {
    @include media-breakpoint-down($next, $breakpoints) {
      @content;
    }
  }
}
style.scss
@use "breakpoints" as *;

.logo {
  width: 130px;
  @include media-breakpoint-up(sm) {
    width: 150px;
  }
  @include media-breakpoint-up(md) {
    width: 170px;
  }
  @include media-breakpoint-up(lg) {
    width: 200px;
  }
}

.logo2 {
  width: 220px;
  @include media-breakpoint-down(xl) {
    width: 200px;
  }
  @include media-breakpoint-down(lg) {
    width: 180px;
  }
  @include media-breakpoint-down(md) {
    width: 150px;
  }
}

.foo {
  @include media-breakpoint-between(lg, xl) {
    width: 150px;
  }
}
コンパイルして出力される CSS
.logo {
  width: 130px;
}
@media (min-width: 576px) {
  .logo {
    width: 150px;
  }
}
@media (min-width: 768px) {
  .logo {
    width: 170px;
  }
}
@media (min-width: 992px) {
  .logo {
    width: 200px;
  }
}

.logo2 {
  width: 220px;
}
@media (max-width: 1199.98px) {
  .logo2 {
    width: 200px;
  }
}
@media (max-width: 991.98px) {
  .logo2 {
    width: 180px;
  }
}
@media (max-width: 767.98px) {
  .logo2 {
    width: 150px;
  }
}

@media (min-width: 992px) and (max-width: 1199.98px) {
  .foo {
    width: 150px;
  }
}

関連項目:メディアクエリ(ブレークポイント)

@debug 出力の確認

@debug を使うと、コンパイルする際に値をターミナル(コマンドライン)に出力することができます。変数や計算結果など式の値を確認するのに使用できます。

Sass (.scss)
@debug 変数や計算結果など式の値;

sass/style.scss
$width:200px;

@debug $width;

上記の sass/style.scss をコンパイルすると以下のようにターミナルにその式の値とファイル名および行番号が出力されます。

ターミナルへの出力
sass/style.scss:3 Debug: 200px

インターポレーションを使って出力

任意の文字列と一緒に出力するには、変数や式の値にインターポレーションを使います。

sass/style.scss
@use "sass:math"; /* math.random()を使用するため math モジュールを読み込み */

@debug "math.random(1000) の値: #{math.random(1000)}"; 
ターミナルへの出力
sass/style.scss:3 Debug: math.random(1000) の値: 433

コンパイルエラーになるような値も出力

@debug は meta.inspect() 同様、通常ではコンパイルエラーになるような値もターミナルに出力してくれます。

以下は15行目の map.get($breakpoints, $name) がエラーになるので、その値のタイプを @debug と meta.type-of() で出力して確認しています。

sass/style.scss
@use "sass:map";
@use "sass:meta";

$breakpoints: (
  'xs': (min-width: 0),
  'sm': (min-width: 576px),
  'md': (min-width: 768px),
  'lg': (min-width: 992px),
  'xl': (min-width: 1200px),
  'xxl': (min-width: 1400px)
);

@mixin bp-mq($name: lg) {
  @debug meta.type-of(map.get($breakpoints, $name)); /* エラーになる値のタイプを出力 */
  @media screen and #{map.get($breakpoints, $name)} {
    @content;
  }
}

.logo {
  width: 130px;
  @include bp-mq(sm) {
    width: 150px;
  }
  @include bp-mq(md) {
    width: 170px;
  }
  @include bp-mq(lg) {
    width: 200px;
  }
}
ターミナルへの出力
sass/style.scss:14 Debug: map /* マップとして認識されている */
Error: (min-width: 576px) isn't a valid CSS value.
   ╷
15 │   @media screen and #{map.get($breakpoints, $name)} {
   │                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   ╵
  sass/style.scss 15:23  bp-mq()
  sass/style.scss 22:3   root stylesheet

Sass: @debug

@error エラーを発生

@error を使用すると、引数に不適切な値が使用された場合などにエラーを発生させて処理を中断することができます。

エラーを発生させる箇所で @error に続けて任意のメッセージを記述します。

メッセージの中で式(変数)を出力するにはインターポレーションを利用します。

@error "任意のエラーメッセージ"

@error は指定されたエラーメッセージをスタックトレース(エラーになったミックスインや関数がどのように呼び出されたかを示す表示)とともに出力します。

以下は、引数に単位が付いていない場合にはエラーを発生させ処理を中止する例です。

sass/style.scss
@use "sass:math";  /* math.is-unitless() を使うので math モジュールを読み込み*/

@mixin adjust-location($x, $y) {
  @if math.is-unitless($x) {
    @error "$x には単位が必要です: #{$x}";
  }
  @if math.is-unitless($y) {
    @error "$y には単位が必要です: #{$y}";
  }
  position: relative; left: $x; top: $y;
}

.foo {
  @include adjust-location(10, 20);
}

上記の場合、ミックスインの呼び出しで引数に単位が付いていないのでコンパイル時にスタックトレースとともにエラーが出力され、処理が中断されます。

以下の8行目以降は、この CSS 読み込んでいる HTML に ::before を使ってエラーを表示するための記述で、HTML には1〜6行目の内容が表示されます。

コンパイルして出力される CSS(style.css)のエラー
/* Error: "$x には単位が必要です: 10"
 *    ,
 * 14 |   @include adjust-location(10, 20);
 *    |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 *    '
 *   sass/style.scss 14:3  root stylesheet */

body::before {
  font-family: "Source Code Pro", "SF Mono", Monaco, Inconsolata, "Fira Mono",
      "Droid Sans Mono", monospace, monospace;
  white-space: pre;
  display: block;
  padding: 1em;
  margin-bottom: 1em;
  border-bottom: 2px solid black;
  content: 'Error: "$x \306b \306f \5358 \4f4d \304c \5fc5 \8981 \3067 \3059 \ff1a  10"\a    \2577 \a 14 \2502    @include adjust-location(10, 20);\a    \2502    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\a    \2575 \a   sass/style.scss 14:3  root stylesheet';
}

ターミナル(コマンドライン)にも以下のような同様のメッセージが表示されます。

ターミナルへの出力
Error: "$x には単位が必要です: 10"
   ╷
14 │   @include adjust-location(10, 20);
   │   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   ╵
  sass/style.scss 14:3  root stylesheet

この例のミックスインの場合、以下のように @error を使わないと

Sass (.scss)
@mixin adjust-location($x, $y) {
  position: relative; left: $x; top: $y;
}

.foo {
  @include adjust-location(10, 20);
}

ミックスインの引数に単位を付けないで呼び出してもエラーにならないため、以下のように無効な値の状態でコンパイルされてしまいます。

コンパイルして出力される CSS
.foo {
  position: relative;
  left: 10; /* CSS として無効な値 */
  top: 20; /* CSS として無効な値 */
}

この例のような場合は、単位が付いてない場合はミックスイン側で単位を付けて @warn で警告を表示することもできます(それが良い方法かどうかは別ですが)。

Sass: @error

@warn 警告の表示

@warn を使用するとユーザーが誤った使い方や推奨されない使い方等をした場合に、任意の警告のメッセージをターミナル(コマンドライン)に表示させる事が出来ます。

@warn はそれが発生した箇所をファイル名と行数、関数名を表示してくれます。但し、@error ルールとは異なり、Sass の処理を停止するわけではありません。

警告を表示する箇所に @warn に続けて任意のメッセージや必要に応じて式(変数など)を記述します。

@warn "任意のメッセージ"

メッセージの中で変数を出力するにはインターポレーションを利用します。

以下は、ミックスインの引数に単位(px)を付けないで呼び出した場合は、ミックスイン側で px の単位を付けて警告メッセージを表示します。また、px 以外の単位が付いている場合は警告メッセージのみを表示します(単位は付け替えない)。

@warn を使用しているので処理は中断されませんが、適切な使い方をユーザーに知らせるために警告を表示しています(単位が異なれば期待した表示にはならないと思いますが)。

sass/style.scss
@use "sass:math";

@mixin adjust-location($x, $y) {
  @if math.is-unitless($x) {
    @warn "指定した値 #{$x} に単位 px を付けてください";
    $x: 1px * $x;
  } @else if math.unit($x) != 'px' {
     @warn " #{$x} 単位は px をお使いください";
  }

  @if math.is-unitless($y) {
    @warn "指定した値 #{$y} に単位 px を付けてください";
    $y: 1px * $y;
  }@else if math.unit($y) != 'px' {
     @warn " #{$y} 単位は px をお使いください";
  }

  position: relative; left: $x; top: $y;
}

.foo {
  @include adjust-location(10, 20);
}

警告は以下のように「Warning:」に続けて指定した任意の文字列や式(変数)が表示されます。

ターミナルへの出力
Warning: Assuming 10 to be in pixels(単位 px を付けてください)
    sass/style.scss 5:5   adjust-location()
    sass/style.scss 16:3  root stylesheet

Warning: Assuming 20 to be in pixels(単位 px を付けてください)
    sass/style.scss 9:5   adjust-location()
    sass/style.scss 16:3  root stylesheet
コンパイルして出力される CSS
.foo {
  position: relative;
  left: 10px;
  top: 20px;
}

Sass: @warn