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

Web/26 Aug 2015

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

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

上記をコンパイルすると

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;
  }
}

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

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> にはカンマ区切りのリストを指定します。で、リストの数だけ繰り返し処理を行います。

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

コンパイルすると

.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 の生成を行っています。

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

コンパイルすると、

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

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

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

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

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

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

.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 を見ると良いです。こんな風に使うんだと勉強になります。

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