HTML・CSS入門③ スマホ対応のページを作ろう
スマホで横にはみ出す原因を、幅の計算から理解します。viewport、画像、Grid、メディアクエリーを段階的に使い、1列・2列・3列を切り替える練習まで進めます。
パソコンではきれいなのに、スマホで開くと文字が小さく、横にもスクロールしてしまう。「同じページなのに、どうして?」となりますよね。
原因は、広い画面で成立していた配置を、そのまま狭い画面へ押し込んでいることかもしれません。今回はHTML・CSS入門②のカードを使い、画面幅に合わせて並び方が変わるページへ直します。
この考え方がレスポンシブWebデザインです。スマホ版とPC版を別々に用意するのではなく、同じ内容の見せ方を調整します。
まずスマホ向けに作る
固定幅がはみ出す理由
次の指定を、画面の表示幅が390pxの端末で使うとどうなるでしょうか。
main {
width: 960px;
}
960pxは390pxより大きいので、本文が画面に収まりません。ここで全体を無理に縮小すると、文字まで小さくなります。直したいのは文字ではなく、まず配置の幅です。
次のように変えます。
* {
box-sizing: border-box;
}
main {
width: min(90%, 960px);
margin: 32px auto;
}
親要素が390pxなら本文は351pxです。左右に残る39pxを半分ずつ分け、各19.5pxの余白になります。親が1200pxなら90%は1080pxですが、上限960pxを使います。
このように狭い画面で読める形を基本にし、広くなったら配置を追加する方法をモバイルファーストと呼びます。小さい画面では、縦1列が案外読みやすい出発点になります。
viewportを設定する
HTMLの head に、次の行があるか確認します。
<meta name="viewport" content="width=device-width, initial-scale=1" />
viewport(ビューポート)は、ブラウザーがページを表示する領域です。スマホのブラウザーには、設定がないページを広い仮想的な画面で配置し、それを縮小して見せる動作があります。
width=device-width は、端末の表示幅に合わせたCSS上の幅で配置する指定です。initial-scale=1 は初期の倍率を指定します。
ここでいう幅はCSSピクセルです。端末の製品仕様にある物理的な点の数と、必ずしも同じではありません。「画面が1170ピクセルなのに390pxとして調べる」という状況もあります。
また、user-scalable=no などで利用者の拡大を禁止する必要はありません。細かい文字を拡大して読む人もいるので、レイアウトを直すために拡大機能を奪わないようにしましょう。
画像のはみ出しを防ぐ
大きな写真を置くと、本文が収まっていても画像だけ飛び出すことがあります。画像には次を設定します。
img {
display: block;
max-width: 100%;
height: auto;
}
max-width: 100% は、画像の横幅が親の内容幅を超えないようにします。height: auto は横幅に合わせて高さを決め、元の縦横比を保ちます。
例えば元画像が1200×800、表示できる幅が360pxなら、横幅は元の0.3倍です。高さも800×0.3で240pxになり、つぶれずに表示されます。
「幅100%」と「最大幅100%」は違います。width: 100% は小さい画像も親いっぱいに広げますが、max-width だけなら本来のサイズより無理に広げません。
HTMLに元画像の width と height を書いておくと、読み込み前に場所を確保しやすくなります。ファイルの容量そのものはCSSで小さくならないので、巨大な画像を使う場合は画像ファイル側の調整も必要です。
メディアクエリーで配置を変える
1. まず1列で並べる
前回の .card-list のFlexbox指定を、今回は次へ置き換えます。異なる並べ方を同じ場所へ継ぎ足すより、対象の指定を整理しておきましょう。
.card-list {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
}
.card {
min-width: 0;
}
Gridは、縦横の区画を使って要素を並べるCSSの仕組みです。ここではカードを入れる列を1本だけ作ります。
fr は、余った空間を割合で分ける単位です。1列だけならその列が利用できる幅を使い、1fr 1fr なら同じ割合の2列にできます。
2. 720px以上で2列にする
@media (min-width: 720px) {
.card-list {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
メディアクエリーは、画面幅などの条件に合った場合だけCSSを適用する仕組みです。
min-width: 720px:表示領域の幅が720px以上ならrepeat(2, ...):同じ列指定を2回繰り返すminmax(0, 1fr):最小幅を0にできる、同じ割合の列
minmax を使うのは、長い文字などのせいで列が必要以上に広がるのを抑えるためです。ただし、内容自体のはみ出しには、改行や個別のスクロールも考えます。
3. 境目の前後で計算する
幅が719pxなら条件は不成立なので1列。720pxなら条件が成立して2列です。この切り替え位置をブレークポイントと呼びます。
720pxの画面で本文が90%なら648px。間隔16pxを引いた632pxを2枚で分けるため、1枚あたり316pxです。「720pxを2で割って360px」ではありません。本文の余白とカード間の隙間もあるんですね。
720pxは決まりではありません。自分のカードが窮屈にならず読める幅を見ながら調整します。
はみ出しを隠す前に、原因を探す
横スクロールを消すために、ページ全体へ overflow-x: hidden を付けたくなることがあります。でも、それでは読めない部分を隠すだけかもしれません。
原因別に直してみましょう。
| 原因 | 直し方の例 |
|---|---|
| 本文が固定幅 | max-width や min() を使う |
| 大きい画像 | max-width: 100% と height: auto |
| 長いURLが折り返せない | 対象へ overflow-wrap: anywhere |
| 横長のコードや表 | その部分だけ横スクロール可能にする |
| 見出しが不自然に切れる | 文字サイズや強制改行を見直す |
コードを1行のまま読ませたい場合の例です。
pre {
max-width: 100%;
overflow-x: auto;
}
pre はコードなどの改行を保つ要素です。ページ全体ではなくコード欄だけをスクロールできれば、本文まで左右に動かずに済みます。
実機に近い幅で確認する
ブラウザーの開発者ツールは、ページの構造や動作を調べる機能です。画面幅を変えるモードで、390px・719px・720px・1000pxなどを試します。
確認は「収まったか」だけで終えず、次の順に行います。
- 本文を拡大しても内容が欠けないか
- 一番長い見出しやURLが読めるか
- リンクやボタンを押し分けられるか
- メニューが消えて、移動できなくなっていないか
- 横向きにしても操作できるか
PCの画面幅変更だけでは、スマホの文字描画や指での押しやすさまで再現できません。可能なら自分の端末でも確認しましょう。hoverはポインターを重ねる操作なので、それだけで開くメニューに頼らないことも大切です。
練習:カードを3列にする
画面幅が1000px以上になった場合だけ、同じ幅の3列にしてください。720px以上1000px未満では2列、それより狭ければ1列を保ちます。
前回のHTMLにはカードが2枚なので、3列すべてを確かめるなら section class="card" をもう1枚追加してください。
模範解答
720px用の指定より後ろに、次を追加します。
@media (min-width: 1000px) {
.card-list {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
解説
1000pxのときは「720px以上」と「1000px以上」の両方を満たします。同じセレクターで同じ項目を指定しているため、後ろに書いた3列の指定が使われます。
本文は900px、隙間は2か所で32pxです。残る868pxを3列で分け、1列は約289.3pxになります。
| 表示幅 | 条件に合う指定 | 最終的な列数 |
|---|---|---|
| 390px | 基本だけ | 1列 |
| 800px | 基本と720px以上 | 2列 |
| 1000px | すべて | 3列 |
ここで大事なのは「大きい画面なら必ず列を増やす」ことではありません。3列にした結果、文章が読みづらければ2列のままでも正解です。見た目の密度より、内容が無理なく読める配置を選びましょう。
まとめと参考資料
レスポンシブ対応は、端末名の一覧を覚える作業ではありません。まず小さい幅で内容を読めるようにし、余裕があるときだけ配置を広げる。その順番で考えると、調整する理由が見えてきます。
動きを追加したくなったら、JavaScriptのカウンター制作も試してみてください。