プログラミング

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などを試します。

確認は「収まったか」だけで終えず、次の順に行います。

  1. 本文を拡大しても内容が欠けないか
  2. 一番長い見出しやURLが読めるか
  3. リンクやボタンを押し分けられるか
  4. メニューが消えて、移動できなくなっていないか
  5. 横向きにしても操作できるか

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のカウンター制作も試してみてください。

← 記事一覧へ戻る