Sassのループ処理と条件分岐で、効率良くスタイルを定義しよう

Sassには、JavaScriptやPHPなどのプログラミング言語にあるforforeachのようなループ処理を@for@eachで行うことができます。

また、条件分岐のif@ifが用意されています。

これらをうまく使うと、1つ1つ手入力していたプロパティを1つの処理で出力したり、出力する数を簡単に変更できたり、特定のカテゴリーだけ別のスタイルを適用することができて、CSSを効率良く書くことできます。

今回はSassの @for @each @if を使って、複数のスタイル定義を行う手法を説明します。

目次

カテゴリーごとのページヘッダーを定義する

Webサイトを構築すると、カテゴリーごとにページヘッダーの背景画像を変更するデザインをコーディングすることがあります。

弊社Webサイトの場合

会社概要では社屋外観の写真、商品紹介では商品の写真、社員紹介では社員たちの写真…といった感じですね。

その場合のHTMLとCSSは、こんな感じで書くことになると思います。

<!-- 会社概要 -->
<div class="c-categoryHead--about">
  <h2>会社概要 ABOUT</h2>
</div>

<!-- 商品紹介 -->
<div class="c-categoryHead--product">
  <h2>商品紹介 PRODUCT</h2>
</div>

<!-- 社員紹介 -->
<div class="c-categoryHead--staff ">
  <h2>社員紹介 STAFF</h2>
</div>
.c-categoryHead--about {
  background: url("../img/bg_head_about01.jpg") no-repeat 0 0;
  background-size: cover;
  font-size: 24px;
  line-height: 1.25;
}
.c-categoryHead--product {
  background: url("../img/bg_head_product01.jpg") no-repeat 0 0;
  background-size: cover;
  font-size: 24px;
  line-height: 1.25;
}
.c-categoryHead--staff {
  background: url("../img/bg_head_staff01.jpg") no-repeat 0 0;
  background-size: cover;
  font-size: 24px;
  line-height: 1.25;
}

デザインにもよりますが、たいていの場合、背景画像以外は同じプロパティを指定することになりますので、同じ指定が繰り返すことになります。ちょっと冗長な感じがします。

書き方を工夫する

書き方を工夫すれば、共通部分をひとまとめにして、デザイン修正などにもすぐに対応できるようにすることができます。

まずは、クラス名を増やして共通部分を.c-categoryHeadにまとめて、カテゴリーごとに異なる部分を別で指定してみましょう。

<!-- 会社概要 -->
<div class="c-categoryHead c-categoryHead--about">
  <h2>会社概要 ABOUT</h2>
</div>

<!-- 商品紹介 -->
<div class="c-categoryHead c-categoryHead--product">
  <h2>商品紹介 PRODUCT</h2>
</div>

<!-- 社員紹介 -->
<div class="c-categoryHead c-categoryHead--staff ">
  <h2>社員紹介 STAFF</h2>
</div>
// 共通
.c-categoryHead {
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: cover;
  font-size: 24px;
  line-height: 1.25;
}

// カテゴリー別
.c-categoryHead--about {
  background-image: url("../img/bg_head_about01.jpg");
}
.c-categoryHead--product {
  background-image: url("../img/bg_head_product01.jpg");
}
.c-categoryHead--staff {
  background-image: url("../img/bg_head_staff01.jpg");
}

これでフォントサイズが24pxから32pxに変更!となっても一箇所変更するだけで済みます。

@eachを使う

書き方を工夫して、共通部分をひとまとめにして、変更にも対応しやすくなりました。

しかし、カテゴリーが増えれば増えるほど、カテゴリー別のスタイル指定が増えていき、コードが長くなってしまいます。

そこで、カテゴリー名を配列にして、それをループさせてスタイルの指定を出力するようにしてみましょう。

// カテゴリー名の配列
$catList: about, product, staff ;

.c-categoryHead {
  
  // 共通
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: cover;
  font-size: 24px;
  line-height: 1.25;

  // カテゴリー別
  @each $cat in $catList01 {
    &--#{$cat} {
      background-image: url("../img/bg_head_#{$cat}01.jpg");
    }
  }
}

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

.c-categoryHead {
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: cover;
  font-size: 24px;
  line-height: 1.25;
}

.c-categoryHead--about {
  background-image: url("../img/bg_head_about01.jpg");
}

.c-categoryHead--product {
  background-image: url("../img/bg_head_product01.jpg");
}

