こんにちは、かつコーチです。
Sassで記述するときに、変数にしたり、ネストするのは最もシンプルです。
しかし、@mixinや@eachなどを扱うとなるとちょっと複雑になります。
今回は、Sass を使用して、指定したメディアクエリとクラス名の繰り返しを
効率よくまとめる方法を解説します。
ContainerをSassで効率よく書く方法
containerをCSSで記述してみます。
.container,
.container-fluid,
.container-sm,
.container-md,
.container-lg,
.container-xl,
.container-xxl {
width: 100%;
margin-right: auto;
margin-left: auto;
padding-right: 15px;
padding-left: 15px;
}
@media (min-width: 576px) {
.container,
.container-sm {
max-width: 540px;
}
}
@media (min-width: 768px) {
.container,
.container-sm,
.container-md {
max-width: 720px;
}
}
@media (min-width: 992px) {
.container,
.container-sm,
.container-md,
.container-lg {
max-width: 960px;
}
}
@media (min-width: 1200px) {
.container,
.container-sm,
.container-md,
.container-lg,
.container-xl {
max-width: 1140px;
}
}
@media (min-width: 1400px) {
.container,
.container-sm,
.container-md,
.container-lg,
.container-xl,
.container-xxl {
max-width: 1280px;
}
}
これでも良いのですが、もう少し効率よく書きたいです。
@mixin
や @each
を使うと、共通のスタイルやブレークポイントをまとめて簡潔に記述することが可能です。
以下は、Sassで最適化した例です。
$container-max-widths: (
sm: 540px,
md: 720px,
lg: 960px,
xl: 1140px,
xxl: 1280px
);
$breakpoints: (
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px
);
// ブレークポイントに対応するクラス名を生成
@mixin container-max-width($breakpoint-name, $breakpoint-size, $max-width, $previous-breakpoints) {
@media (min-width: $breakpoint-size) {
.container, .container-#{$breakpoint-name}#{$previous-breakpoints} {
max-width: $max-width;
}
}
}
// 前のブレークポイントを組み込むためのループ
$previous-breakpoints: '';
@each $breakpoint-name, $breakpoint-size in $breakpoints {
@include container-max-width(
$breakpoint-name,
$breakpoint-size,
map-get($container-max-widths, $breakpoint-name),
$previous-breakpoints
);
// 各ブレークポイント名を連結して、次のループに渡す
$previous-breakpoints: $previous-breakpoints + ', .container-' + $breakpoint-name;
}
// 共通スタイル
.container,
.container-fluid,
.container-sm,
.container-md,
.container-lg,
.container-xl,
.container-xxl {
width: 100%;
margin-right: auto;
margin-left: auto;
padding-right: 15px;
padding-left: 15px;
}
コードの説明
@mixin container-max-width
:- ここで渡されたブレークポイント名 (
$breakpoint-name
) と、その前に処理されたブレークポイントのクラス名を一緒に指定するようにしています。 $previous-breakpoints
は、現在のブレークポイント以前のすべてのクラスを一緒に含めるための変数です。
- ここで渡されたブレークポイント名 (
@each
ループ:$previous-breakpoints
に、前のループで生成した.container-sm
,.container-md
などのクラス名を追加し、次のブレークポイントでもこれらのクラスを引き継ぎます。- つまり、例えば
md
ブレークポイントでは、.container-sm
も含める形になります。
詳しく解説
$breakpoints の定義
まず、$breakpoints
は以下のように キー と 値 のペアで定義されています。
$breakpoints: (
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px
);
この書き方はSassの マップ です。
sm
,md
,lg
などが「名前」 (キー) で、576px
,768px
などが「値」になります。
@each の使い方
次に、@each
文で、このマップ $breakpoints
の キー と 値 を取り出しています。
@each $breakpoint-name, $breakpoint-size in $breakpoints {
// 中で処理を行う
}
@each
はループを作り、$breakpoint-name
にはマップのキー(sm
,md
,lg
など)が入ります。$breakpoint-size
にはマップの値(576px
,768px
,992px
など)が入ります。
具体的には、次のようにループが進みます:
- 最初のループ:
$breakpoint-name
=sm
$breakpoint-size
=576px
- 次のループ:
$breakpoint-name
=md
$breakpoint-size
=768px
- さらに次のループ:
$breakpoint-name
=lg
$breakpoint-size
=992px
…と、このようにループしていきます。
@mixin との組み合わせ
@each
ループ内で、これらの $breakpoint-name
と $breakpoint-size
を使って、@mixin
に値を渡しています。
@include container-max-width(
$breakpoint-name, // sm, md, lg など
$breakpoint-size, // 576px, 768px, 992px など
map-get($container-max-widths, $breakpoint-name), // $container-max-widths マップから対応する max-width を取得
$previous-breakpoints // 以前のブレークポイントを含むクラスを渡す
);
@include
は、引数として以下を渡しています:
$breakpoint-name
:sm
,md
,lg
など、ブレークポイントの名前$breakpoint-size
:576px
,768px
,992px
など、ブレークポイントのサイズmap-get($container-max-widths, $breakpoint-name)
: 対応する最大幅を取得します。例:map-get($container-max-widths, sm)
は540px
を返します。$previous-breakpoints
: これには、前のブレークポイント名が含まれます(後述)。
$previous-breakpoints の仕組み
この変数は、最初は空の状態からスタートします。
$previous-breakpoints: '';
各ループの中で、前のブレークポイント名を連結していきます:
$previous-breakpoints: $previous-breakpoints + ', .container-' + $breakpoint-name;
このようにすることで、各ループで次のブレークポイントに移るたびに、これまでに処理したブレークポイントのクラスが一緒に追加されます。
例えば、ループが進むにつれて、次のように値が変わります:
- 最初のループ (
sm
の場合):$previous-breakpoints
=''
(空)
- 次のループ (
md
の場合):$previous-breakpoints
=', .container-sm'
- さらに次のループ (
lg
の場合):$previous-breakpoints
=', .container-sm, .container-md'
実際のループ処理例
例えば、ループの2回目 (md
の場合) では、以下のように処理されます:
@include container-max-width(
md, // ブレークポイント名
768px, // ブレークポイントサイズ
720px, // $container-max-widths から取得した md に対応する max-width
', .container-sm' // 以前のブレークポイント名を連結
);
このループの結果、次のようなCSSが生成されます:
@media (min-width: 768px) {
.container, .container-sm, .container-md {
max-width: 720px;
}
}
これにより、768px
以上の画面幅では、.container
, .container-sm
, .container-md
すべてに max-width: 720px
が適用されます。
まとめ
@each
でループを回して、Sassのマップ$breakpoints
からブレークポイントの 名前 と サイズ を取り出しています。@mixin
にその名前とサイズを渡し、前のブレークポイント名と連結して、一緒にスタイルを適用しています。@mixin
はカスタムで作成され、複数のブレークポイントに対応するコンテナのmax-width
を動的に定義するようになっています。
これにより、メディアクエリやクラスの繰り返しを最小限に抑え、保守性の高いコードになります。
また、マップを使っているので、新しいブレークポイントや最大幅を追加する際にも簡単に対応可能です。
Sass を使用すれば、指定したメディアクエリとクラス名の繰り返しを効率よく書くことができます。
これ以外の指定も備忘録として残しておこうと思います。
参考にしてください。