ウミ
クル

レスポンシブWebデザイン メディアクエリの書き方

レスポンシブWebデザインには、% や vw を使った流動的なレイアウトデザインと、メディアクエリを使ってブレイクポイントで切り替えをするデザインがあります。
ここではメディアクエリの書き方を、デスクトップファーストとモバイルファーストのアプローチ別に説明します。また、通常のCSSの書き方に加えて、Sassのmixinを使った書き方も紹介します。
レスポンシブWebデザインの詳しい解説はこちら

メディアクエリイメージ

メディアクエリあれこれ

アプローチ別の説明に入る前に、まずはメディアクエリについて説明します。

metaタグにviewportの指定を入れる !
レスポンシブデザインでメディアクエリを使う時は、必ずhtmlに以下の記述をしましょう。この記述がないとメディアクエリが効かず、スマホに縮小されたPC用レイアウトが表示されてしまうなど、画面幅に合ったデザインが適用されません。
<meta name="viewport" content="width=device-width, initial-scale=1.0">

いろいろなメディアクエリの値
よく使われる max-width、min-width の他にもブレイクポイントを指定する方法があり、[and]かつ、[ , ]または、を用いて併用することもできます。
@media (orientation: landscape) { }    ←ブラウザが横向きの場合
@media (min-resolution: 192dpi) { }    ←解像度 192dpi 以上の場合
@media (min-width: 600px) and (max-width: 900px), (min-width: 1200px) { } ←画面幅が600px以上かつ900px以下、または1200px以上の場合

コードの順序が大事
メディアクエリはセレクタの優先順位には影響しませんが、コードの順番が最新(一番下)のものによって上書きされるので、コードの順番に気をつけましょう。

メディアクエリの単位は em
サイズを指定する単位には rem や px もありますが、以下の理由からメディアクエリに最適な単位は em とされています。 検証記事はこちら

  • メディアクエリではhtmlやbodyに設定するルートフォントサイズは考慮されないが、ブラウザによってはルートが考慮されてしまうものもある。
  • ユーザーがズーム機能を使用した時、ブラウザによっては px 指定では機能しない。
  • ブラウザのデフォルトフォントサイズを変更するユーザーに対し、px 指定ではサポートできない。

よって、メディアクエリのブレイクポイントには em を使い、ブラウザのデフォルトフォントサイズである 16px を基準に算出します。

デスクトップファーストのメディアクエリ

デスクトップファーストの場合は、PCデスクトップなどの大画面に合わせてデザインしたものを標準のスタイルとします。 次にメディアクエリの max-width(画面最大幅)を使い、大画面から小画面へと順番に条件を絞って、スタイルを上書きしていきます。

デスクトップファーストのメディアクエリイメージ
下のイメージ図では、メディアクエリで背景色を切り替えるサンプルを示しています。
デスクトップを標準として背景色を薄い灰色とし、メディアクエリにて1200px 以下は黄色、900px 以下は白、600px 以下は濃い灰色と指定しています。
例えば画面幅が 500px の場合、全てのスタイルが適用対象となりますが、一番最新(一番下)のコードにより上書きされるので、濃い灰色が適用となります。

desktopfirst

モバイルファーストのメディアクエリ

デスクトップファーストとは反対に、スマホなどの小さな画面でデザインしたものを標準のスタイルとします。 その上でメディアクエリの min-width(画面最小幅)を使い、小画面から大画面へと適用を切り替えて、スタイルを上書きします。

モバイルファーストのメディアクエリイメージ
今回はスマホを標準として背景色を濃い灰色とし、メディアクエリにて600px 以上を白、900px 以上を黄色、1200px 以上を薄い灰色に、という切り替えをしています。
例えば画面幅 800px の場合では、標準の濃い灰色とメディアクエリの白が適用対象となり、上書きによって最新コードの白が適用になります。

mobilefirst

Sassのmixin機能を使ったメディアクエリ①

Sassを使うと、後からブレイクポイントの値を変更したい時にも一括で変更でき、管理が楽になります。 また、標準スタイルのセレクタにレスポンシブをネストでき、セレクタをメディアクエリ内に再度書く必要がないので、コーディングが早くなり、尚且つ読み易いコードになるというメリットもあります。
書き方は次の通りです。
@mixin で任意の名前を設定し、メディアクエリを定義する
レスポンシブが必要なセレクタ内に、設定した名前を使って @include を記載する
下のコードは上記デスクトップファーストのメディアクエリと同じ内容をSassで書いたものです。

/*--- @mixin でメディアクエリを定義する ---*/

        @mixin tab-land {
            @media only screen and (max-width: 75em) {  @content  }
        }   /*--- タブレット横 1200px /16px =75em 以下 ---*/
        @mixin tab-port {
            @media only screen and (max-width: 56.25em) {  @content  }
        }   /*--- タブレット縦 900px /16px =56.25em 以下 ---*/
        @mixin phone {
            @media only screen and (max-width: 37.5em) {  @content  }
        }   /*--- スマートフォン 600px /16px =37.5em 以下 ---*/
    

/*--- 標準スタイルに続いて @include を記載 ---*/

        .container {
            background: lightgray;
            @include tab-land {    background: yellow;    }
            @include tab-port {    background: white;    }
            @include phone {    background: gray;    }
        }
    

これをコンパイルすると以下の通りとなり、デスクトップファーストのイメージ図にあるコードと同じ結果になります。

/*--- style.css ファイル ---*/

        .container {    background: lightgray;    }
            
        @media only screen and (max-width: 75em) {
            .container {    background: yellow;    }
        }
        @media only screen and (max-width: 56.25em) {
            .container {    background: white;    }
        }
        @media only screen and (max-width: 37.5em) {
            .container {    background: gray;    }
        }
                    

Sassのmixin機能を使ったメディアクエリ②

①で紹介した mixin に条件分岐 @if を加えてさらにコンパクトにしたメディアクエリを紹介します。
$breakpoint に入る名前が tab-land の場合は max-width: 75em です、というような指示です。
コンパイル結果は①と同じになります。

/*--- @mixin でメディアクエリを定義する ---*/

        @mixin respond($breakpoint) {
            @if $breakpoint == tab-land {
                @media only screen and (max-width: 75em) {  @content  };
                }
            @if $breakpoint == tab-port {
                @media only screen and (max-width: 56.25em) {  @content  };
                }
            @if $breakpoint == phone {
                @media only screen and (max-width: 37.5em) {  @content  };
                }
        }

/*--- 標準スタイルに続いて @include を記載 ---*/

        .container {
            background: lightgray;
            @include respond(tab-land) {    background: yellow;    }
            @include respond(tab-port) {    background: white;    }
            @include respond(phone) {    background: gray;    }
        }
    

ブレイクポイントについて

最後にブレイクポイントについて補足します。
今回は 600px、900px、1200px と設定しているブレイクポイントですが、これはstatcountermydevice.ioから各デバイスサイズのデータを集めてグループ化した上で設定されたものです(Udemyより)。 ただ、スマホもタブレットも大型化が進み、ブレイクポイントをどう設定するかは非常に難しい状況です(参考サイト)。
デバイスサイズに関係なく、デザインが崩れたタイミングをブレイクポイントとする方法も選択肢としてはあるので、何をベストとするか都度考えながらブレイクポイントを設定する必要があります。

参考

Udemy "CSS - The Complete Guide 2020 (incl. Flexbox, Grid & Sass)"
Udemy "Advanced CSS and Sass: Flexbox, Grid, Animations and More!"
w3schools.com