Sass(Scss) : メディアクエリ用のミックスイン
- Published:
、『Sass入門 〜より効率的なCSSコーディング』(※電子書籍のみです)にSass 3.2の内容を追加したので、記念にメディアクエリ用のミックスインを作りました。
@media
ルールを都度記述するのは面倒ですし、同じ要素やモジュールのスタイルを各@media
ルールに分けて書くことも面倒です。今回作ったミックスインを使えば、これらの問題を解決することができます。
- 出力したいCSSの例
- 要素やモジュール単位で書く方法
- メディア特性ごとにスタイルを書く方法
- 2つの方法を一緒に使う
- 2つの任意のメディア特性に同じスタイルを適用したい場合
- メディア特性ごとにCSSファイル自体を分ける場合
- ミックスインと設定用の変数
出力したいCSSの例
例えば次のようなCSSを出力したい場合があるとします。
/* 全てに適用 */ h1 { width: 100%; } p { line-height: 1.4; } /* 主にPC用 */ @media only screen and (min-width: 801px) { h1 { color: red; } p { margin: 1em 0; } } /* タブレット用 */ @media only screen and (min-width: 481px) and (max-width: 800px) { h1 { color: blue; } p { margin: 0.8em 0; } } /* スマートフォン用 */ @media only screen and (max-width: 480px) { h1 { color: green; } p { margin: 0.6em 0; } }
これを2種類の方法で書くことができます。
両方とも@include mq {}
の中にスタイルを書き、@media
の代わりに@if
で分けます。
1. 要素やモジュール単位でスタイルを書く方法
@include mq { h1 { @if $mq-all { // 全てに適用 width: 100%; } @if $mq-default { // 主にPC用 color: red; } @if $mq-tablet { // タブレット用 color: blue; } @if $mq-sp { // スマートフォン用 color: green; } } p { @if $mq-all { line-height: 1.4; } @if $mq-default { margin: 1em 0; } @if $mq-tablet { margin: 0.8em 0; } @if $mq-sp { margin: 0.6em 0; } } }
2. メディア特性ごとにスタイルを書く方法
@include mq { @if $mq-all { // 全てに適用 h1 {...} p {...} } @if $mq-default { // 主にPC用 h1 {...} p {...} } @if $mq-tablet { // タブレット用 h1 {...} p {...} } @if $mq-sp { // スマートフォン用 h1 {...} p {...} } }
1つの要素やモジュールのスタイルを一箇所に記述できるので、どちらかと言えば1つ目の方法が好みですが、場合によっては2つ目の方法も使うと良いと思います。
実は、この2つの方法を一緒に使うこともできます。
2つの方法を一緒に使う
例えば、スマートフォン向けにスタイルの追加や上書きをまとめて書きたい場合は@if $mq-sp {}
の中にまとめてスタイルを書いたほうがラクです。
次のコードではh1
は1つ目の方法で、それ以外は2つ目の方法で書いています。
@include mq { h1 { @if $mq-tablet { color: blue; } @if $mq-sp { color: green; } } @if $mq-sp { header { background: url(...); } p { margin: 0.6em 0; } nav { width: 100%; } : } }
これをコンパイルすると次のようになります。
@media only screen and (min-width: 481px) and (max-width: 800px) { h1 { color: blue; } } @media only screen and (max-width: 480px) { h1 { color: green; } header { background: url(...); } p { margin: 0.6em 0; } nav { width: 100%; } : }
h1
の中で書いたスマートフォン用のスタイルも同じ@media
ルール内に出力されています。
このように、スタイルを書く場所が仮にバラバラであっても、メディア特性ごとの@media
ルール内にまとめられるのもこのミックスインの特長です。無駄な@media
ルールが出力されないのでCSSのファイルサイズを減らすことができます。
スタイルの出力を変数で制御しているので、@if
文で2つ以上の変数を利用することで次のようなことができるのもこのミックスインの特長です。
2つの任意のメディア特性に同じスタイルを適用したい場合
同じコードを2箇所以上に書くのは避けたいところですが、タブレットとスマートフォンに同じスタイルを適用したいといった場合は次のようにします。
@include mq { h1 { @if $mq-tablet { margin: 0; } // タブレット "と" スマートフォンですが、 // and ではなく or を使います @if $mq-tablet or $mq-sp { color: blue; } } }
これをコンパイルすると次のようになります。
@media only screen and (min-width: 481px) and (max-width: 800px) { h1 { margin: 0; color: blue; } } @media only screen and (max-width: 480px) { h1 { color: blue; } }
color: blue;
はタブレット用とスマートフォン用の@media
ルール内に出力されています。当然、タブレット用のh1
のスタイルはまとめられています。
メディア特性ごとにCSSファイル自体を分ける場合
メディア特性ごとにCSSファイル自体を分けてlink
要素でそれぞれのファイルを読み込ませたい場合は次のようにします。
まず、スタイルを記述するパーシャルファイルを用意します(ここでは_mq.scssとします)。スタイルは要素やモジュール単位でも良いですし、メディア特性ごとに書いても良いです。
[_mq.scss] h1 { @if $mq-all { width: 100%; } @if $mq-default { color: red; } @if $mq-tablet { color: blue; } @if $mq-sp { color: green; } } p { @if $mq-all { line-height: 1.4; } @if $mq-default { margin: 1em 0; } @if $mq-tablet { margin: 0.8em 0; } @if $mq-sp { margin: 0.6em 0; } }
これを次のように各ファイルで読み込ませます。
[default.scss] $mq-all: true; $mq-default: true; @import "mq"; [tablet.scss] $mq-all: true; $mq-tablet true; @import "mq"; [sp.scss] $mq-all: true; $mq-sp true; @import "mq";
コンパイル後のdefault.cssは次のようになります。
h1 { width: 100%; color: red; } p { line-height: 1.4; margin: 1em 0; }
複数ファイルを@import
しても問題ないので、スタイルをカテゴリごとや作業者ごとなど、別々のファイルに分けて管理することもできます。
ミックスインと設定用の変数
最後にそのミックスインと設定用の変数についてです。
ミックスインmq
では実は4つのミックスインを@include
して、それぞれに@content
でスタイルを渡しているだけです(@content
については『Sass入門』を読んでもらうとして...)。とりあえず次に挙げるものが全てのコードになります。
// # Media Queries // // ## Breakpoints (Window Size) // // 0-480 : [Smartphone] // iPhone3/4/5(Portrait), iPhone3/4(Landscape) // Most Android Phone(Portrait) // 481-800 : [Tablet, Smartphone(Landscape)] // iPhone5(Landscape), iPad(Portrait) // Most Android Phone(Landscape) // Newer Android Tablet(Portrait) // 801+ : Default, iPad(Landscape), Newer Android Tablet(Landscape) // OR 801-1024 // 1025+ : Large Window Size, Newer Android Tablet(Landscape) // ## Variables $mq-all : null !default; $mq-sp : null !default; $mq-tablet : null !default; $mq-default: null !default; $mq-large : null !default; $default-mq-sp-max-width : 480px !default; $default-mq-tablet-min-width : $default-mq-sp-max-width + 1 !default; $default-mq-tablet-max-width : 800px !default; $default-mq-default-min-width: $default-mq-tablet-max-width + 1 !default; $default-mq-large-min-width : 1025px !default; $default-mq-default-max-width: null !default; // $default-mq-default-max-width: $default-mq-large-min-width - 1 !default; // ## Wrapper @mixin mq { @include mq-all { @content; } // @include mq-large { @content; } @include mq-default { @content; } @include mq-tablet { @content; } @include mq-sp { @content; } } // ## For All @mixin mq-all { $_tmp: $mq-all; $mq-all: true; @content; $mq-all: $_tmp; } // ## For Smartphones @mixin mq-sp( $max: $default-mq-sp-max-width ) { $_tmp: $mq-sp; $mq-sp: true; @media only screen and (max-width:#{$max}) { @content; } $mq-sp: $_tmp; } // ## For Tablets @mixin mq-tablet( $min: $default-mq-tablet-min-width, $max: $default-mq-tablet-max-width ) { $_tmp: $mq-tablet; $mq-tablet: true; @media only screen and (min-width:#{$min}) and (max-width:#{$max}) { @content; } $mq-tablet: $_tmp; } // ## For PC (default) @mixin mq-default( $min: $default-mq-default-min-width, $max: $default-mq-default-max-width ) { $_tmp: $mq-default; $mq-default: true; $_breakpoint: "(min-width:#{$min}) "; @if not($max == null) { $_breakpoint: $_breakpoint + "and (max-width:#{$max}) "; } @media only screen and #{$_breakpoint}{ @content; } $mq-default: $_tmp; } // ## For Large Window @mixin mq-large( $min: $default-mq-large-min-width ) { $_tmp: $mq-large; $mq-large: true; @media only screen and (min-width:#{$min}) { @content; } $mq-large: $_tmp; }
ブレイクポイントについては制作するサイトの仕様に合わせて設定用の変数の値を適宜変更します。また、これまでのサンプルでは触れていませんが、大きめのウィンドウサイズ用のミックスインと変数のように必要に応じて別のものを新たに追加することもできるようになっています。
子のミックスイン
ミックスインmq
で@include
されている4つのミックスインについてですが、行なっていることはほとんど同じなのでmq-tablet
を説明することにします。
// ## Variables $mq-tablet : null !default; $default-mq-sp-max-width : 480px !default; $default-mq-tablet-min-width : $default-mq-sp-max-width + 1 !default; $default-mq-tablet-max-width : 800px !default; // ## For Tablets @mixin mq-tablet( $min: $default-mq-tablet-min-width, $max: $default-mq-tablet-max-width ) { $_tmp: $mq-tablet; $mq-tablet: true; @media only screen and (min-width:#{$min}) and (max-width:#{$max}) { @content; } $mq-tablet: $_tmp; }
ミックスインmq-tablet
では変数$mq-tablet
の値を一時的に$_tmp
に保存しておいてからtrue
にしています。そのあと、@media
ルールの中に@content;
があるのでここにスタイルが展開されますが、その時に@if $mq-tablet {}
の中のスタイルだけが出力されます。そして、最後に保存しておいた$mq-tablet
の値を戻しています(外で設定された値を変えないようにしています)。
実は、子のミックスインは単体でも使うことができます。@media
ルールが@include
する度に出力されてしまいますが、局所的に使う場合には@media
ルールを書くよりもラクなので便利だと思います。
h1 { width: 100%; : @include mq-tablet { color: blue; } }
h1 { width: 100%; : } @media only screen and (min-width: 481px) and (max-width: 800px) { h1 { color: blue; } }
以上ですが、それにしてもメディアクエリって面倒ですね...。