.c-categoryHead--staff {
  background-image: url("../img/bg_head_staff01.jpg");
}

これで、カテゴリーが増えても減っても、配列$catListを変更するだけでカテゴリー別のスタイルを出力することができます。

@ifを使う

ループ処理は便利ですが、同じ処理を繰り返すことが前提なので、「商品紹介だけフォントサイズを20pxにする」とか「会社概要は画像ファイルをPNG形式にする」なんてことがあります。

もちろん、プロパティを追加してスタイルを上書きすることもできますね。

// カテゴリー名の配列
$catList: about, product, staff ;

.c-categoryHead {
  
  // 共通
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: cover;
  font-size: 24px;
  line-height: 1.25;

  // カテゴリー別
  @each $cat in $catList {
    &--#{$cat} {
      background-image: url("../img/bg_head_#{$cat}01.jpg");
    }
  }
}

.c-categoryHead--about {
  background-image: url("../img/bg_head_about01.png");
}

.c-categoryHead--product {
  font-size: 20px;
}

これをCSSにコンパイルするとこんな感じです。

.c-categoryHead {
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: cover;
  font-size: 24px;
  line-height: 1.25;
}

.c-categoryHead--about {
  background-image: url("../img/bg_head_about01.jpg");
}

.c-categoryHead--product {
  background-image: url("../img/bg_head_product01.jpg");
}

.c-categoryHead--staff {
  background-image: url("../img/bg_head_staff01.jpg");
}

.c-categoryHead--about {
  background-image: url("../img/bg_head_about01.png");
}

.c-categoryHead--product {
  font-size: 20px;
}

.c-categoryHead--about.c-categoryHead--productの指定が分かれて出力されてしまいます。これはちょっと冗長ですね。

そこで、@ifを使って、商品紹介のときにはフォントサイズを20px、会社概要のときにはPNG形式の画像ファイルを指定するようにします。

// カテゴリー名の配列
$catList: about, product, staff ;

.c-categoryHead {
  
  // 共通
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: cover;
  font-size: 24px;
  line-height: 1.25;

  // カテゴリー別
  @each $cat in $catList {
    &--#{$cat} {
      @if $cat == about {
        background-image: url("../img/bg_head_#{$cat}01.png");
      } @else {
        background-image: url("../img/bg_head_#{$cat}01.jpg");
      }
      @if $cat == product {
        font-size: 20px;
      }
    }
  }
}

コンパイル後のCSSは以下のようになります。

.c-categoryHead {
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: cover;
  font-size: 24px;
  line-height: 1.25;
}

.c-categoryHead--about {
  background-image: url("../img/bg_head_about01.png");
}

.c-categoryHead--product {
  background-image: url("../img/bg_head_product01.jpg");
  font-size: 20px;
}

.c-categoryHead--staff {
  background-image: url("../img/bg_head_staff01.jpg");
}

冗長な部分が減って見やすくなりましたね。

汎用クラスを定義する

スタイル定義を行っていると、どうしても特定の箇所だけ特別なスタイルが必要になる場合があります。

通常、本文のフォントサイズは16pxだけど、ここの文字だけ18pxになるといった具合に、わざわざクラスとして定義するほどではない小さな違いですね。

よく使われるのは、「どこでも使える汎用クラスを定義して、必要に応じてクラス属性に追加する」手法ですね。

例えば、会社概要で会社情報の一覧表があったとします。

通常、table要素のtd要素は、フォントサイズ16pxとして定義されています。
しかし、この一覧表では会社名のフォントサイズは18pxでするように指定がありました。

そこで、汎用クラスとして、.w250.fz18を用意して変更する要素にクラス属性を追加して対応します。

<table>
  <tr>
    <th class="w250">商号</th>
    <td class="fz18">友野印刷株式会社</td>
  </tr>
  <tr>
    <th>創業</th>
    <td>昭和36年1月1日</td>
  </tr>
  <tr>
    <th>会社設立</th>
    <td>昭和36年9月8日</td>
  </tr>
</table>
.w250 {
  width: 250px;
}

.fz18 {
  font-size: 18px;
}

このように都度プロパティを追加して対応することもできますが、都度対応できない場合(クライアントにCSSを渡してしまって変更できない)は、事前にある程度汎用クラスを用意しておく方がよいでしょう。

横幅は200pxから600pxまで50pxごとに、フォントサイズは17pxから32pxまで1pxごとにクラスを用意することにします。

