【SCSS】メディアクエリを爆速に!@mixinとmap変数を使ったレスポンシブ管理術

Webサイトのレスポンシブ対応を行う際、CSSで毎回 @media (min-width: 768px) { ... } のように記述していませんか?

この書き方だと、コードが冗長になるだけでなく、後から「タブレットのブレイクポイントを 768px から 820px に変更したい」となった時に、全ファイルの該当箇所を書き換えるという地獄の作業が発生してしまいます。

そんな悩みを一発で解決するのが、SCSS(Sass)の map 変数と @mixin を使った一元管理テクニックです! これを設定しておけば、以降は @include mq(md) { ... } とたった1行書くだけでメディアクエリが適用でき、数値の変更も1ファイル直すだけで全ページに反映されるようになります。

今回は、保守性の高いSCSSのディレクトリ設計とメディアクエリの実装方法をご紹介します!

デモ動作

See the Pen @mixinとmap変数を使ったレスポンシブ管理術 by mikanbako (@mikanbako) on CodePen.

全画面でのデモ動作は以下のリンクからご確認下さい!(別タブで開かれます)

実装コードの紹介

【HTML】

<div class="l-wrap">
  <div class="p-box">
    <p class="p-box__text">
      ブラウザの幅を広げたり縮めたりしてみてね!<br>
      <span class="u-show-sp">現在の状態:【スマホサイズ📱】</span>
      <span class="u-show-pc">現在の状態:【PCサイズ💻】</span>
    </p>
  </div>
</div>

【SCSS】

/* =========================================
   ① 変数の定義(本来は _variables.scss などに記述)
========================================= */
$breakpoints: (
  'sm': '(width >= 576px)',
  'md': '(width >= 768px)',
  'lg': '(width >= 1024px)'
);

/* =========================================
   ② mixinの定義(本来は _mixins.scss などに記述)
========================================= */
@use "sass:map";
// ※別ファイルではここで @use "variables" as v; などを読み込みます

@mixin mq($breakpoint) {
  // map.has-key で指定したキーが存在するかチェックする
  @if map.has-key($breakpoints, $breakpoint) {
    @media #{map.get($breakpoints, $breakpoint)} {
      @content; /* ここに @include した際のCSSの中身が入ります */
    }
  } @else {
    @error "指定されたブレイクポイント '#{$breakpoint}' は存在しません。";
  }
}

/* =========================================
   ③ 実際のスタイル適用
========================================= */
.l-wrap {
  padding: 20px;
}

.p-box {
  border-radius: 8px;
  padding: 30px;
  text-align: center;
  font-weight: bold;
  transition: all 0.3s ease-out;
  
  /* スマホ時のベーススタイル */
  background-color: #fee7e7;
  color: #c72c4c;
  
  /* PC(md以上)でのスタイル上書き */
  @include mq(md) {
    background-color: #e7f6fe;
    color: #1bb4d4;
    padding: 60px;
  }
}

/* 表示の切り替え用ユーティリティクラス */
.u-show-pc {
  display: none; // スマホでは隠す
  @include mq(md) {
    display: inline; // PCでは表示
  }
}

.u-show-sp {
  display: inline; // スマホでは表示
  @include mq(md) {
    display: none; // PCでは隠す
  }
}

コードの解説・こだわったポイント

実務を想定したファイルの分割管理

デモ環境(CodePen)では1つのファイルにまとめて記述していますが、実際の開発現場では global フォルダなどに分けて保守性を高めます。

global/_variables.scss
サイト全体のカラーやブレイクポイントを変数として定義するファイル。

global/_mixins.scss
メディアクエリなどの便利な関数(mixin)をまとめるファイル。

_mixins.scss 内で @use "variables" as v; のように変数を読み込み、各コンポーネントからは、この _mixins.scss を読み込む(またはglobalフォルダに_index.scssを用意して全体を読み込む)だけでメディアクエリが使えるように設計するのが一般的です。

sass:map@error を使った安全設計

@mixin mq($breakpoint) {
  // map.has-key で指定したキーが存在するかチェックする
  @if map.has-key($breakpoints, $breakpoint) {
    @media #{map.get($breakpoints, $breakpoint)} {
      @content; /* ここに @include した際のCSSの中身が入ります */
    }
  } @else {
    @error "指定されたブレイクポイント '#{$breakpoint}' は存在しません。";
  }
}

@mixin mq($breakpoint) の中身では、Sassの組み込みモジュールである map を使用しています。 単純に値を返すだけでなく、map.has-key を使って「存在しないブレイクポイント名(例えば md ではなく mm など)が指定された場合」にコンパイルエラー(@error)を出して知らせてくれる安全設計にしています。

モダンな Range Syntax による記述

$breakpoints: (
  'sm': '(width >= 576px)',
  'md': '(width >= 768px)',
  'lg': '(width >= 1024px)'
);

今回の $breakpoints の値には、従来の min-width: 768px ではなく、width >= 768px という直感的な記法(Media Queries Level 4 の Range Syntax)を採用しています。よりモダンでスッキリとしたコードを書くことができます。

まとめ

今回は、SCSSの機能を活用して、レスポンシブ対応のメディアクエリをスマートに管理・運用する方法をご紹介しました。

はじめに _variables_mixins の環境を構築する手間はかかりますが、この土台さえ作ってしまえば、それ以降のCSSコーディングの速度と保守性は格段に跳ね上がります。

「ただ動くものを作る」だけでなく、「後から他の人が見ても修正しやすい、安全で破綻しにくい設計」を意識して、日々のフロントエンド開発に取り組んでいきたいと思います!

Prev
Next