@media の向きを読む — min-width か max-width か
Week 07 で、repeat(auto-fit, minmax(240px, 1fr)) ならメディアクエリを1行も書かずに列数が変わることを見ました。あれは自動で任せる書き方です。今週扱う @media は、切り替わる幅を自分で指定する書き方です。AIに「スマホ対応にして」と頼んだときに増えるのは、ほぼこちらです。
@media はただの条件分岐
身構える必要はありません。@media は「この条件が真のときだけ、カッコの中のCSSを適用する」というだけの仕組みです。CSSに if 文が付いたと思ってください。
/* 画面幅が 768px 以上のときだけ、この中が適用される */
@media (min-width: 768px) {
.card-list {
display: flex;
}
}
長いCSSを渡されると @media のブロックが何個も並んでいて圧倒されますが、読むべきなのは条件を書いた1行目だけです。中身は今まで通りのCSSで、新しい知識は要りません。
min-width と max-width で「土台」がどちらか分かる
条件に使われるのは、ほぼ min-width か max-width の2つです。名前が紛らわしいので、ここだけ丁寧に押さえます。
@media (min-width: 768px) { ... } /* 画面幅が 768px 以上のとき */
@media (max-width: 768px) { ... } /* 画面幅が 768px 以下のとき */
min-width は「最小でもこの幅があるとき」=それ以上の広い画面。max-width は「最大でもこの幅までのとき」=それ以下の狭い画面です。「min だから小さい画面」と読み間違えるのが定番のつまづきなので、min = 以上、max = 以下と機械的に覚えてしまうのが早いです。
ここから、そのCSSの土台がどちらの画面なのかが読み取れます。
/* ケースA: 土台がスマホ(= モバイルファースト) */
.card-list {
display: block; /* ← まずスマホ用。縦に積む */
}
@media (min-width: 768px) {
.card-list { display: flex; } /* ← 広い画面のときだけ横並びに上書き */
}
/* ケースB: 土台がPC */
.card-list {
display: flex; /* ← まずPC用。横並び */
}
@media (max-width: 767px) {
.card-list { display: block; } /* ← 狭い画面のときだけ縦積みに上書き */
}
@media の外側に書かれているCSSが、そのコードの土台です。@media の中は、条件を満たしたときだけ土台を上書きする追加分にすぎません。だから条件が min-width ばかりなら「土台はスマホ」、max-width ばかりなら「土台はPC」と判別できます。前者の書き方がモバイルファーストと呼ばれるものです。なお自分で書くときにどちらの向きで組み立てるかは、レスポンシブデザイン実践ガイドの「CSSの記述順序」にまとめてあります。今週は読んで判別できるところまでで十分です。
どちらが土台かで、直す場所が変わる
この判別は雑学ではなく、直す場所を決めるために使います。「スマホで見たときだけ崩れている」という状況を考えてください。
- 土台がスマホ(min-width)のコード → スマホの見た目は
@mediaの外が作っている。@mediaの中をいくら直しても変わらない - 土台がPC(max-width)のコード → スマホの見た目は
@media (max-width: ...)の中が作っている。外を直すとPC表示も一緒に動く
「AIに直してもらったのに、スマホの表示が変わらない」という相談は、たいてい土台の側ではなく上書きの側を直しているだけです。どちらの向きで書かれているかを最初に見れば、この空振りは起きません。
両方が混ざっているとき
AIに追加の修正を何度も頼むと、1つのCSSに min-width と max-width が混在することがあります。前の回答の書き方を引き継がず、そのときの都合で書くためです。
/* 危ないパターン: 768px ちょうどで両方が該当する */
@media (max-width: 768px) {
.title { font-size: 20px; }
}
@media (min-width: 768px) {
.title { font-size: 32px; }
}
max-width: 768px は「768px 以下」、min-width: 768px は「768px 以上」なので、ちょうど 768px のときだけ両方が該当します。このとき勝つのはあとに書かれた方で、上の例では 32px になります。ウィンドウ幅がぴったり 768px のときだけ表示が想定と違う、という再現しにくい不具合の正体はこれです。
見つけたときはどちらかの向きに統一するのが本筋です。統一せずに済ませたいなら、境界を max-width: 767.98px のようにずらして重なりを消します。767px にすると、その間の小数の幅がどちらにも該当しない隙間になるので、.98 を使うのが定番です。
@media が全く効かないとき
条件も中身も正しいのに、実機のスマホで @media がまるごと無視されているように見える場合があります。そのときはCSSではなくHTMLの <head> を見てください。
<meta name="viewport" content="width=device-width, initial-scale=1.0">
この1行が無いと、スマホは「自分の画面幅は980pxくらいある」と嘘の申告をしてページ全体を縮小表示します。画面幅が980px扱いなので、max-width: 768px の条件はいつまでも真になりません。この行の意味は Week 04 のメタタグ入門で扱っているので、忘れていたら見直してください。
覚え方: min-width = それ以上の広い画面 = 土台はスマホ。max-width = それ以下の狭い画面 = 土台はPC。土台は必ず @media の外に書いてある。
その数字に根拠はあるか
@media の向きが読めるようになると、次に目に入るのが条件に書かれた数字です。AIはここに 768 / 1024 / 1280 を置いてきます。この数字を疑えるかどうかが、今週いちばん実利のあるところです。
768 / 1024 / 1280 はどこから来た数字か
結論から言うと、よく使われているから使われている数字です。iPadの縦幅が768pxだった、ノートPCが1280pxだった、という由来のある慣習値で、CSSの仕様で決まっているわけでも、あなたのページに合わせて計算されたわけでもありません。AIは学習した大量のコードでこの数字を見ているので、何も指定しなければこれを置きます。
慣習値が悪いという話ではありません。悪いのはその数字が自分のページで妥当かを確かめないまま採用することです。カードが4枚並ぶページと、表が1つあるだけのページで、崩れ始める幅が同じはずがありません。
AIに理由を聞いて、根拠の有無を確かめる
確かめ方は単純で、AIにその数字の理由を聞くだけです。返答は2種類に分かれます。
- 「一般的なタブレットの幅に合わせました」「よく使われるブレイクポイントです」 → 根拠は慣習だけ。自分で確かめる必要がある
- 「カードの最小幅240pxが3枚 + gap を足すと768pxを超えるので、そこで2列に落としています」 → 中身から計算されている。信用して構わない
前者が返ってきたら、そのまま採用しないでください。「デバイスに合わせて決めるのではなく、このページのコンテンツが崩れる幅で決めたいです」と伝えると、AIは中身を見た提案に切り替えます。伝えないと、AIは崩れる幅を知る手段を持ちません。実際の画面を見ていないからです。
崩れる幅を自分で見つける
最終的に判断するのは自分です。ブラウザの開発者ツールで幅を変えながら探します。手順はこれだけです。
- ページを開いて F12(Macは Command + Option + I)で開発者ツールを出す
- デバイスモード(スマホとタブレットのアイコン)に切り替える。上部に幅の数値が出る
- 幅を1280pxあたりから始め、10pxずつ狭めていく
- 見た目が「これは読みにくい」に変わった瞬間の数値を記録する
- その数値の少し手前を、ブレイクポイントの候補にする
「読みにくいに変わった瞬間」の判断に迷うと思うので、具体的なサインを3つ挙げます。①見出しが不自然な位置で2行になる ②隣り合う要素が重なる・くっつく ③横スクロールバーが出る。どれか1つでも起きたら、そこがあなたのページの限界幅です。慣習値の768pxより手前で起きることも、ずっと先まで平気なことも、どちらもあります。
なお、ここで探しているのは「自分のページの崩れる幅」です。ブレイクポイントを何本置くか、どの順にCSSを書くかといった設計の組み立て方は、レスポンシブデザイン実践ガイドにまとめてあります。今週はAIが置いた数字を検算できる状態までで十分です。
覚え方: ブレイクポイントに正解の数字は無い。自分のコンテンツが崩れる幅が正解。AIが置いた 768 は「よく見る数字」であって、あなたのページを見て決めた数字ではない。
px / % / rem / vw / clamp() の読み分け
AI出力には単位が混ざって出てきます。Week 05 のCSSの単位で一通り扱いましたが、今週必要なのは覚え直しではなく、出てきた単位を見て「画面幅が変わったらこの値はどうなるか」を即答できることです。
見るのは「何を基準に変わるか」だけ
px— 固定。基準が無いので、画面幅が変わっても値は動かない%— 親要素が基準。親が広がれば一緒に広がるrem— ルート(html)のフォントサイズが基準。画面幅では動かないvw— ビューポート幅が基準。画面幅に正比例して伸縮する。上限も下限も無いclamp(最小, 可変, 最大)— 真ん中の値で伸縮するが、両端を超えない
clamp() だけは形が特殊なので、読み方を1つ挙げます。
font-size: clamp(1.8rem, 4vw, 3.2rem);
/* 1つ目の 1.8rem = 最小値。これより小さくならない */
/* 2つ目の 4vw = 可変値。画面幅に合わせて動く */
/* 3つ目の 3.2rem = 最大値。これより大きくならない */
引数は必ず「最小・可変・最大」の順です。真ん中に画面幅で動く単位(vw)が入っていて、両側が固定値という並びになっていれば、それは「伸縮するが行き過ぎない」という意図です。両端の数字を見れば、どこまで小さくなるか・大きくなるかがそのまま読み取れます。真ん中の 4vw がどこから出てきた数字かは、いま気にしなくて構いません。
AI出力で疑う2つのパターン
単位の意味が分かると、スマホで崩れる予兆が読めるようになります。疑うべきは2つです。
/* パターン1: 幅に px が並んでいる */
.sidebar { width: 320px; }
.main { width: 880px; }
/* → 合計1200px。375pxの画面では確実にはみ出す */
/* パターン2: font-size に vw が単独で入っている */
.hero-title { font-size: 5vw; }
/* → 375pxの画面では 18.75px、1920pxの画面では 96px。
下限も上限も無いので、狭い画面で読めなくなる */
パターン1は、AIがPC幅の見た目だけを想定して書いた典型です。幅指定に px が並んでいたら、狭い画面での合計を頭で足してみる癖をつけてください。パターン2は「レスポンシブなタイポグラフィにして」と頼んだときに返ってきやすい形で、clamp() に置き換えれば解決します。
それぞれの単位をどの場面で選ぶか、clamp() の値をどう計算するかは、CSS単位の使い分け完全ガイドに詳しくまとめてあります。今週は読めれば十分で、自分で値を組み立てるのは後からで構いません。
覚え方: 単位を見たら「何が基準か」を1問だけ自分に聞く。pxは基準なし(固定)、%は親、remはルート、vwは画面幅。clamp()は「伸縮するが両端は超えない」。
画像がはみ出す・伸びる
レスポンシブで最初に壊れるのは、たいてい画像です。しかも原因はほぼ1つに決まっているので、見るべき場所も2行だけです。
見るのは2行だけ
img {
max-width: 100%; /* ← 親の幅を超えない */
height: auto; /* ← 縦横比を保つ */
}
AI出力に画像が含まれていたら、この2行が入っているかを最初に確認してください。入っていなければ、画像は元のファイルの実寸で描画されます。1920px幅の写真は375pxの画面でも1920pxのまま置かれ、親要素を突き破って横スクロールを生みます。
max-width: 100% だけを入れて height: auto を忘れるのもよくある形です。幅は親に収まるようになりますが、高さが元の値のまま残るため、画像が縦に引き伸ばされて潰れます。「なぜか写真だけ縦長に歪んでいる」という症状はこれです。2行はセットで確認してください。
Week 03 の画像を表示する — img タグで、width と height 属性をHTMLに書きました。あれは読み込み中に枠を確保しておくための指定で、画面幅への追従はCSSのこの2行が担当します。役割が別なので、両方あって構いません。HTMLに width="800" と書いてあるからCSSは不要、とは読まないでください。
srcset が出てきたとき
AI出力に srcset という属性が混ざってくることがあります。
<img src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1600.jpg 1600w"
alt="作業風景">
意味は「同じ写真を複数のサイズで用意しておいて、ブラウザに選ばせる」仕組みです。スマホに1600pxの画像を送る必要は無いので、通信量と表示速度のために使われます。今週はそういう仕組みがあると知っているだけで十分で、書けなくても困りません。
むしろ注意したいのは逆で、AIが srcset を提案してきても、そこに書かれたファイルは存在しないという点です。photo-400.jpg を自分で用意していなければ画像は表示されません。AIはファイルを作れないので、この属性が出てきたら「複数サイズを自分で書き出す作業が付いてくる」と読んでください。
設計の考え方や実装の手順は、それぞれの解説ページにまとめてあります。今週の「読み方」で当たりを付けてから引いてください。
- レスポンシブデザイン実践ガイド
- CSS単位の使い分け完全ガイド
- CSS clamp() ジェネレーター — 実際に値を作って挙動を確かめられます
今週の課題
Week 08 課題
Week 07 で作ったカード3枚のレイアウト(Flexbox版とGrid版)を、そのまま使います。今週はこれをスマホ1列 / タブレット2列 / PC3列に切り替わるようにします。ブレイクポイントの数字は慣習値を写さず、自分のカードが崩れる幅を探して決めるのがこの課題の本題です。
必須要件
- Week 07 のFlexbox版を土台に使う(Grid版はボーナス課題で扱います)。HTMLは変えず、CSSだけを書き換える
- まず
@mediaの外に、スマホ用の状態(カードが縦1列)を書く。ここが土台になる @mediaはmin-widthに統一する。max-widthは1つも使わない- ブレイクポイントを2本置く(2列にする幅と、3列にする幅)
- その2つの数値を、DevToolsで幅を10pxずつ狭めて崩れる点を探して決める。768 / 1024 をそのまま書かない
- 決めた数値の根拠をCSSのコメントに書く(例:
/* 2列だとカードが240pxを切るのでここで1列へ */) - カードの見出しか本文のfont-sizeを1箇所
clamp()にする。値はCSS clamp() ジェネレーターで生成する - 幅を375pxにして、横スクロールバーが出ないことを確認する
- 画像を1枚入れ、
max-width: 100%とheight: autoを付ける前と後の両方を見て、はみ出しが消えるのを確認する - 幅を1280pxから375pxまでゆっくり狭め、3列 → 2列 → 1列と自分が意図した幅で切り替わることを確認する
ボーナス課題
- 同じ課題を
max-widthだけで書き直し(土台をPCにする)、どちらが読みやすいかを自分の感覚で比べる - わざと
@media (max-width: 768px)と@media (min-width: 768px)を両方書き、幅がぴったり768pxのときだけ表示が変わるのを再現する。順番を入れ替えると結果が変わることも確認する <meta name="viewport">の1行を一時的に消して、スマホ表示でメディアクエリが効かなくなることを確認してから戻すclamp()の真ん中の値を4vwから10vwに変え、上限で止まるのを確認する- Week 07 のGrid版で、
@mediaを1行も使わずrepeat(auto-fit, minmax(240px, 1fr))だけで同じ3→2→1列を作り、メディアクエリ版との書く量の違いを比べる
自己チェック項目(提出前に確認)
@mediaの外に書いたのは、スマホの状態か(PCの状態を書いていないか)min-widthだけで書けているか。max-widthが混ざっていないか- ブレイクポイントの数値に、コメントで根拠を書いたか
- その数値は、自分がDevToolsで見つけた幅か(慣習値を写していないか)
- 幅375pxで横スクロールバーが出ないか
clamp()を入れた箇所が、狭い幅でも読めるサイズで止まっているか- 画像に
max-width: 100%とheight: autoの2行が揃っているか
自己診断テスト
@media (min-width: 768px)はどちらの画面に適用されますか。またそのコードはスマホ基準ですか、PC基準ですか?- 「スマホだけ表示を直したい」とき、
min-widthで書かれたCSSでは@mediaの中と外のどちらを触りますか? - ブレイクポイントの「正しい値」はどう決めますか。AIが置いた768pxをそのまま使ってよいのはどんなときですか?
vwだけでフォントサイズを指定すると何が起きますか。clamp()にすると何が変わりますか?px/%/rem/vwは、それぞれ何を基準に値が決まりますか?- スマホで横スクロールバーが出たとき、最初に何をしますか。原因の候補を3つ挙げられますか?
- 実機のスマホで
@mediaがまるごと効いていないように見えるとき、CSSの前に確認するHTMLの1行は何ですか?
答えに詰まった問題があれば、その番号の内容を扱ったセクションに戻ってください。7問すべてを人に説明できる状態になっていれば、AIが出したレスポンシブCSSを渡されても、どこを見ればいいか迷わなくなります。
HTML/CSS土台 完走 — ここまでで身についたこと
Week 01 から8週かけて、AIが出したHTMLとCSSを読んで、崩れている箇所を1つ直せるところまで来ました。全部を自分で書けるようになったわけではありません。それは今も目標ではありません。返ってきたコードのどこを見ればいいか分かる、これがバイブコーディングの土台です。
8週間で身についたのは、具体的にはこの3つです。①構造を読む力(HTMLのどこが何を表しているか) ②見た目の因果を辿る力(なぜこう表示されているかをCSSから説明できる) ③症状から原因に辿る力(崩れを見て確認する場所を絞れる)。この3つは、この先JavaScriptに進んでも同じ形で使い続けます。
HTML/CSS土台 ロードマップ:
- Week 01〜04(済): HTMLの基本構造・テキスト要素・画像とリンク・セマンティックタグとメタ情報
- Week 05〜06(済): セレクタ・詳細度・ボックスモデル・display・position
- Week 07〜08(済・今週): Flexbox・Grid・メディアクエリ・単位
- この先(Coming): JavaScript、TypeScript、React
次のフェーズはJavaScriptです。ここまでは「表示されているものを読む」話でしたが、JavaScriptからは「動きとデータ」が入ります。AI出力を読むうえでの難易度は一段上がりますが、やることは同じで、最初に見る数行を決めて、そこから辿るだけです。公開までしばらくかかるので、その間はここまでの8週分の課題を、自分のページで作り直してみてください。読めるようになった状態を維持する一番安いやり方は、AIに何かを作らせて読むことです。