初心者のためのSCSS。条件分岐のif文、反復処理for文などを使ってみよう。

SCSSでコントロールディレクティブを使う

SCSSを導入しようかと検討する際に、このブログの記事を参考にしてくれた奇特な方が居たそうな。どうもありがとう。

で、声をいただくと書かない訳にはいかないので、条件分岐のIf文と反復処理の構文に絞った内容で書いてみようかと思う次第です。

SCSSとは

CSSの拡張言語です。長くなったり、複雑になって管理できなくなったりするCSSを効率的に書けるようにします。効率的にする機能として、以前に紹介した変数やパーシャル、これから紹介する条件分岐のif文と繰り返し処理のfor文などがあります。他にも継承させる@extendや関数化できる@mixinなどがありますが、これは別の機会で。

条件分岐の使い方

デザイナーならjavascriptとかで触れたことがある条件分岐、if文の使い方です。

公式サイトを見ると、基本的な記述例と以下内容が記載されています。

Note: Control directives are an advanced feature, and are uncommon in day-to-day styling. They exist mainly for use in mixins, particularly those that are part of libraries like Compass, and so require substantial flexibility.

「コントロールディレクティブ(if文や次に紹介するfor文などの繰り返し処理)は柔軟なスタイリングが必要なmixinなどで使用するように」

意訳していますが、実際に使う機会を想定しても個別のスタイルを記述している箇所で条件分岐やループはほとんど使いません。逆にmixinの引数ごとに処理を変更させるとかは想定できますね。

if文

基本的なコード例については、公式サイトからお借りしました。
Sass Documentation

// SCSS
// if文はセレクタの中に書く
p {
  @if 1 + 1 == 2 { border: 1px solid;  }
  @if 5 < 3      { border: 2px dotted; }
  @if null       { border: 3px double; }
}

上記をコンパイルすると

/* CSS */
p {
  border: 1px solid;
}

となります。これは@if以降の式の真偽を見ていて、falsenull以外の時にだけ{}の中の値を返します。
さらに、elseelse ifも使えます。

// SCSS - if文を使った複数の分岐
$type: monster;
p { // monsterの時だけ処理する
  @if $type == ocean {
    color: blue;
  } @else if $type == matador {
    color: red;
  } @else if $type == monster {
    color: green;
  } @else {
    color: black;
  }
}

コンパイルすると以下のようになります。

/* CSS */
p { color: green; }

@を付けることに注意すれば記法も特に難しくはないはず。で、自分が使っている例も出そうと思ったのですがほとんど使っていないので、Bootstrapで見てみます。
Bootstrap 4になってFlexboxを使ったCSSレイアウトが採用されています。ですが、現状通りのFloatレイアウトも使えます。2種類のレイアウトの切り替えを実現するために、以下のようにIf文を用いて出力するスタイルを制御しています。

// Bootstrap 4 - mixin/_grid.scss の13行目くらい
@mixin make-row($gutter: $grid-gutter-width) {
  @if $enable-flex { // 変数 $enable-flex の値がtrueならFlexboxレイアウト
    display: flex;
    flex-wrap: wrap;
  } @else { // falseならclearfix使うFloatレイアウト(子要素にfloat指定)
    @include clearfix();
  }
  margin-left:  ($gutter / -2);
  margin-right: ($gutter / -2);
}

子要素の配置を横並びにする時の親要素を生成するmixinで、レイアウトごとに異なるスタイルを適用させる時に使えそうです。分岐をうまく用いれば、少ない手間でいろいろなレイアウトの形を試せるようになるかもしれません。

反復処理の使い方

スタイルを繰り返し出力させる処理で、forとwhile、eachがあります。以下では基本的な例を紹介し、最後にこれらを組み合わせた記述を紹介します。

for文とwhile文

個人的な感覚ではfor文の方がよく使う印象があります。と言っても、そもそもmixinとかでしか使わないのですが。