先ほど説明した@eachでは、設定したい値を配列で用意する必要があります。
実際に配列を定義すると、以下のようになります。

// 横幅
$widthValue: 200, 250, 300, 350, 400, 450, 500, 550, 600;

// フォントサイズ
$fontValue: 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32;

配列が長くて、見づらいですね。
また、フォントサイズの上限が増えたり、横幅の指定が20pxごとに変更することになったりしたら、変更するのも一手間です。

@forを使う

そこで、指定した回数だけループ処理ができるを@for使います。

まずは、フォントサイズの汎用クラスから定義してみましょう。

@for $i from 17 through 32 {
 .fz#{$i} {
   font-size: #{$i}px !important;
 }
}

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

.fz17 {
  font-size: 17px !important;
}

.fz18 {
  font-size: 18px !important;
}

~中略~

.fz31 {
  font-size: 31px !important;
}

.fz32 {
  font-size: 32px !important;
}

17pxから32pxまで、汎用クラスが定義されていますね。
ひとつひとつ手入力したり、コピペしたりするより、圧倒的に効率がよいですね。

では、続いて横幅の汎用クラスを定義します。

$start: 200;
$end: 600;
$interval: 50;

$count: ($end - $start) / $interval; 

@for $i from 1 through $count {
  $value: $start + ($interval * $i);

  .w#{$value)} {
    width: #{$value}px !important;
  }
}

一気にプログラミングっぽくなりました。細かく解説していきますね。

解説

STEP
変数の定義

まず、今後作りたい汎用クラスの範囲が変わることを想定して、変数を定義します。

$start: 200;    // 最小幅
$end: 600;      // 最大幅
$interval: 50;  // 間隔
STEP
ループ処理の回数を算出

次にループの実行回数を算出します。

@forは指定した値になるまで、「1, 2, 3…」と1つずつカウントアップされていきます。
しかし、処理は200から600まで50ごとカウントアップされてほしいので、そのままでは狙ったとおりにループできません。

そこで、最大値の600から最長値の200を引き算して、その差分である400を50で除算して、何回ループを回すのかを算出して、変数$countに設定します。

$count: ($end - $start) / $interval; 
STEP
@forを定義

ループ処理の@forを定義します。

@for $i from 1 through $count {
}

終了値は、先ほど設定した変数$countにします。

STEP
値を算出
$value: $start + ($interval * $i);

クラス名と横幅に設定する値を算出して、変数$valueに設定します。

変数$iには、ループの回数が格納されています。
間隔に回数を乗算して最小値に加算することで、200, 250, 300…と設定したい値を算出することができます。

算出された値を変数$valueへ格納します。

STEP
CSSプロパティを定義

変数$valueを使って、汎用クラス名とwidthの値を設定します。

.w#{$value)} {
  width: #{$value}px !important;
}

完成

こうしてできあがったSCSSをコンパイルすると、以下のようなCSSになります。

.w250 {
  width: 250px !important;
}

.w300 {
  width: 300px !important;
}

~ 中略 ~

.w550 {
  width: 550px !important;
}

.w600 {
  width: 600px !important;
}

最小値、最大値、間隔を変数にしていますので、それぞれの変数を変えれば欲しい汎用クラスを生成することができます。

例えば、100pxから300pxまで、10pxごとに汎用クラスを作る場合には、変数を以下のように設定します。

$start: 100;
$end: 300;
$interval: 10;

すると、CSSは以下のようにコンパイルされます。

.w110 {
  width: 110px !important;
}

.w120 {
  width: 120px !important;
}

.w130 {
  width: 130px !important;
}

~ 中略 ~

.w280 {
  width: 280px !important;
}

.w290 {
  width: 290px !important;
}

.w300 {
  width: 300px !important;
}

配列を用意したり、ループ処理の回数を自分で計算しなくても、値だけを設定すれば生成されるので、効率良くコーディングできます。

まとめ

Sass(SCSS)には、ループや条件分岐といった命令が用意されているので、工夫すればコーディングを効率良く行えるので、とてもべんりですね。

とはいえ、何でもかんでもループや条件分岐を使って生成していると、柔軟な変更に対応できなかったり、応用がきかなくなったりしますので、使いすぎには気をつけましょう。

よかったらシェアしてね!

この記事を書いた人

Webコーダーとして日々研鑽しています。
最近はJavaScriptで実現できるギミックが増えることに喜びながら、後方互換に悩むのが日課になっています。

コメント

コメントする

目次
閉じる