この記事は、プログラミングをまったく知らない人が「AI に頼らず、自分の手でアプリやサイトを作れる」ようになるための連載(全85本)の第8回です。毎日1本ずつ公開します。
前の回: #07 CSS のレイアウト:Flexbox と Grid
この記事でできるようになること
画面の幅に合わせて並べ方を変え、スマホでも崩れないページを作れるようになります。使うのは <meta name="viewport"> と @media(メディアクエリ)の2つです。これで「段階0 準備」は最後です。
説明
スマホで見ると、なぜ困るのか
前回のページは、パソコンの広い画面では3列でちょうどよく並びました。しかし横幅が狭いスマホで3列にすると、1枚のカードが細くなりすぎます。服でいえば、大人用を子どもが着るようなもので、サイズが合っていません。
そこで「画面が広いときはこの並べ方、狭いときはこの並べ方」と場合分けします。この考え方をレスポンシブデザイン(画面の大きさに応じて見た目が変わる作り)と呼びます。
道具1:viewport(ビューポート)
スマホのブラウザは、何も書かないと「パソコン用の広い画面(980px 前後)をむりやり縮めて表示」します。そのため文字が豆粒のように小さくなります。これを防ぐ宣言が、<head> の中に書く次の1行です。
<meta name="viewport" content="width=device-width, initial-scale=1">
「画面の幅は、その端末の本当の幅にしてね。拡大も縮小もしないでね」という意味です。スマホ対応するページには必ず入れるお約束として覚えてください(意味の詳細は MDN の viewport の解説にあります)。
道具2:@media(メディアクエリ)
CSS の中に「画面の幅がこの条件のときだけ、この中身を使う」と書ける仕組みです。
@media (max-width: 600px) {
/* 画面の幅が 600px 以下のときだけ使うルール */
}
-
max-width: 600pxは「幅が 最大 600px まで」、つまり600px 以下という意味です - 条件に合わない広い画面では、波かっこの中身は無視されます
- この境目の数字をブレークポイントと呼びます(今回は 600px)
手を動かす
コピーせず、自分で打ってください。 前回の layout-practice フォルダを profile-page という名前でコピーして VS Code で開きます。
1. HTML に viewport を足す
index.html の <head> に、<meta charset="UTF-8"> の次の行として足します。
<meta name="viewport" content="width=device-width, initial-scale=1">
2. style.css の一番下に @media を足す
前回の CSS は消さずに、最後に足します。
@media (max-width: 600px) {
.bar {
flex-direction: column;
gap: 8px;
}
.cards {
grid-template-columns: 1fr;
}
}
-
flex-direction: columnは、Flexbox の並べる向きを横から縦に変えます(初期値はrowで横並び)。ロゴの下にメニューが来ます -
grid-template-columns: 1frは、列が1つだけ。カードが1列で縦に並びます -
gap: 8pxは、縦に並べたロゴとメニューのすき間です
後に書いたルールが勝つので、@media は元のルールより後ろに書きます。
3. 画面の幅を変えて確かめる
open index.html
ブラウザでページを開き、Command + Option + I(Mac)で開発者ツールを開きます。左上にあるスマホとタブレットのアイコンを押すと、画面を狭くして確かめられます(ツールの見た目はブラウザのバージョンで変わるので、アイコンが見つからなければ、ウィンドウの幅を手で狭めても大丈夫です)。
私の環境で Chrome に実際に測らせたところ、結果は次のとおりでした。
| 画面の幅 | ロゴとメニュー | カード |
|---|---|---|
| 1000px | 横並び(ロゴが左端、メニューが右端) | 3列、1枚の幅は307px |
| 500px | ロゴの下にメニュー(縦積み) | 1列、1枚の幅は452px |
500px のとき、ロゴは上、メニューはその下に並びました。カードは6枚とも同じ列に縦に並んでいます。
なお、私の環境の Chrome は画面幅を500px より狭くできなかったので、375px のスマホ幅は測っていません。500px も 600px 以下なので、@media の中身は同じように使われます。
4. @media を外して、違いを見る
@media のかたまりをいったん消して500px で見ると、カードは3列のままで、1枚の幅は140pxまで細くなりました。@media を戻すと452px です。足した効果が数字で分かります。
練習問題
答えを見ずに解いてみてください。
- ブレークポイントを
600pxから800pxに変えて、幅700px のときの並びがどうなるか考えてください。 - 幅が
601px以上900px以下のとき、カードを2列にしたい。@mediaをもう1つ足して書いてください(ヒント:min-widthは「最小」、つまり以上です。andで条件をつなげられます)。 - 画面が狭いときだけ、
.menuの文字を大きく(font-size: 20px)してください。
よくあるエラーと直し方
CSS は間違えてもエラーメッセージが出ません。効かないときは次を疑います。
@media の綴りを間違えた
max-width を max-wdith と書くと、その条件は意味を持たず、中のルールが使われません。実際に試すと、500px でもカードは3列のまま(1枚の幅140px)でした。
viewport を書き忘れた
パソコンで開いているだけでは気づけません。スマホの実機で見たときに、ページが小さく縮んで見えます。スマホ対応のページには、必ず <meta name="viewport" ...> を入れてください。
@media を元のルールより前に書いた
同じ要素に同じプロパティが2回出てきたときは、後ろに書いたほうが勝ちます。@media を .cards のルールより前に書くと、あとから来る元のルール(3列)に上書きされ、1列になりません。@media は一番下に置きましょう。
波かっこが足りない
@media の中に .bar { ... } のようなルールが入るので、波かっこは二重になります。最後の } を忘れると、その後のルールがすべて壊れます。VS Code が波かっこの対応を色で見せてくれるので確認してください。
答え
1. 幅700px は 800px 以下なので、@media の中身が使われます。ロゴの下にメニューが来て、カードは1列になります(ブレークポイントを大きくすると、より広い画面から縦並びになる)。
2.
@media (min-width: 601px) and (max-width: 900px) {
.cards {
grid-template-columns: repeat(2, 1fr);
}
}
3.
@media (max-width: 600px) {
.menu a {
font-size: 20px;
}
}
既にある @media の中に足しても同じ動きになります。
次回予告
「段階0 準備」はこれで終わりです。次回からは「段階1 JavaScript の基礎」に入ります。「#09 console.log と開発者ツールで動きを見る」で、動かしながら確かめる方法を学びます。