CSS

Sass/SCSS入門|CSSを効率的に書くプリプロセッサ

CSS Sass SCSS

Sass/SCSS入門
CSSを効率的に書くプリプロセッサ

Sass/SCSSの基本機能を解説。変数、ネスト、ミックスイン、継承、関数まで、CSSをより効率的に書く方法を学べます。

こんな人向けの記事です

  • Sass/SCSSを初めて使う
  • CSSの記述を効率化したい
  • ミックスインや継承を活用したい

Step 1Sass/SCSSとは

Sass(Syntactically Awesome Style Sheets)は、CSSを拡張したプリプロセッサです。変数、ネスト、ミックスインなどの機能を使って、CSSをより効率的に記述できます。最終的にはコンパイルされて通常のCSSファイルに変換されます。

SassとSCSSの違い
Sassには2つの構文があります。SCSS(.scss)はCSSと互換性のある構文で、波括弧とセミコロンを使います。Sass(.sass)はインデントベースの構文です。現在はSCSSが主流のため、この記事ではSCSS構文を使用します。
項目SCSS (.scss)Sass (.sass)
構文CSSと互換性あり(波括弧 + セミコロン)インデントベース(波括弧・セミコロン不要)
学習コスト低い(CSSがそのまま書ける)やや高い(独自の記法)
普及度主流少数派
拡張子.scss.sass
SCSS(.scss)
// SCSS構文 - CSSと互換性あり
.container {
  max-width: 1200px;
  margin: 0 auto;

  .header {
    background: #333;
    color: #fff;
  }
}
Sass(.sass)
// Sass構文 - インデントベース
.container
  max-width: 1200px
  margin: 0 auto

  .header
    background: #333
    color: #fff
コンパイル後のCSS
/* どちらも同じCSSにコンパイルされる */
.container {
  max-width: 1200px;
  margin: 0 auto;
}
.container .header {
  background: #333;
  color: #fff;
}
Sassの導入方法
npm install -g sass でインストールし、sass input.scss output.css でコンパイルできます。
sass --watch input.scss:output.css でファイル変更を監視して自動コンパイルも可能です。

Step 2変数($variable)

Sassでは$記号を使って変数を定義できます。色やフォントサイズなど、繰り返し使う値を一箇所で管理でき、変更時の修正漏れを防げます。

SCSS
// 変数の定義
$primary-color: #3498db;
$secondary-color: #2ecc71;
$text-color: #333;
$font-stack: 'Noto Sans JP', sans-serif;
$base-spacing: 16px;
$border-radius: 4px;

// 変数の使用
body {
  font-family: $font-stack;
  color: $text-color;
}

.button {
  background-color: $primary-color;
  padding: $base-spacing;
  border-radius: $border-radius;
  color: #fff;

  &:hover {
    background-color: darken($primary-color, 10%);
  }
}

.alert {
  background-color: lighten($secondary-color, 30%);
  border: 1px solid $secondary-color;
  padding: $base-spacing;
  border-radius: $border-radius;
}
コンパイル後のCSS
body {
  font-family: "Noto Sans JP", sans-serif;
  color: #333;
}

.button {
  background-color: #3498db;
  padding: 16px;
  border-radius: 4px;
  color: #fff;
}
.button:hover {
  background-color: #217dbb;
}

