CSS講座 / メディアクエリー:内容から決めるブレークポイント

メディアクエリーは、ビューポートの幅などの環境条件に応じてCSSを追加する仕組みです。ブレークポイントは端末名で一律に決めず、実際の内容が別の配置を必要とする幅から判断します。

基本の指定に条件付きの指定を加える

条件の外のCSSが基本になり、条件が一致すると中の宣言もカスケードへ参加します。関係のない基本指定が消えるわけではありません。条件を増やす前に、可変幅と上限で自然に収まるかを見ます。

.cards { display: grid; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 33rem) {
  .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

この例は同じセレクターで基本を先、条件付きの指定を後に書いています。「下にあれば必ず勝つ」という規則ではなく、重要度、レイヤー、詳細度などが同じときに順番で決まる条件です。一致しても変わらないなら、開発者ツールで打ち消された宣言を調べます。

カードの必要幅から境界を計算する

実習では枠とpaddingを含めた一枚の目標最低幅を16remとします。これは万能の値ではなく、長い見出しや説明が読めるかを試して決める設計条件です。

二列は16rem×2+間隔1rem=33remの内容幅が必要です。外側の左右paddingが各1remなら画面幅は35remになります。三列は48rem+二つの間隔2rem+左右2rem=52remです。

カード内のpaddingは16remに含めているため再加算しません。サイドバーと幅を分ける場合は、画面幅だけではこのカード幅を保証できません。外側の条件を再計算するか、コンテナークエリーで部品の幅を基準にします。

remと境界を含む条件を理解する

min-widthは指定値以上、max-widthは指定値以下で一致します。初期フォントが16pxなら35remは560px、52remは832pxです。ユーザーやブラウザーの初期値で変わるので、remを常に同じpxとは考えません。

メディアクエリー内の相対長は、ページCSSで上書きしたフォントサイズではなく初期値を基準にします。html { font-size: 32px; }を追加するだけで、35remの条件が1120pxになるわけではありません。本文のremと条件のremを分けて考えます。CSS Media Queries仕様の単位で確認できます。

/* Both conditions are true even at 560px. */
@media (max-width: 560px) { /* narrow screen rule */ }
@media (min-width: 560px) { /* wide screen rule */ }

同じ数値のminとmaxは、等しい点で両方一致します。基本とmin-widthを段階的に加える構成なら境界を整理しやすくなります。大画面では二列と三列の両条件が一致しますが、完全例は同じセレクターとプロパティで三列を後にしています。

一列から二列・三列へ広げる完全例

次をmedia-breakpoint.htmlとして保存します。外部ファイルは不要です。見出し、説明、リンクを含む三枚のカードを配置し、長い文字列も入れています。

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>media-breakpoint.html</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font: 1rem/1.6 sans-serif; color: #243447; }
h1, h2, p { margin-top: 0; } a { color: #145f8f; }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 3px solid #ac4100; outline-offset: 3px; }
.content { width: min(100%, 70rem); margin-inline: auto; padding: 1rem; }
.cards { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; }
.card { min-width: 0; padding: 1rem; border: 1px solid #789; background: #eef5fa; overflow-wrap: anywhere; }
.card h2 { font-size: 1.25rem; } .card a { display: inline-block; padding: .5rem; }
@media (min-width: 35rem) { .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 52rem) { .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
</style>
</head>
<body>
<main class="content"><h1>Choose breakpoints based on the content</h1>
<p>The target minimum card width is 16rem, including the border and padding.</p>
<div class="cards">
<article class="card"><h2>Files and screen settings to prepare</h2><p>The description and link should follow naturally even when the heading wraps onto several lines.</p><a href="#result">Read the first description</a></article>
<article class="card"><h2>Options for narrow screens</h2><p>Reduce the number of columns to make room instead of simply shrinking the text.</p><a href="#result">Read the second description</a></article>
<article class="card"><h2>English identifier</h2><p>ARTICLE_REFERENCE_WITHOUT_SPACES_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</p><a href="#result">Read the third description</a></article>
</div><p id="result">Check that links and keyboard focus remain visible on the screen.</p></main>
</body>
</html>

minmax(0, 1fr)とアイテムのmin-width: 0で、長い内容が列を押し広げる影響を抑えます。ただし文字だけを無理に詰めるのではなく、必要に応じて列数を減らすのがこの例の目的です。本文の最大70remで、列が無制限に広がることも防ぎます。

境界の直前・一致点・直後を確認する

  1. 初期フォント16pxの条件で559・560・561pxを比べます。559pxは一列、560pxから二列です。
  2. 831・832・833pxを比べます。831pxは二列、832pxから三列です。境界でもカードの外幅が16rem以上か確認します。
  3. 二列の境界だけを30remへ変えます。480pxでカードが目標より狭くなり、見出しの行数が増えるか見て35remへ戻します。
  4. ブラウザーの既定フォントを変える条件と、CSSのhtmlフォントだけを変える条件を別々に記録して比較します。

メディアクエリーは向き、入力能力、動きを減らす設定なども判定できます。狭い画面が必ずタッチ入力、大きい画面が必ずマウスとは限りません。幅の配置を整え、機能に必要な条件だけを加えます。MDNのメディアクエリーを参照してください。