Web制作の効率が劇的アップ!SCSSの基本機能と活用テクニック(Dart Sass対応版)

2018.09.12
2018年に作成した記事をDart Sass版に書き換えています。

Web制作の効率を劇的に上げる!SCSSの基本機能と実践的な活用術

Web制作において、CSSの記述をより効率的で、管理しやすいものに変えてくれる「SCSS」。入れ子構造や変数、関数といったSCSS独自の機能を使うことで、コードの記述量を減らし、Webサイトのメンテナンス性や開発スピードを大幅に向上させることができます。

本記事では、Dart Sass に対応した記述方法で、主要な機能を豊富なコード例とともに分かりやすく解説します。SCSSをマスターして、質の高いWebサイトを効率的に構築しましょう。

入れ子(ネスト)

SCSSの大きな特徴の一つが「入れ子(ネスト)」記述です。HTMLの構造に合わせてCSSのセレクタを入れ子にして書けるため、記述量が減り、コードの可読性とメンテナンス性が向上します。

記述例

▼SCSS

a {
  color: gold;
  transition: opacity .3s;
  &:hover {
    opacity: .7;
  }
}

▼CSS

a { color: gold; transition: opacity .3s; }
a:hover { opacity: .7; }

注意点

入れ子を深くしすぎると、生成されるCSSのセレクタが長くなり、ブラウザのレンダリングパフォーマンスに影響を与える可能性があります。また、コードが読みにくくなり、Webサイトのメンテナンスコストが増大することも考えられます。

理想的な入れ子の深さは1〜3段階とされています。CSSの優先順位を考慮し、多くても4段階以内に収めることを目指しましょう。

▼SCSS(深すぎる入れ子の例)

ul {
  >li {
    .text_wrap {
      p {
        .text_headline { font-size: 22px; }        
      }
    }
  }
}

▼CSS

ul > li .text_wrap p .text_headline { font-size: 22px; }

変数

SCSSの「変数」機能を使えば、繰り返し使う値(色コード、フォントサイズ、余白など)を一度定義し、複数の場所で使い回せます。これにより、変更があった際に変数の値を修正するだけでよくなり、Webサイト全体のデザインの一貫性を保ちやすくなります。

記述例

▼SCSS

$text_color-red: #fc0; /* 変数の定義 */
a {
  color: $text_color-red;
}
.notice_label {
  color: #fff;
  background: $text_color-red;
}

▼CSS