で、以下が基本的な記述例です。一定のルールや規則的に計算し出力させたい場合に適していて、.item- + 変数の組み合わせでスタイルが出力されます。

// for文
@for $i from 1 through 3 {
  .item-#{$i} { width: 2em * $i; }
}

while文でも以下のように同様の処理を書けます。

// while文
$i: 1;
@while $i <= 3 {
  .item-#{$i} { width: 2em * $i; }
  $i: $i + 1;
}

for文、while文で、クラス名の文字列に変数を使いたい時は、#{i}のようにします。また、値として変数を使う場合は$iのように書きます。
これらのコンパイル結果はどちらも同じとなります。

.item-1 {
  width: 2em; }

.item-2 {
  width: 4em; }

.item-3 {
  width: 6em; }

each文

each文は、@each $var in <list>という構文で記述します。$varには任意の変数が指定でき、<list>にはカンマ区切りのリストを指定します。で、リストの数だけ繰り返し処理を行います。

// SCSS
// リスト[puma, sea-slug, egret, salamander]の数だけ繰り返す
@each $animal in puma, sea-slug, egret, salamander {
  .#{$animal}-icon {
    background-image: url('/images/#{$animal}.png');
  }
}

コンパイルすると

/* CSS */
.puma-icon {
  background-image: url('/images/puma.png'); }

.sea-slug-icon {
  background-image: url('/images/sea-slug.png'); }

.egret-icon {
  background-image: url('/images/egret.png'); }

.salamander-icon {
  background-image: url('/images/salamander.png'); }

リストと同じ数の.#{$animal}-icon形式のアイコンスタイルが出力されました。

基本的な知識としてはこれで十分なのですが、BootstrapのようなCSSフレームワークでは、複数の反復処理を組み合わせてグリッドなどが生成されています。以下はそんな組み合わせの例となります。

組み合わせて使ってみる

フレームワーク全盛期の昨今、中身を見た時に少しでも理解ができればということで、each文とfor文を組み合わせたグリッド生成の処理を見てみましょう。

以下では、リスト[sm, md, lg]ごとに$columns: 3で指定したカラム数をもとに、クラスとクラスごとのwidthの生成を行っています。

// scss
$columns: 3;
@each $breakpoint in sm, md, lg {
  @for $i from 1 through $columns {
    .col-#{$breakpoint}-#{$i} {
      width: percentage($i / $columns);
    }
  }
}

コンパイルすると、

/* sm */
.col-sm-1 {
  width: 33.33333%; }

.col-sm-2 {
  width: 66.66667%; }

.col-sm-3 {
  width: 100%; }

/* md */
.col-md-1 {
  width: 33.33333%; }

.col-md-2 {
  width: 66.66667%; }

.col-md-3 {
  width: 100%; }

/* lg */
.col-lg-1 {
  width: 33.33333%; }

.col-lg-2 {
  width: 66.66667%; }

.col-lg-3 {
  width: 100%; }

リストごとに3つのスタイルが出力されました。例えば、リストのsm,md,lgの値によって、カラム数とその値を変えたい場合は、ifで条件を追加すればよいですね。

@each $breakpoint in sm, md, lg {
  // リストごとにカラム数を変える
  @if $breakpoint == sm {
    $columns: 6;
  } @else if $breakpoint == md {
    $columns: 8;
  } @else {
    $columns: 12;
  }
  @for $i from 1 through $columns {
    .col-#{$breakpoint}-#{$i} {
      width: percentage($i / $columns);
    }
  }
}

組み合わせれば柔軟性の高いスタイルを作ることができます。そしてこれらは、mixinで活用してその真価を発揮します。

以上、公式サイトに載っている基本的な構文を中心に見ていきました。さらに活用したい場合は、様々なフレームワークやCompassのmixinを見ると良いです。こんな風に使うんだと勉強になります。

ちなみに自分は、今回初めて公式サイトのドキュメントを見ましたが、ここも結構わかりやすく書いてありました。英語なので疲れましたけどね。

関連記事