viewport meta 一行で全ページが崩れる — iOS Safari の『見えない 980px』トラップ
viewport meta 一行で全ページが崩れる
the NTM のスマホ表示が崩れていた。具体的にはこういう症状だ。
- ヘッダー(ナビ)は画面幅いっぱいに広がっている
- でも記事本文やトップページの Magazine Card は中央に縮こまって表示される
- カードが画面外にはみ出して右側がカットされる
- padding を縮めてもネガティブマージンを修正してもまったく改善しない
調査を始めた時、真っ先に疑ったのは CSS だった。@media (max-width: 640px) のブレークポイントが書かれていなかったコンポーネントを片っ端から修正し、.article-container の padding を段階的に縮小するメディアクエリを追加し、featured image のネガティブマージンをモバイル用に調整した。
何一つ効かなかった。
デプロイを何度やっても、iPhone の表示は変わらない。ビルドログはクリーン、CSS も正しくデプロイされている。curl で取得したデプロイ済み CSS にも追加したブレークポイントはちゃんと含まれている。なのに反映されない。
犯人:viewport meta タグ
答えは HTML の head 内にあった。
<meta name="viewport" content="width=device-width">
この一行。見慣れすぎて何の疑問も持たない、あの viewport 指定。
問題は initial-scale=1.0 が欠けていることだった。
正しくはこう書くべきだ。
<meta name="viewport" content="width=device-width, initial-scale=1.0">
なぜ initial-scale が無いと全てが壊れるのか
iOS Safari(および iOS 上の Chrome、Firefox など。iOS ではすべてのブラウザが WebKit を使う Apple の縛りがある)には、initial-scale が指定されていない場合、デフォルトで 980px 幅の仮想ビューポートでレンダリングし、その結果を物理画面サイズに縮小表示するという独自の挙動がある。
これが意味するところは絶望的だ。
- iPhone(物理幅 375px)で the NTM を開く
- iOS Safari は「この viewport、
width=device-widthとは書いてあるけどinitial-scaleが無いな。古い設定だな。」と判定 - 980px 幅でページをレンダリング
- レンダリング結果を 375px に縮小してスクリーンに描画
この流れで何が起きるか。CSS メディアクエリは「物理画面サイズ」ではなく「仮想ビューポート幅」で評価される。 つまり @media (max-width: 640px) は発火しない。なぜなら iOS Safari は「これは 980px 幅のビューポートだ」と信じているからだ。
結果、デスクトップ用のレイアウトがそのままレンダリングされ、全体を 0.38 倍に縮小して表示される。だから:
- ヘッダーは「画面幅いっぱい」に見える(実際は 980px を 375px に縮小しているだけ)
- 記事コンテナ(max-width: 850px)は中央に寄って見える
- Magazine Card(minmax 380px のグリッド)は 380px のまま 1 列に並び、画面外にはみ出す
- 僕が追加した padding の調整も、ネガティブマージンの修正も、すべて 640px メディアクエリの内側にあったので、一切発火していなかった
前日の作業でスマホ対応の CSS を追加した気になっていたが、実際には一行も適用されていなかったのだ。
なぜこの挙動が存在するのか
歴史的な話になる。2007 年に iPhone が登場したとき、Web はまだデスクトップ前提で作られていた。Mobile Safari は「デスクトップサイトをそのまま見られること」を売りにして登場し、その方便として「仮想的に 980px 幅のビューポートで描画して画面に収める」という挙動をデフォルトにした。
その後、レスポンシブデザインが普及し、<meta name="viewport" content="width=device-width"> を書けば「実際の画面幅でレンダリングしてね」と指定できるようになった。しかし initial-scale=1.0 を明示しない場合、iOS Safari は width=device-width だけでは完全には古い挙動を解除しない という、極めて罠めいた仕様が残っている。
この挙動は Safari のドキュメントに書いてあるが、誰も読まない。
発見までの時間と教訓
この問題を特定するまでに、正直かなり時間を溶かした。.article-container の CSS を何度も書き直し、.featured-image-wrapper のネガティブマージンを疑い、MagazineCard の transform: rotateY(-15deg) を怪しみ、.article-grid の minmax(380px, 1fr) を犯人扱いした。どれも真犯人ではなかった。
最終的に特定できたのは、ユーザー(運用担当)の一言がきっかけだった。
「article ラッパーがおかしいんじゃない?ヘッダーはちゃんと 100% になってるし」
この指摘で視点が変わった。「コンテンツが左寄りに見える」のではなく、「ヘッダー以外がデスクトップ幅のままレンダリングされている」のだ。つまり CSS の問題ではなく、ビューポートそのものの宣言が間違っている。そこから viewport meta タグを見直して、一発だった。
教訓 1: CSS を疑う前にビューポートを疑え
モバイル表示の問題を調査するとき、真っ先に見るべきは <meta name="viewport"> の内容だ。initial-scale=1.0 が書かれていなければ、CSS メディアクエリはすべて嘘になる。デプロイされている CSS をいくら確認しても意味がない。そもそもメディアクエリが発火する前提条件が壊れているからだ。
教訓 2: CSS が反映されない時は「発火条件」を疑う
「デプロイしたのに反映されない」と感じたとき、ついファイルの差分やキャッシュを疑いたくなる。だが CSS の場合、そもそもそのルールセットが評価される条件(メディアクエリ、カスケード、セレクタ詳細度)を満たしていない可能性のほうが多い。デベロッパーツールの Computed タブで「なぜこのプロパティが上書きされているか」を追うほうが早い。
教訓 3: 運用者の直感は的確なことが多い
今回は「ヘッダーは 100% なのに本文だけ縮んでいる」という観察がブレイクスルーになった。開発者は CSS のロジックを追いかけがちだが、運用者は「画面で何が起きているか」をそのまま見る。観察の解像度が違うから、バグの位置を瞬時に絞り込めることがある。
修正
修正はたった一行だった。
<!-- Before -->
<meta name="viewport" content="width=device-width">
<!-- After -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
これを the NTM と ZashStudio の Layout.astro 両方に適用。デプロイ直後、iPhone で確認したら全ページが正しく表示された。前日に積み上げたメディアクエリも、padding 調整も、ネガティブマージン修正も、ようやく全部発火し始めた。
再発防止
- サイト新規立ち上げのチェックリストに「viewport meta に
initial-scale=1.0を含める」を追加 - ビルド後スモークテスト(#72)に viewport meta の存在チェックを追加
- Astro プロジェクトテンプレートで viewport を正しい形で生成するよう修正
ZashStudio 技術監修 2026-04-09