.alert {
  background-color: #a3e9bc;
  border: 1px solid #2ecc71;
  padding: 16px;
  border-radius: 4px;
}
データ型説明
数値$size: 16px;単位付き・なし両方可
文字列$font: 'Arial';クォートあり・なし両方可
$color: #3498db;HEX, RGB, HSL, 色名すべて可
真偽値$debug: true;条件分岐に使用
リスト$sizes: 8px 16px 24px;スペースまたはカンマ区切り
マップ$colors: (primary: #3498db);キーと値のペア
null$value: null;値なし(プロパティ自体が出力されない)
CSS変数(カスタムプロパティ)との違い
Sass変数はコンパイル時に値が確定し、出力CSSには変数は残りません。一方、CSS変数(--primary: #3498db)はブラウザ実行時に解決されるため、JavaScriptでの動的変更やメディアクエリ内での切り替えが可能です。用途に応じて使い分けましょう。

Step 3ネスト(入れ子構造)

SCSSではセレクタをネスト(入れ子)にして記述できます。HTMLの構造に沿って書けるため、CSSの見通しが良くなります。

SCSS
// ネストの基本
.navbar {
  background: #333;
  padding: 10px 20px;

  .logo {
    font-size: 24px;
    font-weight: bold;
    color: #fff;
  }

  .nav-list {
    list-style: none;
    display: flex;
    gap: 20px;

    .nav-item {
      a {
        color: #ccc;
        text-decoration: none;

        &:hover {
          color: #fff;
        }

        &.active {
          color: #3498db;
          font-weight: bold;
        }
      }
    }
  }
}
コンパイル後のCSS
.navbar {
  background: #333;
  padding: 10px 20px;
}
.navbar .logo {
  font-size: 24px;
  font-weight: bold;
  color: #fff;
}
.navbar .nav-list {
  list-style: none;
  display: flex;
  gap: 20px;
}
.navbar .nav-list .nav-item a {
  color: #ccc;
  text-decoration: none;
}
.navbar .nav-list .nav-item a:hover {
  color: #fff;
}
.navbar .nav-list .nav-item a.active {
  color: #3498db;
  font-weight: bold;
}
&(親セレクタ参照)の活用
& は親セレクタ自体を参照します。擬似クラス(&:hover)、修飾クラス(&.active)、BEM記法(&__element, &--modifier)で活用できます。
SCSS - &の活用パターン
// BEM記法との組み合わせ
.card {
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);

  // Element: &__
  &__header {
    padding: 16px;
    border-bottom: 1px solid #eee;
  }

  &__body {
    padding: 16px;
  }

  &__footer {
    padding: 16px;
    border-top: 1px solid #eee;
  }

  // Modifier: &--
  &--featured {
    border: 2px solid #3498db;
  }

  &--dark {
    background: #333;
    color: #fff;
  }
}

// コンパイル結果:
// .card { ... }
// .card__header { ... }
// .card__body { ... }
// .card__footer { ... }
// .card--featured { ... }
// .card--dark { ... }
SCSS - プロパティのネスト
// プロパティのネスト(font-, margin-, border- など)
.text {
  font: {
    family: 'Noto Sans JP', sans-serif;
    size: 16px;
    weight: 400;
  }
  margin: {
    top: 0;
    bottom: 16px;
  }
  border: {
    style: solid;
    width: 1px;
    color: #ddd;
    radius: 4px;
  }
}

// コンパイル結果:
// .text {
//   font-family: 'Noto Sans JP', sans-serif;
//   font-size: 16px;
//   font-weight: 400;
//   margin-top: 0;
//   margin-bottom: 16px;
//   border-style: solid;
//   border-width: 1px;
//   border-color: #ddd;
//   border-radius: 4px;
// }
ネストは3〜4階層までに留める
ネストが深すぎると、コンパイル後のセレクタが長くなり(.a .b .c .d .e { })、詳細度が高くなりすぎます。一般的に3〜4階層までに留めるのがベストプラクティスです。深くなりすぎる場合は、コンポーネントの分割を検討しましょう。

Step 4ミックスイン(@mixin, @include)

ミックスインは、再利用可能なスタイルの塊を定義する機能です。@mixinで定義し、@includeで呼び出します。引数を渡すこともでき、柔軟なスタイル生成が可能です。

SCSS - ミックスインの基本
// 引数なしのミックスイン
@mixin flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

// 引数ありのミックスイン
@mixin button-style($bg-color, $text-color: #fff) {
  display: inline-block;
  padding: 10px 24px;
  background-color: $bg-color;
  color: $text-color;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;

  &:hover {
    background-color: darken($bg-color, 10%);
  }
}

// 使用例
.hero {
  @include flex-center;
  min-height: 400px;
}

.btn-primary {
  @include button-style(#3498db);
}

.btn-danger {
  @include button-style(#e74c3c);
}

.btn-outline {
  @include button-style(transparent, #333);
  border: 2px solid #333;
}
コンパイル後のCSS
.hero {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 400px;
}

.btn-primary {
  display: inline-block;
  padding: 10px 24px;
  background-color: #3498db;
  color: #fff;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}
.btn-primary:hover {
  background-color: #217dbb;
}

.btn-danger {
  display: inline-block;
  padding: 10px 24px;
  background-color: #e74c3c;
  color: #fff;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}
.btn-danger:hover {
  background-color: #c0392b;
}
SCSS - 実用的なミックスイン集
// レスポンシブ対応ミックスイン
@mixin responsive($breakpoint) {
  @if $breakpoint == mobile {
    @media (max-width: 767px) { @content; }
  } @else if $breakpoint == tablet {
    @media (max-width: 1023px) { @content; }
  } @else if $breakpoint == desktop {
    @media (min-width: 1024px) { @content; }
  }
}

// テキスト省略(1行)
@mixin text-ellipsis {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

// テキスト省略(複数行)
@mixin line-clamp($lines) {
  display: -webkit-box;
  -webkit-line-clamp: $lines;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

// 使用例
.sidebar {
  width: 300px;

  @include responsive(mobile) {
    width: 100%;
    display: none;
  }
}

.card-title {
  @include text-ellipsis;
  font-size: 18px;
}

.card-description {
  @include line-clamp(3);
  font-size: 14px;
}
@content でブロックを渡す
@content を使うと、ミックスインの呼び出し時に{ }内のスタイルブロックを渡せます。上のレスポンシブミックスインのように、メディアクエリのラッパーとして使う場合に便利です。

Step 5継承(@extend, %placeholder)

@extendを使うと、あるセレクタのスタイルを別のセレクタに継承できます。ミックスインと似ていますが、コンパイル結果が異なります。@extendはセレクタをグループ化してCSSを共有します。

SCSS - @extendの基本
// 通常のセレクタを継承
.message {
  padding: 12px 16px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
}

.success-message {
  @extend .message;
  border-color: #2ecc71;
  background-color: #eafaf1;
  color: #27ae60;
}

.error-message {
  @extend .message;
  border-color: #e74c3c;
  background-color: #fdedec;
  color: #c0392b;
}
コンパイル後のCSS
/* セレクタがグループ化される */
.message, .success-message, .error-message {
  padding: 12px 16px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
}

.success-message {
  border-color: #2ecc71;
  background-color: #eafaf1;
  color: #27ae60;
}

.error-message {
  border-color: #e74c3c;
  background-color: #fdedec;
  color: #c0392b;
}
%placeholder(プレースホルダーセレクタ)
%で始まるセレクタは「プレースホルダー」と呼ばれ、@extend専用のセレクタです。単体ではCSSに出力されないため、継承元としてのみ使いたい場合に最適です。
SCSS - %placeholderの活用
// プレースホルダー(単体ではCSSに出力されない)
%reset-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

%flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

%visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

// 使用例
.nav-list {
  @extend %reset-list;
  display: flex;
  gap: 16px;
}

.footer-links {
  @extend %reset-list;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.icon-button {
  @extend %flex-center;
  width: 40px;
  height: 40px;
}

.sr-only {
  @extend %visually-hidden;
}
コンパイル後のCSS
/* %reset-list はCSSに出力されず、使用箇所のみ出力 */
.nav-list, .footer-links {
  margin: 0;
  padding: 0;
  list-style: none;
}

.icon-button {
  display: flex;
  justify-content: center;
  align-items: center;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

.nav-list {
  display: flex;
  gap: 16px;
}

.footer-links {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.icon-button {
  width: 40px;
  height: 40px;
}
比較項目@mixin + @include@extend + %placeholder
引数使える使えない
CSS出力呼び出し箇所ごとにスタイルが複製されるセレクタがグループ化されて共有
ファイルサイズ大きくなりやすい小さくなりやすい
メディアクエリ内使える使えない(制約あり)
用途引数で値を変えたいパターン完全に同じスタイルを共有したいパターン
@extendの注意点
@extendはメディアクエリをまたいで使えません。また、複雑なセレクタと組み合わせると予期せぬセレクタが生成される場合があります。迷ったら@mixinを使う方が安全です。

Step 6関数と演算

Sassには多くの組み込み関数があり、色の操作や数値の計算を簡単に行えます。また、自分で関数を定義することもできます。

SCSS - 色の操作関数
$base-color: #3498db;

.color-demo {
  // 明るくする / 暗くする
  color: lighten($base-color, 20%);    // #a3d4f7
  color: darken($base-color, 20%);     // #1d6fa5

  // 彩度の調整
  color: saturate($base-color, 20%);   // 彩度を上げる
  color: desaturate($base-color, 20%); // 彩度を下げる

  // 透明度の調整
  color: rgba($base-color, 0.5);       // 50%透明
  color: opacify(rgba($base-color, 0.5), 0.3); // 透明度を下げる

  // 色の混合
  color: mix(#3498db, #e74c3c, 50%);   // 2色を50%ずつ混合

  // 補色
  color: complement($base-color);      // 補色を取得

  // グレースケール
  color: grayscale($base-color);       // グレーに変換
}
SCSS - 数値の演算
// 四則演算
.container {
  width: 100% - 20px;        // ※ 単位が異なる場合はcalc()を使う
  width: calc(100% - 20px);  // CSS calc() も使える
  padding: 16px / 2;         // 8px ※ Dart Sass ではmath.divを推奨
  margin: 8px * 2;           // 16px
}

// 数値関数
@use "sass:math";

.example {
  width: math.div(100%, 3);       // 33.3333%
  height: math.round(16.7px);     // 17px
  min-height: math.max(200px, 50vh); // 大きい方を選択
  font-size: math.abs(-16px);     // 16px
}
SCSS - カスタム関数(@function)
// pxをremに変換する関数
@function px-to-rem($px, $base: 16px) {
  @return math.div($px, $base) * 1rem;
}

// スペーシングスケール関数
@function spacing($multiplier) {
  $base: 8px;
  @return $base * $multiplier;
}

// カラーパレット生成関数
@function shade($color, $level) {
  @return mix(black, $color, $level * 10%);
}

@function tint($color, $level) {
  @return mix(white, $color, $level * 10%);
}

// 使用例
.heading {
  font-size: px-to-rem(24px);      // 1.5rem
  margin-bottom: spacing(3);        // 24px
  color: shade(#3498db, 3);         // 30%暗くした色
}

.card {
  padding: spacing(2) spacing(3);   // 16px 24px
  background: tint(#3498db, 7);     // 70%明るくした色
  font-size: px-to-rem(14px);       // 0.875rem
}
SCSS - 文字列関数とリスト関数
@use "sass:string";
@use "sass:list";

// 文字列関数
$class-name: "button";
.#{$class-name} {
  // 変数展開で動的クラス名
  display: inline-block;
}

// リストとループの組み合わせ
$sizes: (sm: 12px, md: 16px, lg: 20px, xl: 24px);

@each $name, $size in $sizes {
  .text-#{$name} {
    font-size: $size;
  }
}

// コンパイル結果:
// .text-sm { font-size: 12px; }
// .text-md { font-size: 16px; }
// .text-lg { font-size: 20px; }
// .text-xl { font-size: 24px; }

// @for ループ
@for $i from 1 through 5 {
  .mt-#{$i} {
    margin-top: 8px * $i;
  }
}

// コンパイル結果:
// .mt-1 { margin-top: 8px; }
// .mt-2 { margin-top: 16px; }
// .mt-3 { margin-top: 24px; }
// .mt-4 { margin-top: 32px; }
// .mt-5 { margin-top: 40px; }
@functionと@mixinの使い分け
@functionは値を返すもの(計算結果)に使い、@mixinはスタイルブロックを出力するものに使います。
例: px-to-rem()は値を返すので関数、flex-centerはスタイル群を出力するのでミックスイン。

まとめSass/SCSSのポイント

機能ポイント
変数$で定義。色・サイズ・フォントなど繰り返す値を一元管理
ネストHTML構造に沿った記述が可能。&で親セレクタを参照。3〜4階層まで
ミックスイン引数付きで再利用可能なスタイル。@contentでブロックも渡せる
継承@extendでセレクタを共有。%placeholderで出力を制御
関数色操作・数値計算の組み込み関数。@functionでカスタム関数も定義可能
ループ@each, @forでユーティリティクラスを効率的に生成

学習チェックリスト

  • SCSSファイルをCSSにコンパイルできる
  • 変数を使って色やサイズを一元管理できる
  • ネストを使ってHTMLに対応したCSSを書ける
  • &を使って擬似クラスやBEM記法を記述できる
  • ミックスインで再利用可能なスタイルを定義できる
  • @extendと%placeholderの違いを理解している
  • 色操作関数(lighten, darken, mix)を使える
  • @functionでカスタム関数を定義できる
  • @eachや@forでユーティリティクラスを生成できる