メディアクエリを 1 つの例で
メディアクエリは CSS を条件で包みます。@media (min-width: 600px) の中のルールは、ビューポートの幅が 600px 以上の間だけ適用されます:
プレビューはフレームで、その中のメディアクエリはあなたの画面ではなくフレームを測ります。 デスクトップではこの記事の列くらいの幅で、たいてい 600px を超えるので、ボックスは青になります。ブラウザのウィンドウを狭くしてフレームが 600px を下回ると琥珀色に変わります。ボックスの下の行には、フレームの幅がリアルタイムで表示されます。スマートフォンではフレームが最初から狭いので、琥珀色の方が見えます。
@media の書き方
@media (min-width: 600px) { ... } /* one condition */
@media (min-width: 600px) and (max-width: 899px) { ... } /* both must be true */
@media (max-width: 599px), print { ... } /* either one (comma = or) */
@media not print { ... } /* negation */
@media screen and (orientation: landscape) { ... } /* media type plus a feature */
@media (width >= 600px) { ... } /* range syntax */
@media (600px <= width < 900px) { ... } /* a range with both ends */
and の前後には空白が必要です。(min-width: 600px)and(max-width: 900px) は無効で、クエリ全体が無視されます。範囲の構文 (width >= 600px) は現在の Chrome、Firefox、Safari で使え、特に「未満」を表すときに min-width よりわかりやすく書けます。
よく使う特性:
| 特性 | 一致する条件 | 例 |
|---|---|---|
min-width / width >= | ビューポートがこの幅以上 | (min-width: 768px) |
max-width / width <= | ビューポートがこの幅以下 | (max-width: 767px) |
orientation | portrait (縦長) または landscape (横長) | (orientation: landscape) |
hover | 主なポインターでホバーできる (hover)、できない (none、多くのタッチスクリーン) | (hover: hover) |
pointer | 主なポインターが fine (マウス) か coarse (指) か | (pointer: coarse) |
prefers-color-scheme | ユーザーが dark か light のテーマを選んでいる | (prefers-color-scheme: dark) |
prefers-reduced-motion | ユーザーがシステムに動きを減らすよう設定している | (prefers-reduced-motion: reduce) |
print (メディアタイプ) | ページを印刷するか PDF に保存するとき | @media print |
モバイルファースト: min-width のブレイクポイント
スマートフォンのレイアウトを基本の CSS として書き、スペースが広がるにつれてレイアウトを変える min-width のクエリを加えます。各クエリには変わる部分だけを書けば済みます:
幅の広いデスクトップのウィンドウでは、プレビューが 720px を超えるので 3 列に見えます。グリッドの下の行に幅と列の数が表示されます。ウィンドウを狭くすると、720px 未満で 2 列、480px 未満で 1 列になります。2 つのクエリの順番は重要です。広い画面ではどちらも成り立ち、後に書いたほうが勝つので、min-width のクエリは小さい順に書きます (max-width のクエリでは逆に、大きい順です)。
ブレイクポイントの選び方
公式のリストはありません。よく使われる値と、それがたいてい分けるものは次のとおりです:
| ブレイクポイント | 主な対象 |
|---|---|
min-width: 640px | 横向きの大きいスマートフォン、小さいタブレット |
min-width: 768px | 縦向きのタブレット |
min-width: 1024px | 横向きのタブレット、小さいノートパソコン |
min-width: 1280px | デスクトップ |
よりよい方法: 狭いレイアウトから始め、何かがおかしく見える (行が長すぎる、カードが広すぎる) までウィンドウを広げ、そこにブレイクポイントを置きます。たいていのページは 2 つか 3 つで足ります。1 つも要らないこともよくあります。grid の repeat(auto-fit, minmax(200px, 1fr))、flex-wrap、clamp() は連続的に対応するからです。
どのページにも viewport の meta タグが必要
<head> にこのタグがないと、スマートフォンのブラウザは画面の幅を約 980px としてページを配置してから縮小表示するので、min-width: 480px のクエリが常に成り立ち、スマートフォン用のレイアウトが表示されません:
<meta name="viewport" content="width=device-width, initial-scale=1">
各値の意味は meta viewport のページ で解説しています。
prefers-color-scheme でダークモード
prefers-color-scheme は OS のライトとダークの設定に従います。一番すっきりした使い方は、色を CSS 変数に入れておき、クエリの中では変数だけを変えることです:
このプレビューでは、システムがダークモードでもクエリが false と表示されることがあります。Chrome は、このような sandbox 付きのフレームにシステムの設定を渡さないためです。ボタンは同じ変数を手動で切り替えます。サイトのテーマ切り替えもこの仕組みです。:root[data-theme] はクエリ内の単なる :root より詳細度が高いので、読者の選択がシステムの設定より優先されます。クエリがシステムに追従する様子を見るには、例をファイルとして保存して開いてください。
スクリプトはメディアクエリのもう半分を示しています。matchMedia() は同じクエリを JavaScript から実行し、今一致しているかを返し、結果が変わると change イベントを発生させます。タッチデバイスではメニューの開き方を変えるなど、スタイルだけでなく動作が画面によって変わるときに使います。
動きも同じです。大きなアニメーションや繰り返すアニメーションは、animation のページ にあるように prefers-reduced-motion の確認で包みましょう。
コンテナクエリ: コンポーネントに判断させたいとき
メディアクエリが知っているのはビューポートだけです。同じページで広いメインの列にも狭いサイドバーにも置かれるカードは、代わりに 自分自身の スペースを知る必要があります。それがコンテナクエリです。親に container-type: inline-size を付け、同じ条件で @container を使います。
灰色のボックスの角をドラッグしてサイズを変えてください。カードは、ウィンドウのサイズに関係なく、ボックス の幅 360px でレイアウトを切り替えます:
最初の 480px では、画像は文章の横にあります。ボックスを 376px (内容の 360px と左右の padding 8px ずつ) より狭くドラッグすると、画像が文章の上に移ります。コンテナクエリは現在の主要なブラウザすべてで使えます。
印刷用のスタイル
@media print は、ページを印刷するか PDF に保存するときだけ適用されます。ナビゲーションとボタンを隠し、白地に濃い色の文字にしましょう:
@media print {
nav, .ad, button { display: none; }
body { color: black; background: white; }
a::after { content: " (" attr(href) ")"; } /* print the URL after each link */
}
よくある間違い
- viewport の meta タグがない。 スマートフォンが広いレイアウトビューポートを報告し、小さい画面向けのクエリが一致しません。
- クエリの順番の間違い。 同じセレクターで 2 つのクエリが成り立つと、後のほうが勝ちます。
min-widthのクエリは小さい順に並べましょう。 - 境目が重なる、またはすき間ができる。
max-width: 768pxとmin-width: 768pxは、ちょうど 768px で両方一致します。片方を767pxにするか、範囲の構文(width < 768px)と(width >= 768px)を使いましょう。 andの後に空白がない。and(は無効で、クエリは黙って捨てられます。- デスクトップのウィンドウを縮めるだけで確認する。 実際のスマートフォンか、ブラウザのデバイスモードでも確認しましょう。デバイスモードはスマートフォンのビューポート、ピクセル比、タッチを再現します。
- ブレイクポイントが多すぎる。 コンポーネントごとに必要になるなら、grid の
auto-fit、flex-wrap、コンテナクエリを試しましょう。
よくある質問
CSS のメディアクエリとは何ですか?
デバイスやウィンドウについての条件が成り立つときだけ、中の CSS を適用するルールです。@media (min-width: 600px) { ... } はビューポートの幅が 600px 以上のときだけスタイルを適用します。これで 1 つのページがスマートフォンからデスクトップまで対応します。
メディアクエリは min-width と max-width のどちらを使うべきですか?
多くのサイトはモバイルファーストで書きます。基本の CSS を小さい画面向けにし、画面が広くなるにつれて min-width のクエリでレイアウトを加えます。max-width のクエリはデスクトップのレイアウトから始める逆の方法です。どちらでも動きますが、同じ要素に両方を混ぜると、境目で重なりやすき間が生まれます。
メディアクエリの標準的なブレイクポイントは?
公式の標準はありません。よく使われるのは 640px、768px、1024px、1280px あたりですが、自分のレイアウトの見た目がおかしくなり始める位置にブレイクポイントを置き、数を少なく保つほうがよい方法です。
スマートフォンでメディアクエリが効かないのはなぜですか?
一番多い原因は viewport の meta タグがないことです。<meta name="viewport" content="width=device-width, initial-scale=1"> がないと、モバイルブラウザはページの幅を約 980px とみなすので、狭い幅のクエリが一致しません。クエリが上書きしたいルールより後にあるかも確認しましょう。
ダークモードのメディアクエリはどう書きますか?
@media (prefers-color-scheme: dark) { ... } を使います。ユーザーの OS やブラウザがダークテーマに設定されていると一致し、中で色や CSS 変数を上書きできます。
メディアクエリとコンテナクエリの違いは何ですか?
メディアクエリはビューポート (ウィンドウ全体) を調べます。@container で書くコンテナクエリは、container-type: inline-size を付けた親要素のサイズを調べます。同じページの広い場所と狭い場所の両方に出てくるコンポーネントには、コンテナクエリを使いましょう。