はじめに
前回の記事ではJavaScriptでカルーセルと背景ぼかしを実装する方法を解説しました。今回は**Sass(サス)**の基本的な使い方を解説します。「CSSが長くなってきて管理しにくい」「同じ色コードを何度も書いている」「ネストした要素のセレクターを毎回フルパスで書くのが面倒」という悩みをSassは一気に解決してくれます。変数・ネスト・ミックスイン・関数を使いこなすことで、CSSが格段に書きやすく・読みやすく・メンテナンスしやすくなります。
1. Sassとは何か
1.1 Sassの概要
Sass(Syntactically Awesome Style Sheets):
CSSを拡張したメタ言語。
Sassで書いたコードを
コンパイル(変換)することで
通常のCSSが生成される。
ブラウザはSassを直接読めないため
必ずコンパイルが必要。
Sassの2つの記法:
① SCSS記法(推奨):
→ CSSとほぼ同じ書き方
→ ファイルの拡張子は .scss
→ 既存のCSSをそのまま使える
② Sass記法(インデント記法):
→ インデントでブロックを表現する
→ 波カッコ・セミコロンが不要
→ ファイルの拡張子は .sass
→ 現代のプロジェクトではほぼSCSS記法が使われる
→ この記事もSCSS記法で解説する
1.2 Sassを使うメリット
Sassを使うメリット:
① 変数で色・サイズを一元管理できる
→ 色を変えたいときに1箇所直すだけでOK
② ネストでセレクターを入れ子にできる
→ HTML構造に合わせてCSSを整理できる
③ ミックスインでCSSのまとまりを再利用できる
→ 同じプロパティ群を何度でも使い回せる
④ ファイルを分割して管理できる
→ コンポーネントごとにファイルを分けられる
⑤ 計算・関数が使える
→ 動的な値を計算して生成できる
⑥ ReactやViteと相性がよい
→ モダンな開発環境にシームレスに組み込める
2. Sassの環境を準備する
2.1 Viteプロジェクトに導入する(推奨)
bash
# Viteプロジェクトを作成する
npm create vite@latest my-project -- --template vanilla
cd my-project
# Sassをインストールする
npm install -D sass
# 開発サーバーを起動する
npm run dev
インストール後の使い方:
① src/style.scss を作成する(または .css を .scss に変更)
② main.js で .scss ファイルを import する
import './style.scss'
③ ViteがSCSSを自動でコンパイルしてくれる
→ 設定不要ですぐに使える
2.2 VSCodeで使う(簡単な方法)
VSCodeの拡張機能「Live Sass Compiler」を使う:
① VSCodeの拡張機能で
「Live Sass Compiler」を検索してインストール
② .scss ファイルを作成する
③ ステータスバーの「Watch Sass」をクリックする
④ .scss を保存するたびに
自動的に .css ファイルが生成される
→ HTMLには生成された .css ファイルを読み込む
2.3 npmのsassコマンドで使う
bash
# scss を css にコンパイルする(1回だけ)
npx sass src/style.scss dist/style.css
# ファイルの変更を監視して自動コンパイルする
npx sass --watch src/style.scss dist/style.css
# 圧縮して出力する
npx sass --style=compressed src/style.scss dist/style.min.css
3. 変数(Variables)
3.1 変数の基本
scss
// Sass の変数は $ で始まる
// CSS変数(--color-primary)とは別物
// ============================================
// 変数の定義
// ============================================
// カラー
$color-primary: #1A5FC0;
$color-secondary: #27AE60;
$color-accent: #EF9F27;
$color-text: #111827;
$color-text-sub: #6B7280;
$color-bg: #FFFFFF;
$color-bg-sub: #F9FAFB;
$color-border: #E5E7EB;
// フォントサイズ
$font-size-xs: 1.2rem;
$font-size-sm: 1.4rem;
$font-size-base: 1.6rem;
$font-size-lg: 1.8rem;
$font-size-xl: 2.0rem;
$font-size-2xl: 2.4rem;
$font-size-3xl: 3.2rem;
$font-size-4xl: 4.0rem;
// スペーシング
$space-1: 4px;
$space-2: 8px;
$space-3: 12px;
$space-4: 16px;
$space-5: 20px;
$space-6: 24px;
$space-8: 32px;
$space-10: 40px;
$space-12: 48px;
$space-16: 64px;
$space-24: 96px;
// ブレークポイント
$bp-sm: 640px;
$bp-md: 768px;
$bp-lg: 1024px;
$bp-xl: 1280px;
// その他
$radius-sm: 4px;
$radius-md: 8px;
$radius-lg: 12px;
$radius-xl: 16px;
$radius-full: 9999px;
$shadow-sm: 0 1px 3px rgba( 0, 0, 0, 0.08 );
$shadow-md: 0 4px 12px rgba( 0, 0, 0, 0.1 );
$shadow-lg: 0 8px 32px rgba( 0, 0, 0, 0.12 );
$transition-base: 0.2s ease;
$transition-slow: 0.4s ease;
3.2 変数を使う
// 変数を使ってスタイルを書く
.btn {
background-color: $color-primary;
color: $color-bg;
font-size: $font-size-base;
padding: $space-3 $space-6;
border-radius: $radius-md;
transition: background-color $transition-base;
&:hover {
background-color: darken( $color-primary, 10% );
// → darken()はSassの組み込み関数
// 色を指定した%分暗くする
}
}
.card {
background: $color-bg;
border: 1px solid $color-border;
border-radius: $radius-lg;
padding: $space-6;
box-shadow: $shadow-md;
}
// 変数を変えるだけでサイト全体の色が変わる
// → デザイン変更時の修正コストが激減する
💡 SassのI変数とCSS変数(カスタムプロパティ)は使い分けが大切です: Sassの変数はコンパイル時に値に置き換えられます。CSS変数(--color-primary)はブラウザでリアルタイムに変更できます。ダークモードの切り替えなど動的に変える必要があるものはCSS変数・静的な設定値はSassの変数が向いています。
4. ネスト(Nesting)
4.1 ネストの基本
// ❌ 通常のCSSの書き方(冗長)
.nav { display: flex; }
.nav a { color: #111; }
.nav a:hover { color: #1A5FC0; }
.nav .nav-item { padding: 0 16px; }
.nav .nav-item.is-active { font-weight: bold; }
// ✅ Sassのネストで整理する
.nav {
display: flex;
a {
color: #111;
text-decoration: none;
&:hover { // & = 親セレクター(.nav a:hover)
color: #1A5FC0;
}
}
.nav-item {
padding: 0 16px;
&.is-active { // .nav-item.is-active
font-weight: 700;
color: $color-primary;
}
}
}
4.2 &(アンパサンド)の使い方
/*
& は親セレクターを参照する特別な記号。
擬似クラス・擬似要素・修飾クラスに使う。
*/
.btn {
background: $color-primary;
color: #fff;
transition: background $transition-base;
// 擬似クラス
&:hover { background: darken( $color-primary, 8% ); }
&:focus { outline: 2px solid $color-primary; }
&:active { transform: translateY( 1px ); }
&:disabled {
background: $color-border;
cursor: not-allowed;
}
// 修飾クラス(バリアント)
&--secondary {
// .btn--secondary(BEM記法との相性がよい)
background: $color-secondary;
}
&--outline {
// .btn--outline
background: transparent;
border: 2px solid $color-primary;
color: $color-primary;
}
&--sm {
// .btn--sm
font-size: $font-size-sm;
padding: $space-2 $space-4;
}
&--lg {
// .btn--lg
font-size: $font-size-lg;
padding: $space-4 $space-8;
}
// 擬似要素
&::before {
content: '';
display: block;
}
// 親セレクターを後ろに置く(コンテキスト変更)
.dark-theme & {
// .dark-theme .btn
background: lighten( $color-primary, 15% );
}
}
4.3 ネストの注意点
/*
❌ 深くネストしすぎるのは避ける
→ 生成されるCSSが複雑になる
→ 詳細度が上がりすぎて上書きしにくくなる
*/
// ❌ 深すぎるネスト(3階層以下を推奨)
.card {
.card-body {
.card-title {
span { // ← 4階層目は避ける
em { // ← 5階層目は絶対NG
color: red;
}
}
}
}
}
// ✅ 適切な深さ(2〜3階層まで)
.card {
&-body { padding: $space-6; }
&-title { font-size: $font-size-xl; }
&-text { color: $color-text-sub; }
&-footer { padding-top: $space-4; }
}
5. ミックスイン(Mixins)
5.1 ミックスインの基本
/*
ミックスイン:
CSSのまとまりを定義して何度でも再利用できる仕組み。
@mixin で定義して @include で呼び出す。
*/
// ミックスインの定義
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@mixin flex-between {
display: flex;
align-items: center;
justify-content: space-between;
}
// ミックスインの使用
.hero {
@include flex-center;
height: 100vh;
}
.header {
@include flex-between;
padding: 0 $space-10;
height: 80px;
}
5.2 引数付きミックスイン
// 引数を受け取るミックスイン
@mixin button-variant( $bg, $color: #fff, $hover-bg: darken( $bg, 10% ) ) {
background-color: $bg;
color: $color;
&:hover {
background-color: $hover-bg;
}
}
// 使用例
.btn-primary { @include button-variant( $color-primary ); }
.btn-secondary { @include button-variant( $color-secondary ); }
.btn-danger { @include button-variant( #E24B4A ); }
.btn-dark { @include button-variant( #111827, #fff ); }
// ============================================
// メディアクエリのミックスイン
@mixin mq( $breakpoint ) {
@if $breakpoint == 'sm' {
@media ( min-width: $bp-sm ) { @content; }
} @else if $breakpoint == 'md' {
@media ( min-width: $bp-md ) { @content; }
} @else if $breakpoint == 'lg' {
@media ( min-width: $bp-lg ) { @content; }
} @else if $breakpoint == 'xl' {
@media ( min-width: $bp-xl ) { @content; }
}
}
// 使用例(モバイルファースト)
.section-title {
font-size: $font-size-2xl;
@include mq( 'md' ) {
font-size: $font-size-3xl;
}
@include mq( 'lg' ) {
font-size: $font-size-4xl;
}
}
5.3 よく使うミックスイン集
// ============================================
// よく使うミックスイン集
// ============================================
// テキストの省略(1行)
@mixin text-ellipsis {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
// テキストの省略(複数行)
@mixin line-clamp( $lines: 3 ) {
display: -webkit-box;
-webkit-line-clamp: $lines;
-webkit-box-orient: vertical;
overflow: hidden;
}
// アスペクト比を固定する
@mixin aspect-ratio( $ratio: '16/9' ) {
aspect-ratio: #{$ratio};
overflow: hidden;
}
// 絶対配置で中央揃え
@mixin absolute-center {
position: absolute;
top: 50%;
left: 50%;
transform: translate( -50%, -50% );
}
// すりガラス効果
@mixin glass-effect(
$bg: rgba( 255, 255, 255, 0.15 ),
$blur: 12px,
$border: rgba( 255, 255, 255, 0.2 )
) {
background: $bg;
backdrop-filter: blur( $blur );
-webkit-backdrop-filter: blur( $blur );
border: 1px solid $border;
}
// ホバー時の浮き上がり効果
@mixin hover-lift( $y: -4px, $shadow: $shadow-lg ) {
transition: transform $transition-base,
box-shadow $transition-base;
&:hover {
transform: translateY( $y );
box-shadow: $shadow;
}
}
// スクリーンリーダー専用テキスト
@mixin sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect( 0, 0, 0, 0 );
border: 0;
}
// 使用例
.card-title { @include text-ellipsis; }
.card-text { @include line-clamp( 2 ); }
.hero-image {
@include aspect-ratio( '16/9' );
img { width: 100%; height: 100%; object-fit: cover; }
}
.glass-header { @include glass-effect; }
.portfolio-card { @include hover-lift; }
.visually-hidden { @include sr-only; }
6. 関数(Functions)
6.1 Sassの組み込み関数
// ============================================
// よく使うSassの組み込み関数
// ============================================
// 色を操作する関数
$base: #1A5FC0;
.example {
// 暗くする
color: darken( $base, 10% ); // → 10%暗い
// 明るくする
color: lighten( $base, 10% ); // → 10%明るい
// 透明にする
color: rgba( $base, 0.5 ); // → 50%透明
// 彩度を下げる
color: desaturate( $base, 20% ); // → 彩度-20%
// 補色を取得する
color: complement( $base ); // → 反対色
// 色を混ぜる
color: mix( $base, #fff, 80% ); // → 白と80:20で混合
}
// 数値を操作する関数
.calc-example {
width: percentage( 1/3 ); // → 33.3333%
height: round( 16.7px ); // → 17px
margin: ceil( 10.2px ); // → 11px(切り上げ)
padding: floor( 10.8px ); // → 10px(切り捨て)
font-size: max( 1.4rem, 16px ); // → 大きい方を使う
font-size: min( 1.6rem, 18px ); // → 小さい方を使う
width: clamp( 300px, 50%, 600px ); // → 範囲内に収める
}
// 文字列を操作する関数
$prefix: 'is-';
.#{$prefix}active { color: red; } // → .is-active { color: red; }
6.2 カスタム関数を作る
// @function でオリジナルの関数を定義する
// rem変換関数(pxをremに変換する)
@function rem( $px, $base: 16 ) {
@return ( $px / $base ) * 1rem;
}
// 使用例
.title {
font-size: rem( 32 ); // → 2rem
margin: rem( 24 ); // → 1.5rem
}
// ============================================
// コンテナの幅を計算する関数
@function container-width( $columns, $total: 12, $gutter: 24px ) {
@return calc(
( 100% * #{$columns} / #{$total} ) - #{$gutter}
);
}
// z-indexを管理する関数
$z-index-map: (
'behind': -1,
'base': 0,
'raised': 1,
'dropdown': 10,
'sticky': 50,
'modal': 100,
'toast': 200,
);
@function z( $layer ) {
@if map-has-key( $z-index-map, $layer ) {
@return map-get( $z-index-map, $layer );
}
@warn "z-index '#{$layer}' は定義されていません";
@return 0;
}
// 使用例
.header { z-index: z( 'sticky' ); } // → 50
.modal { z-index: z( 'modal' ); } // → 100
.dropdown { z-index: z( 'dropdown' ); }// → 10
7. ファイルの分割と@use
7.1 ファイルを分割して管理する
推奨のファイル構成:
src/
scss/
├── abstracts/
│ ├── _variables.scss # 変数
│ ├── _mixins.scss # ミックスイン
│ └── _functions.scss # 関数
├── base/
│ ├── _reset.scss # リセットCSS
│ └── _typography.scss # タイポグラフィ
├── components/
│ ├── _button.scss # ボタン
│ ├── _card.scss # カード
│ ├── _modal.scss # モーダル
│ └── _carousel.scss # カルーセル
├── layout/
│ ├── _header.scss # ヘッダー
│ ├── _footer.scss # フッター
│ └── _grid.scss # グリッド
├── pages/
│ ├── _home.scss # トップページ
│ └── _contact.scss # お問い合わせ
└── style.scss # エントリーポイント
7.2 @use で読み込む(モダンな書き方)
// style.scss(エントリーポイント)
// @use でファイルを読み込む(モダンな書き方)
@use 'abstracts/variables' as v;
@use 'abstracts/mixins' as m;
@use 'abstracts/functions' as f;
@use 'base/reset';
@use 'base/typography';
@use 'components/button';
@use 'components/card';
@use 'components/modal';
@use 'layout/header';
@use 'layout/footer';
@use 'pages/home';
// _button.scss
// @use で変数を読み込む
@use '../abstracts/variables' as v;
@use '../abstracts/mixins' as m;
.btn {
background: v.$color-primary;
padding: v.$space-3 v.$space-6;
@include m.hover-lift;
&--secondary {
background: v.$color-secondary;
}
}
💡 @import は非推奨・@use を使いましょう: 古いSassの記事では @import が使われていますが現在は非推奨になっています。@use を使うとスコープが明確になり変数の衝突も防げます。
8. 実践的なSCSSファイル例
8.1 カードコンポーネントのSCSS
// _card.scss
@use '../abstracts/variables' as v;
@use '../abstracts/mixins' as m;
.card {
background: v.$color-bg;
border: 1px solid v.$color-border;
border-radius: v.$radius-lg;
overflow: hidden;
@include m.hover-lift;
// 画像
&__image {
@include m.aspect-ratio( '16/9' );
img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform v.$transition-slow;
}
}
&:hover &__image img {
transform: scale( 1.05 );
}
// 本文エリア
&__body {
padding: v.$space-6;
display: flex;
flex-direction: column;
gap: v.$space-3;
}
// タグ
&__tags {
display: flex;
flex-wrap: wrap;
gap: v.$space-2;
}
&__tag {
font-size: v.$font-size-xs;
padding: v.$space-1 v.$space-2;
background: rgba( v.$color-primary, 0.1 );
color: v.$color-primary;
border-radius: v.$radius-full;
font-weight: 600;
}
// タイトル
&__title {
font-size: v.$font-size-xl;
font-weight: 700;
line-height: 1.4;
@include m.line-clamp( 2 );
}
// テキスト
&__text {
font-size: v.$font-size-sm;
color: v.$color-text-sub;
line-height: 1.7;
@include m.line-clamp( 3 );
flex: 1;
}
// フッター
&__footer {
padding: v.$space-4 v.$space-6;
border-top: 1px solid v.$color-border;
@include m.flex-between;
}
// バリアント
&--horizontal {
display: grid;
grid-template-columns: 200px 1fr;
.card__image {
aspect-ratio: auto;
height: 100%;
}
}
&--featured {
border: none;
box-shadow: v.$shadow-lg;
.card__title {
font-size: v.$font-size-2xl;
}
}
}
9. 実践チェックリスト
✓ npm install -D sass でSassをインストールして .scss ファイルで書けるか確認したか
✓ 変数ファイル(_variables.scss)でカラー・スペーシング・ブレークポイントを一元管理しているか
✓ & を使ってBEM記法(.card__title・.card--featured)をネストで書けるか
✓ メディアクエリのミックスイン(@include mq('md'))を作ってモバイルファーストで書けるか
✓ メディアクエリのミックスイン(@include mq('md'))を作ってモバイルファーストで書けるか
✓ @import ではなく @use でファイルを読み込んでいるか
✓ ファイルをabstracts・base・components・layout・pagesに分割して管理しているか
✓ darken() / lighten() / rgba() などSassの色関数を活用しているか
✓ 3階層以上の深いネストを避けているか
まとめ
今回はSassの基本的な使い方として変数・ネスト・ミックスイン・関数を解説しました。ポイントをまとめると:
- SassはCSSを拡張したメタ言語でコンパイルが必要・ViteやLive Sass Compilerで簡単に導入できる
- 変数(
$color-primary)でカラー・スペーシング・ブレークポイントを一元管理すると変更コストが大幅に減る - ネストでHTML構造に合わせてCSSを整理できる・
&で親セレクターを参照してBEM記法と相性よく使える - ミックスイン(
@mixin/@include)でメディアクエリ・すりガラス・テキスト省略などをまとめて再利用できる darken()/lighten()/rgba()など組み込み関数で色を操作できる・@functionでカスタム関数も作れる- ファイルをabstracts・base・components・layoutに分割してコンポーネントごとに管理するとメンテナンスが楽になる
@importは非推奨・@useを使ってスコープを明確にする- ネストは3階層以下に抑える・深くしすぎると詳細度が上がり上書きしにくいCSSになる
次の記事では、Gitの基本的な使い方を解説します。バージョン管理の仕組み・コミット・ブランチ・GitHubへのプッシュなど、制作現場で必須のGitをゼロから学べる内容をお届けします。お楽しみに!
コメント