a { color: #fc0; }
.notice_label { color: #fff; background: #fc0; }

変数の上書き

変数は{}で区切られた範囲(スコープ)内で有効です。内側のスコープで変数を上書きした場合、その変更はそのスコープ内でのみ適用されます。

▼SCSS(スコープの例)

$text_color: #fc0; /* グローバル変数 */
a {
  color: $text_color;
  &.nolink {
    $text_color: #ddd; /* このスコープ内で上書き */
    color: $text_color;
  }
}
.notice_label {
  color: #fff;
  background: $text_color; /* グローバル変数が適用される */
}

▼CSS

a { color: #fc0; }
a.nolink { color: #ddd; }
.notice_label { color: #fff; background: #fc0; }

また、変数名はセレクタ名やプロパティ名の一部としても使えます。#{}(インターポレーション/補間)という記述方法を使います。

▼SCSS(インターポレーションの例)

$imgPath: "/common/images";
$className: balloon;
$direction: left;
a.#{$className} { /* セレクタ名の一部に変数を使用 */
  padding-#{$direction}: 2em; /* プロパティ名の一部に変数を使用 */
  background: url(#{$imgPath}/arrow-bgi.png); /* プロパティ値に変数を使用 */
}

▼CSS

a.balloon {
  padding-left: 2em;
  background: url(/common/images/arrow-bgi.png);
}

その他

変数のスコープは、!globalフラグや!defaultフラグを使って調整できます。ただし、Dart Sassのモジュールシステム(@use)においては!globalの使用は推奨されません。また、CSSネイティブ変数(カスタムプロパティ)は、コンパイル後もそのままCSSとして出力されます。

計算

SCSSでは、CSSのプロパティ値に四則演算を直接記述できます。これにより、要素のサイズや余白などを動的に計算でき、レスポンシブWebデザインなどの複雑なレイアウト構築が容易になります。
なおDart Sassでは、割り算にスラッシュ(/)を使用することが非推奨となりました。代わりにsass:mathモジュールのmath.div()関数もしくはcalc()関数を使用します。

記述例

▼SCSS

$siteWidth:1200px;
$spaceWidth:20;

.panel_list_wrap {
  width: $siteWidth + 20px; /* 足し算 */
}
.panel_list {
  padding: 0 $siteWidth - 1180px; /* 引き算 */
  li {
    margin: 0 $spaceWidth*2px; /* 掛け算 */
    width: math.div($siteWidth, 3); /* 割り算(math.div推奨) */
  }
}
.panel_space {
  padding: $spaceWidth%3%; /* 余り */
}

▼CSS

.panel_list_wrap { width: 1220px; } /* 1200px + 20px */
.panel_list { padding: 0 20px; } /* 1200px - 1180px */
.panel_list li {
  margin: 0 40px; /* 20 * 2px */
  width: 400px; /* 1200px / 3 */
}
.panel_space { padding: 2%; } /* 20 ÷ 3 の余り */

文字列の連結

文字列の連結も可能です。+演算子を使って、複数の文字列変数や固定文字列を結合できます。

▼SCSS

$name: "佐藤さん";
$name2: "鈴木さん";

a {
  &:after {
    content: $name+"と"+$name2+"が来ます";
  }
}

▼CSS

a:after { content: "佐藤さんと鈴木さんが来ます"; }

@mixin

@mixinは、繰り返し使うCSSのスタイルセットをまとめて定義し、必要な場所で呼び出せる機能です。引数を設定することで、より柔軟なスタイル調整も可能になります。これにより、コードの再利用性が高まり、Web制作の効率が飛躍的に向上します。

@mixin 名前 で定義し、 @include 名前; で呼び出します。

記述例

▼SCSS

@mixin blueBorder { /* mixinの定義 */
  border: solid 2px blue;
}
.text {
  @include blueBorder; /* mixinの呼び出し */
}
.box_text {
  @include blueBorder;
}

▼CSS

.text { border: solid 2px blue; }
.box_text { border: solid 2px blue; }

引数の設定

引数を設定することで、同じmixinでも異なるスタイルを適用できます。初期値を設定することも可能です。

▼SCSS(引数と初期値の例)

@mixin blueBorder($style: solid, $borderWidth: 4px ) { /* 引数と初期値 */
  border: $style $borderWidth blue;
}
.default {
  @include blueBorder(); /* 初期値が適用される */
}
.wide_box {
  @include blueBorder(double,10px); /* 引数を指定 */
}
.dot_box {
  @include blueBorder(dotted,6px);
}

▼CSS

.default { border: solid 4px blue; }
.wide_box { border: double 10px blue; }
.dot_box { border: dotted 6px blue; }

その他

@mixinの定義内に@content;と記述することで、呼び出し時にブロックコンテンツを渡す「コンテンツブロック」という機能も使えます。気になる方は「mixin content」で検索してみてください。

@extend

@extendは、既存のCSSスタイルを別のセレクタに継承させる機能です。これにより、共通するスタイルを一つにまとめることができ、CSSの記述量を減らし、Webサイトの保守性を高める効果があります。

記述例

▼SCSS

.headline3 { /* 継承元のスタイル */
  margin-bottom: .5em; padding-left: .5em;
  border-left: solid .25em gray;
  font-size: 22px;
}
.headline3_red {
  @extend .headline3; /* .headline3のスタイルを継承 */
  border-left-color: red;
  color: red;
}
.headline3_red_modified {
  @extend .headline3_red; /* .headline3_redのスタイルを継承 */
  transform: rotate3d(1, 1, 1, 45deg);
}

▼CSS

.headline3, .headline3_red, .headline3_red_modified {
  margin-bottom: .5em; padding-left: .5em;
  border-left: solid .25em gray;
  font-size: 22px;
}
.headline3_red, .headline3_red_modified { border-left-color: red; color: red; }
.headline3_red_modified { transform: rotate3d(1, 1, 1, 45deg); }

さらに

%(パーセント)を頭に指定した「プレースホルダーセレクタ」を使えば、@extendで呼び出されない限りCSSに出力されない、Extend専用のスタイルを作成できます。

▼SCSS(プレースホルダーセレクタの例)

%default-box-style { /* プレースホルダーセレクタ */
  margin: 10px;
  padding: 10px;
  border: solid 1px gold;
}
.boxA {
  @extend %default-box-style; /* 継承 */
  background: green;
}

▼CSS

/* .boxAが@extendしているため、%default-box-styleの内容が.boxAにのみ書き出される */
.boxA { margin: 10px; padding: 10px; border: solid 1px gold; }
.boxA { background: green; }

その他

@extendを多用しすぎると、生成されるセレクタの数が膨大になり、CSSの内容が複雑で読みにくくなることがあります。また、継承元と継承先のセレクタがまとまって出力されるため、CSSの優先順位がSCSSで意図した通りにならない可能性もあります。

そのため、コンポーネント内のみでの使用など、ある程度範囲を絞って使うことが推奨されます。

関数

SCSSでは、独自の関数を作成したり、あらかじめ用意されている「ネイティブ関数(組み込み関数)」を利用できます。これにより、複雑な計算や値の加工を効率的に行い、より柔軟で動的なCSSを記述できるようになります。
Dart Sassでは、組み込み関数は sass:math などのモジュールを通して使用することが推奨されています。

記述例

▼SCSS(自作関数の例)

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

/* ▼引数を2で割った値を返す関数 */
@function half_width($value) {
  @return math.div($value, 2); /* 割り算はmath.divを使用 */
}
  
$contentWidth: 1000px;
.half_width-item {
  width: half_width($contentWidth); /* 自作関数を呼び出し */
}

/* ▼引数が複数の関数 */
@function px($size, $width:640){
  $rate: math.div($size, 640) * math.div(640, $width);
  @return $rate * 100 * 1%;
}
.px_sample { width: px(200); }
.px_sample-w600 { width: px(200,600); } /* 親要素のwidthが600pxの時を想定 */

▼CSS

/* ▼引数を2で割った値を返す関数 */
.half_width-item { width: 500px; }

/* ▼引数が複数の関数 */
.px_sample { width: 31.25%; }
.px_sample-w600 { width: 33.3333333333%; }

ネイティブ関数

SCSSには、色の彩度調整、数値の四捨五入、文字列操作、配列操作など、多くのネイティブ関数が標準で用意されています。
ここでは一部の例をご紹介します。さらに詳しい情報は、公式ドキュメントや関連サイトでご確認ください。

Dart Sassでは、これらはsass:mathsass:colorsass:stringなどのモジュールに分類されています。

▼SCSS(ネイティブ関数の例)

@use "sass:color";
@use "sass:math";

/* ▼color.mix:2色の混合色を返す */
.sample-mix {
  color: color.mix(#0086af, #00c, 50%);
}

/* ▼math.round:四捨五入 */
.sample-round {
  $a-width: math.div(100, 3);
  $b-height: math.div(100 * 3.14%, 2.2);
  width: math.round($a-width) * 1px; /* math.round関数で四捨五入 */
  height: math.round($b-height);
}

/* ▼math.abs:絶対値 */
.sample-abs {
  width: math.abs(100px); /* math.abs関数で絶対値を返す */
  height: math.abs(-100px);
}

▼CSS

/* ▼中間色 */
.sample-mix { color: #0043be; }

/* ▼四捨五入 */
.sample-round {
  width: 33px; height: 143%;
}

/* ▼絶対値 */
.sample-abs { width: 100px; height: 100px; }

色の調整

Dart Sassでは、以前の色調整関数(lighten, darkenなど)は非推奨となり、代わりに**color.adjust()** や **color.scale()** 関数を使うことが推奨されています。これらを使うには @use "sass:color"; が必要です。

記述例

▼SCSS

@use "sass:color";

// 色の変数を宣言
$color: #0086af;

/* ▼color.change:特定の値(透明度など)だけを変更 */
.rgba {
  background: color.change($color, $alpha: 0.5);
}

/* ▼color.mix:2色の混合色を返す */
.mix {
  background: color.mix($color, #00c, 50%);
}

/* ▼color.adjust:値を加算・減算して調整(lighten/darkenの代替) */
.lighten {
  /* 輝度(lightness)を+30%する */
  background: color.adjust($color, $lightness: 30%);
}

.darken {
  /* 輝度(lightness)を-20%する */
  background: color.adjust($color, $lightness: -20%);
}

/* ▼color.scale:現在の値に対する比率で調整(より滑らかな変化) */
.saturate {
  /* 彩度を現在の値から20%高める */
  background: color.scale($color, $saturation: 20%);
}

/* ▼color.grayscale:グレースケールに変換 */
.grayscale {
  background: color.grayscale($color);
}

/* ▼color.complement:補色を返す */
.complement {
  background: color.complement($color);
}

/* ▼color.invert:色を反転 */
.invert {
  background: color.invert($color);
}

/* ▼color.adjust:色相(hue)を回転させる */
.adjust-hue {
  background: color.adjust($color, $hue: -60deg);
}

▼CSS

/* ▼rgba(透明度変更) */
.rgba { background: rgba(0, 134, 175, 0.5); }

/* ▼中間色 */
.mix { background: #0043be; }

/* ▼輝度を明るくする */
.lighten { background: #49d4ff; }

/* ▼輝度を暗くする */
.darken { background: #001116; }

/* ▼彩度を上げる */
.saturate { background: #0086af; }

/* ▼グレースケールに変換 */
.grayscale { background: #575858; }

/* ▼補色 */
.complement { background: #af2900; }

/* ▼色の反転 */
.invert { background: #ff7950; }

/* ▼色相環の調整 */
.adjust-hue { background: #00af29; }

繰り返し

SCSSでは、プログラミング言語のように@for@while@eachといった繰り返し構文を使用できます。これにより、規則性のあるCSSプロパティを自動生成でき、記述量を大幅に削減し、Web制作の効率を向上させます。

記述例

▼SCSS

/* ▼forループ */
@for $i from 1 through 3 { /* 1から3まで(3を含む) */
  .for-through-#{$i} { width: 2em * $i; }
}
@for $i from 1 to 3 { /* 1から3まで(3を含まない) */
  .for-to-#{$i} { width: 2em * $i; }
}

/* ▼whileループ */
$i: 1;
@while $i <= 3 { /* $iが3以下の間繰り返す */
  .while-nobori-#{$i} { width: 2em * $i; }
  $i: $i + 1;
}
$i: 6;
@while $i > 0 { /* $iが0より大きい間繰り返す */
  .while-kudari-#{$i} { width: 2em * $i; }
  $i: $i - 2;
}

/* ▼eachループ */
$colors : red, green, blue;
@each $array in $colors { /* $colors配列の各要素に対して繰り返す */
  .#{$array}{
    color : $array;
  }
}

▼CSS

/* ▼for */
.for-through-1 { width: 2em; }
.for-through-2 { width: 4em; }
.for-through-3 { width: 6em; }
.for-to-1 { width: 2em; }
.for-to-2 { width: 4em; }

/* ▼while */
.while-nobori-1 { width: 2em; }
.while-nobori-2 { width: 4em; }
.while-nobori-3 { width: 6em; }
.while-kudari-6 { width: 12em; }
.while-kudari-4 { width: 8em; }
.while-kudari-2 { width: 4em; }

/* ▼each */
.red { color: red; }
.green { color: green; }
.blue { color: blue; }

実例

繰り返し構文は、以下のような実用的なシーンで活用できます。

▼SCSS

/* ▼background-imageとnth-childの組み合わせ */
li.bg-for {
  $count:5; // 繰り返す数
  @for $i from 1 through $count {
    &:nth-child(#{$i}) a {
      background: url(/icon-#{$i}.png);
    }
  }
}

/* ▼z-indexの連番生成 */
li.z-index {
  $i: 1;
  $count: 7; // リストの数
  @while $i <= $count {
    &:nth-child(#{$i}) {
      z-index: 801 - $i;
    }
    $i: $i + 1;
  }
}

/* ▼letter-spacingのバリエーション生成(eachループとリスト) */
$lsSize: (0, 25, 50, 75, 100);
@each $icon in $lsSize {
  .ls#{$icon} {
    letter-spacing: $icon*.001em;
  }
}

/* ▼Bootstrapのようなボタンサイズのバリエーション生成(eachループとMap型) */
$btn-sizes: (
  sm: 20px,
  md: 30px,
  lg: 40px
);
@each $modifier, $size in $btn-sizes {
  .btn--#{$modifier} {
    width: $size;
    height: $size;
  }
}

▼CSS

/* ▼backgroundとnth-child */
li.bg-for:nth-child(1) a { background: url(/icon-1.png); }
li.bg-for:nth-child(2) a { background: url(/icon-2.png); }
li.bg-for:nth-child(3) a { background: url(/icon-3.png); }
li.bg-for:nth-child(4) a { background: url(/icon-4.png); }
li.bg-for:nth-child(5) a { background: url(/icon-5.png); }

/* ▼z-index */
li.z-index:nth-child(1) { z-index: 800; }
li.z-index:nth-child(2) { z-index: 799; }
li.z-index:nth-child(3) { z-index: 798; }
li.z-index:nth-child(4) { z-index: 797; }
li.z-index:nth-child(5) { z-index: 796; }
li.z-index:nth-child(6) { z-index: 795; }
li.z-index:nth-child(7) { z-index: 794; }

/* ▼letter-spacing */
.ls0 { letter-spacing: 0em; }
.ls25 { letter-spacing: 0.025em; }
.ls50 { letter-spacing: 0.05em; }
.ls75 { letter-spacing: 0.075em; }
.ls100 { letter-spacing: 0.1em; }

/* ▼bootstrap? */
.btn--sm { width: 20px; height: 20px; }
.btn--md { width: 30px; height: 30px; }
.btn--lg { width: 40px; height: 40px; }

その他

SCSSの配列には、「Map型(連想配列)」やnth関数などの機能もあります。これらを組み合わせることで、さらに複雑で柔軟なCSSの自動生成が可能です。ぜひ調べてみましょう。

条件分岐

SCSSでは、@if@else if@elseを使った条件分岐が可能です。これにより、特定の条件に基づいて異なるCSSスタイルを適用でき、様々な状況に対応したWebサイトのデザインを効率的に作成できます。

記述例

▼SCSS

$signal: susume;

.signal_color {
  @if $signal == susume { /* もし変数が"進め"なら */
    color: green;
  } @else if $signal == tomare { /* もし変数が"止まれ"なら */
    color: red;
  } @else if $signal == chuui { /* もし変数が"注意"なら */
    color: yellow;
  } @else { /* 上記いずれでもないなら */
    color: black;
  }
}

▼CSS

.signal_color { color: green; }

実例

条件分岐は、以下のような実践的なWeb制作のシーンで役立ちます。

▼SCSS

@use "sass:color";

/* ▼グラデーションの有無を切り替えるmixinの例 */
@mixin gradient-bg($bg-color, $enable-gradients) {
  @if $enable-gradients { /* $enable-gradientsがtrueなら */
    background:
      $bg-color linear-gradient(180deg, color.mix(#fff, $bg-color, 15%), $bg-color)
      repeat-x;
  } @else { /* falseなら */
    background-color: $bg-color;
  }
}

.bg-gradient {
  @include gradient-bg($bg-color:#fc0, $enable-gradients:true);
}

.bg-no_gradient {
  @include gradient-bg($bg-color:#fc0, $enable-gradients:false);
}

/* ▼繰り返しと組み合わせたパターン(レスポンシブなカラム幅の自動生成) */
$columns:1;
@each $breakpoint in sm, md, lg { /* ブレイクポイントごとに処理 */
  @if $breakpoint == sm { /* smの場合 */
    $columns: 2;
  } @else if $breakpoint == md { /* mdの場合 */
    $columns: 3;
  } @else { /* lgの場合 */
    $columns: 4;
  }
  @for $i from 1 through $columns { /* 各ブレイクポイントでカラムを生成 */
    /* 割り算をmath.percentageなどで計算 */
    .col-#{$breakpoint}-#{$i} {
      width: percentage($i / $columns);
    }
  }
}

▼CSS

.bg-gradient {
  background: #fc0 linear-gradient(180deg, #ffd426, #fc0)
  repeat-x;
}
.bg-no_gradient { background-color: #fc0; }

/* ▼組み合わせ */
.col-sm-1 { width: 50%; }
.col-sm-2 { width: 100%; }
.col-md-1 { width: 33.3333333333%; }
.col-md-2 { width: 66.6666666667%; }
.col-md-3 { width: 100%; }
.col-lg-1 { width: 25%; }
.col-lg-2 { width: 50%; }
.col-lg-3 { width: 75%; }
.col-lg-4 { width: 100%; }

@use

@use "ファイル名" と記述することで、複数のSCSSファイルを一つにまとめてコンパイルできます。
Dart Sassでは従来の@importが廃止予定です。

記述例

▼SCSS

/* 以下のようなディレクトリ構造の場合 */
common  
│
├── css
│      └── style.css
│
└── scss
        ├── _variables.scss  /* 変数を定義 */
        ├── _mixin.scss      /* mixinを定義 */
        └── style.scss       /* メインのファイル */


/* --- _variables.scss の中身 --- */
$primary-color: #fc0;


/* --- _mixin.scss の中身 --- */
@mixin box-base {
  padding: 10px;
}


/* --- style.scss(読み込む側) --- */

/* ファイル名を指定して読み込む(拡張子不要) */
@use "variables";
@use "mixin";

.box {
  /* 名前空間(ファイル名)をつけて呼び出す */
  color: variables.$primary-color;
  @include mixin.box-base;
}

/* "as *" をつけると名前空間が不要になる */
@use "variables" as *;
@use "mixin" as *;

.box {
    /* variables.$primary-color と書かなくてOK */
    color: $primary-color;

    /* mixin.box-base と書かなくてOK */
    @include box-base;
}

その他

モジュールとして読み込むSCSSファイルには、単独でCSSにコンパイルされないよう先頭にアンダースコア(`_`)を付ける慣習があります(例:`_mediaquery.scss`)。これは「パーシャルファイル」と呼ばれ、SCSSをより構造的に管理するために推奨されています。

よくある質問(FAQ)

Dart SassとLibSassの違いは何ですか?
LibSass(C++実装)は開発が終了した旧式のSassコンパイラです。現在はDart Sass(Dart実装)が公式の推奨実装であり、最新機能はDart Sassにのみ追加されます。大きな違いとして、@importの代わりに@useを使うモジュールシステムや、色・計算関数の名前空間化(color.adjust, math.divなど)が挙げられます。

.

CONTACT

webサイト制作、デザインに関するご相談、御見積のご依頼など、弊社へのお問い合わせはこちら