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: #fc0; 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()関数を使用します。
記述例
▼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 の余り * 1% */
文字列の連結
文字列の連結も可能です。+演算子を使って、複数の文字列変数や固定文字列を結合できます。
▼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:math、sass:color、sass: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など)が挙げられます。 - SCSSの「入れ子」は、どのくらい深くしても大丈夫ですか?
- 入れ子を深くしすぎると、生成されるCSSのセレクタが非常に長くなり、Webサイトの表示速度に悪影響を与えたり、コードが読みにくくなったりする可能性があります。一般的には、CSSの優先順位とレンダリング効率を考慮し、1〜3段階の深さに抑えるのが理想的です。多くても4段階以内に収めることを意識しましょう。
- @mixinと@extendは、どのように使い分ければ良いですか?
@mixinは、共通のプロパティセットをまとめて再利用したい場合に最適です。例えば、ベンダープレフィックス付きのスタイルや、グラデーションの定義など、引数を使って柔軟に変化させたいスタイルに向いています。一方、@extendは、既存のセレクタが持つ「全てのスタイル」を別のセレクタに継承させたい場合に有効です。主に、共通の見た目を持つ要素に対して、ベースとなるスタイルを継承させ、特定の差異だけを上書きしたい場合などに使います。ただし、@extendはCSSの出力が複雑になることがあるため、使用は慎重に、特にコンポーネント内で完結させるなど範囲を限定することが推奨されます。
