今回は、レスポンシブで絶対にお世話になるCSSの メディアクエリ(Media Queries)について。基本的な書き方や記述の意味についてまとめていきます。
なんとなく @medeia screen and ...
とか書いているけど、 screen
ってどういう意味?とか、そんなレベルの話です。メディアタイプ・メディア特性・区切り方やそのキーワードの意味など...。
先日、 @media only screen...
という書き方を目にした時に only
の意味がわからず、それだけを調べるつもりが、結構知らないことがあってびっくりしました。
今までがいかに「何となく」だったかを痛感し、せめて基本的なことくらい分かっておこうと思った次第です。
はじめに
今回まとめていくメディアクエリは、「 Media Queries Level 4」を参考にしています。
すでに勧告プロセスが CR まできており、「 CSS current work」をチェックしてみるとUpcoming の欄が PR となっているので、「勧告」となるのもそう遠くないだろうという判断です。
基本的なことは特に 今までのメディアクエリと変わらないので特に意識しなくても大丈夫だと思いますが、このメモで「 非推奨」と述べている記述は、「Media Queries Level 4」にて非推奨となったもの、という意味だということを予めご理解ください。
「勧告」というのがよくわからない方は以下のメモをご覧ください。
また、メディアクエリに Level があることが意味わからないという方は以下のメモをご覧ください。
また、このメモでは「デバイス幅が〇〇px以下」のような表現をしますが、これは、HTML側でビューポートの設定が以下のように記述されていることを前提としています。
<meta name="viewport" content="width=device-width">
メディアクエリの基本的な使い方
メディアクエリを使って、デバイスによってCSSを変えたい時、基本的に以下の3通りの使い方があります。
- HTMLでCSSファイルを読み込むlinkタグにmedia属性を記述する
- CSS内で@importする時に記述する
- CSS内で@mediaを記述する
HTMLでCSSファイルを読み込むlinkタグにmedia属性を記述する
まずは、HTMLでファイルの読み込みに メディアクエリを使う方法です。
デバイスによって 読み込むファイル自体を振り分けることができます。
記述例:横幅600px以下のデバイスでのみ mobile.css というファイルを読み込む
<link rel="stylesheet" href="./css/mobile.css" media="screen and (max-width: 600px)">
よく見る記述かと思いますが、この構造をしっかり理解しておきましょう。
上記の記述例は、次のような構造で記述したものになります。
<link rel="stylesheet" href="読み込むファイルのパス" media="メディアタイプの指定 and (メディア特性の指定)">
screen
とは「メディアタイプ」の一種であり、 (max-width: 600px)
とは、「メディア特性」に関する指定です。
CSS内で@importする時に記述する
次はCSSファイル内で使える方法です。
デバイスによって インポートするファイルを振り分けることができます。
記述例:横幅600px以下のデバイスでのみ mobile.css というファイルをインポート
@import url('mobile.css') screen and (max-width: 600px);
こちらも、構造を確認しておきましょう。
@inport url('読み込むファイル') メディアタイプの指定 and (メディア特性の指定);
CSS内で@mediaを記述する
次に、CSSファイル内でメディアクエリを使う方法。
読み込むファイル同じだが、デバイスごとに 指定するスタイルを振り分けることができます。
記述例:横幅600px以下のデバイスでのみdivタグのwidthを上書きする
div{ width: 920px; }
@media screen and (max-width: 600px) {
div{ width: 100%; }
}
こちらも同じく、構造を確認しておきましょう。
@media メディアタイプの指定 and (メディア特性の指定) { /*指定するスタイルの記述*/ }
メディアタイプについて
メディアクエリでは、対象とするデバイスを「メディアタイプ」という分類で指定することができます。
先ほど、メディアクエリの基本的な使い方の例を書きましたが、その中のscreen
というのも、「メディアタイプ」の一種です。
主なメディアタイプ
まずは、主なメディアについて。
all | 全てのデバイス |
---|---|
プリンター。印刷プレビューに表示されるドキュメントも対象。 | |
screen | "print"と"speech"にマッチしないもの全て。 (一般的に、コンピュータやスマホなどの「スクリーン画面」を持ったデバイス) |
speech | スピーチシンセサイザ |
この4つです。(参考:Media Queries Level 4 - Media Types)
次のようにして使用します。
@media メディアタイプ { /*そのメディアでのみ有効となるスタイル*/ }
メディアタイプだけを用いた記述例
@media screen { /*プリンターとスピーチシンセサイザ以外の全てのデバイスで有効となるスタイル*/ }
@media print { /*プリンターでのみ有効となるスタイル*/ }
注意点
MDNでは以下のように注記がありました。
注記: 現在、Firefox には print および screen メディアタイプしか実装されていません。 アドオンの FullerScreen 拡張をインストールすると projection メディアタイプのサポートが有効になります。
「え、Firefoxはall
も使えないのか?」とびっくりしたのですが、検証したところ、Firefoxでもall
を指定したスタイルが無事に適用されることを確認しています。
どうやら標準となるall
以外に実装されているのが上記2つだけということらしいです。まったくややこしい。笑
非推奨となったメディアタイプ
Media Queries 4 で非推奨となったメディアタイプを記載しておきます。
- tty
- tv
- projection
- handheld
- braille
- embossed
- aural
これらは使わないほうが良いでしょう。
メディア特性について
メディアクエリでは、先述の「 メディアタイプ」に加え、さらなる条件として「 メディア特性」に関する指定ができます。
レスポンシブでよく見かける (max-width : 480px)
のような指定はこの「 メディア特性」に関する記述だったのです。
( [min- | max-] メディア特性 : 値 )
という構造によって、メディア特性に関する指定ができます。
主なメディア特性
width | ビューポートの幅 |
---|---|
height | ビューポートの高さ |
aspect-ratio | アスペクト比(ビューポートの幅と高さから算出) |
orientation | ビューポートの向き。 とれる値は portrait (縦長) または landscape (横長) |
resolution | 出力デバイスの画素密度 |
-webkit-device-pixel-ratio | デバイスピクセル比 |
その他にもたくさんのメディア特性があります。(参考: MDN - メディア特性)
範囲型と離散型
メディア特性は「 範囲型」もしくは「 離散型」のどちらかに分類されます。
widthやheightなどの数値で指定できるものが 範囲型、orientationなどの特定の値しかとれないものが 離散型に当てはまります。
メディア特性の使用例
例:(ビューポートの)アスペクト比が16:9の全てのデバイス
@media all and (aspect-ratio: 16/9) {}
例:縦長状態のscreenデバイス
@media screen and (orientation: portrait) {}
例:デバイスピクセル比が2のデバイス
@media screen and (resolution: 2dppx) {}
//これは、-webkit-device-pixel-ratioを用いた以下と同じ
@media screen and (-webkit-device-pixel-ratio: 2) {}
非推奨になったメディア特性
Media Queries 4 で 非推奨となったメディ特性をいくつか記載しておきます。
device-width | 出力デバイスの幅 |
---|---|
device-height | 出力デバイスの高さ |
device-aspect-ratio | アスペクト比(出力デバイスの幅と高さから算出) |
[ min- | max- ] 接頭辞と [ >= | <= | > | < ] 演算子
width、heightなど、 範囲型のメディア特性については、その 最大値や 最小値でメディア特性を指定することができます。
その際、メディア特性の名前に min-
または max-
接頭辞を付けて記述します。
例:横幅 600px 以下のデバイス
@media screen and (max-width: 600px) {}
ベンダー付きのメディア特性は、 -webkit-min-
のように、 -webkit-
接頭辞の次に記述します。
例:Retinaディスプレイ(デバイスピクセル比が2以上のデバイス)
@media screen and (-webkit-min-device-pixel-ratio: 2) {}
//以下と同じ
@media screen and (min-resolution: 2dppx) {}
Level4からの記法
Media Queries Lebel4 からは、以下のように記述することができるようになりました。
例:横幅 600px 未満のデバイス
@media screen and (width < 600px) {}
例:横幅 320px 以上 600px 未満のデバイス
@media screen and (320px <= width < 600px) {}
めちゃくちゃ便利ですね!
メディアタイプ all の省略
メディアタイプが all
かつ、 メディア特性の指定がある場合、 all
は省略可能です。
例:allの省略
@media all and (max-width: 600px) {}
//これは以下でもOK
@media (max-width: 600px) {}
andと,による条件の組み合わせ
メディアクエリの指定条件の組み合わせについてまとめていきます。
andでの組み合わせ
まずはすでに何気なく使っている and
について。
ここまで「メディアタイプ and (メディア特性の指定)」としか使っていませんでしたが、
実はこれ、「メディアタイプ and (メディア特性の指定) and (メディア特性の指定)」のように、いくつでも条件をつなげることができます。
通常の論理演算の 「A and B」の意味、「AかつB」の「かつ」と同じものです。
例:メディアタイプがscreen かつ 横幅が600px以下 かつ デバイスピクセル比が2
@media screen and (max-width: 600px) and (resolution: 2dppx) {}
例:横幅が320px 以上かつ600px 以下 ( <= や >=を使うともっと楽ですが)
@media (min-width: 320px) and (max-width: 600px) {}
, での組み合わせ
論理演算のorに当たります。メディアクエリでは or ではなく ,
で区切って表現します。
「A or B」の意味、「AまたはB」の「または」と同じ意味です。
例:横幅が480px以下、または1200px以上
例:「メディアタイプがscreen かつ 横幅が600px以下」または、「デバイスピクセル比が2」
@media screen and (max-width: 600px), (resolution: 2dppx){}
例:横幅が480px以下、または1200px以上
@media (max-width: 480px), (min-width: 1200px){}
クエリ単体を意味するメディアクエリ(a media query)とモジュール名としてのメディアクエリ(Media Queries)
メディアクエリ(Media Queries)という機能は、条件指定に当てはまるメディアのみ対象とするための機能ですが、この「条件指定」に関する記述部分のことを、英文では単体表記で「A media query」のように記述されています。
A media query is a method of testing certain aspects of the user agent or device that the document is being displayed in.
以下、モジュール名としてのメディアクエリではなく「メディアを指定するための条件指定式」のことを、単に「クエリ」と表現することとします。
W3Cのドキュメントでは、単一の「クエリ」を構成する式を以下のような図で説明されています。
「media type」はそのまま「メディアタイプ」です。
「media condition」というのが、「メディア特性の指定」のことです。
* onlyとnotについては後述します。
説明を付け足した図が以下になります。
ここで注目して欲しいのは、「andによる条件の追加」が、単一の「クエリ」の構造の中に入っている点です。
「条件1かつ条件2かつ..」という、and
で組み合わされた条件は、それらをまとめて、一つの「クエリ」として評価されます。
次に、,
による条件の追加がどう説明されているかを見てみましょう。
W3Cのドキュメントでは、以下のような図で説明されていました。
「media query」とは、単一の「クエリ」のことです。「media query」を形成する中身が、先ほどの図です。(「media type」やら「media condition」やらが出てきたやつ)
つまり、「クエリ」と「クエリ」を組み合わせ、複数の「クエリ」を指定できるようにするのが、,
による条件の追加です。
notキーワードとonlyキーワード
メディアクエリでは、メディアタイプの指定の直前に、not
またはonly
キーワードをつけることが可能です。
また、not又はonlyキーワードを使用する場合は、メディアタイプを明示的に指定する必要があります。つまり、all
の省略はできません。
@media [not|only] メディアタイプ and (メディア特性) {}
notキーワード
not
キーワードは、「クエリ」全体を反転します。not
キーワードは「クエリ」の最後に評価されるため、メディアタイプだけを否定するような使い方はできません。
例:メディアタイプが'speech'以外のデバイス全て
@media not speech {}
例:「screenかつデバイスピクセル比が1」ではないデバイス全て = Ratinaディスプレイ
@media not screen and (resolution: 1dppx) {}
上記は、「screen」だけを否定しているわけではなく、「screen and (resolution: 1dppx)」全体を否定しています。
,で隣接した「クエリ」への影響について
あくまでnotキーワードも、単一の「クエリ」を形成するための演算子なので、隣接する「クエリ」には影響しません。
例:「デバイスピクセル比が1以外のデバイス」、または、「横幅が1200pxのデバイス」
@media not (resolution: 1dppx), (min-width: 1200px) {}
onlyキーワード
現在のメディアクエリの形式に対応していない、旧来のUAでクエリを無視してもらうためのキーワードです。
メディアクエリが導入された当初はまだHTML4の時代で、クエリの内容を最初の非英数字までの部分をメディアタイプとして解釈し、残りの部分は無視するような仕様でした。
例えば、「screen and (max-width: 600px) 」は、旧来のUAでは単に「screen」として解釈されてしまい、想定外のスタイルが適用されてしまうことになります。
これを防ぐために、メディアタイプの前にonly
キーワードを記述します。
例
@media only screen and (max-width: 600px) {}
では、なぜこれが旧来のUAでは無視されるのか?もう少し説明しておきます。
「only screen and (max-width: 600px)」は旧来のUAでは「only」の部分しか読み込まれません。
つまり、「メディアタイプが only のデバイス」として解釈します。
しかし、「only」に該当するメディアタイプは存在しないので、旧来のUAにおいては全てのデバイスでそのメディアクエリが無視される...というわけです。
ただ、only
キーワードが必要になることはほぼ無いでしょう。
おわりに - レスポンシブのメディアクエリはもっとシンプルでいい。
さて、ここまでメディアクエリの仕様方法やその構成の意味をまとめてきました。
そして、今まで随分と誤解をしたままメディアクエリを使ってきていたんだなぁと反省しています。
例えば、レスポンシブデザインに対応するため、私はスマホに適用させるスタイルを以下のように記述してきました。
@media screen and (max-width: 767px) {}
「なぜ 767px なんだ」というのはひとまず置いておきましょう。ここは人によっては 480px や 599px などとしているかと思います。
ここまで読んできてくれた方ならもうお分かりかと思うのですが、これ、以下でいいんですよね。
@media (max-width: 767px) {}
もしくは、
@media (width < 768px) {}
これだけ。
我々は誤解していた
何を誤解していたのか。
「screen and (max-width: 〇〇)」という記述の意味です。
おそらくですが、「screen = スクリーン画面の、max-width = 最大幅が〇〇までのデバイス」というような解釈をしていたんじゃないでしょうか。
ですが、screen
とは「プリンターまたは音声機器以外のデバイス全て」のことでした。決して、「スクリーン画面の(横幅)」と装飾するための言葉ではありません。
一応、信じられないという方のためにW3Cのドキュメントの英文も載せておきますね。
'screen' - Matches all devices that aren’t matched by 'print' or 'speech'.
つまり、「プリンターには適用したくない」という明確な意図が無い限り、all
でいいのです。そして、all
は省略もできるのです。
そして、メディア特性width
とは、正確にはビューポートの幅のことでした。
なぜこれがスクリーンの幅と解釈できるのかというと、それはHTML側で記述するビューポートに関するmetaタグ、
<meta name="viewport" content="width=device-width">
これのおかげだったんです。(width=device-width
というのが、デバイス幅をビューポートに設定するということ)
「レスポンシブで使えるメディアクエリの書き方!」みたいな記事のほとんどが何の注釈もなくscreen
を(ひどい場合だとonly
も)使っているのは、これらのことを知らないままどこかからコピペしただけの情報だからでしょう。
やはり、信頼できるのは公式ドキュメント(またはその翻訳文書)ですね。