rem と em の違いを入れ子のデモで
rem は ルート のフォントサイズ (<html> 要素、初期状態で 16px) が基準です。em は 現在の フォントサイズが基準で、font-size の場合は親のフォントサイズです。同じクラスを 3 回入れ子にすると違いがわかります:
表示されたサイズは、ブラウザが計算した値です。1.25em はそれぞれ親に掛け算されて、20px、25px、31.25px になります。1.25rem はルートしか見ないので、20px、20px、20px です。この掛け算のせいで、入れ子のリストやメニューで em のフォントサイズが手に負えなくなります。多くのサイトがフォントサイズを rem で指定するのはこのためです。
各単位の基準
| 単位 | 基準 | 初期状態の 1 単位 |
|---|---|---|
px | なし (CSS ピクセル) | 1px |
rem | ルート要素 (html) のフォントサイズ | 16px |
em | 要素のフォントサイズ。font-size 自体では親のフォントサイズ | 最上位では 16px |
% | プロパティによる (下を参照) | |
vw / vh | ビューポートの幅 / 高さの 1% | |
dvh、svh、lvh | 動的、小さい、大きいビューポートの高さの 1% | |
vmin / vmax | ビューポートの短いほう / 長いほうの辺の 1% | |
ch | 現在のフォントの「0」の幅 | 約 0.5em |
ex | 現在のフォントの x ハイト | 約 0.5em |
CSS ピクセルはデバイスのピクセルではありません。3 倍の画面のスマートフォンでは、1px はデバイスのピクセル 3 つ分の幅です。どの画面でも見た目の大きさがほぼ同じなので、border や影には今でも px で問題ありません。
文字に合わせて変わる余白には em
em はフォントサイズ専用ではありません。padding、margin、width、border-radius では「この要素のフォントサイズの何倍か」という意味になります。そのため、1 つのボタンのクラスがどのサイズでも使えます:
各ボタンの padding は、縦がフォントサイズの半分、横がフォントサイズと同じなので、3 つは同じボタンの 3 つのサイズに見えます。px の padding では、サイズごとに padding のルールが必要になります。
ボタンは初期状態ではページのフォントサイズを継承しない (ブラウザはフォーム部品に独自のサイズを与える) ので、ここの真ん中のボタンは Chrome では 16px ではなく 13.33px です。ボタンや入力欄をページに合わせたいときは font: inherit を追加しましょう。
パーセント: プロパティによって変わる
% には 1 つの意味がありません。何のパーセントかは、プロパティごとに決まっています:
| プロパティ | % の基準 |
|---|---|
width、max-width、left、right | 親 (包含ブロック) の幅 |
height、top、bottom | 親の高さ。親の高さが指定されている場合のみ |
padding、margin (4 辺すべて) | 親の 幅 |
font-size | 親のフォントサイズ (150% = 1.5em) |
line-height | 要素自身のフォントサイズ |
transform: translate() | 要素自身のサイズ |
width: 50% は親の半分の 200px です。padding-top: 5% は 20px で、親の高さではなく 幅 の 5% です。そして height: 50% は何もしません。親に高さが指定されていないので、子要素の高さは文字と padding の分しかありません。このルールは width と height のページ で詳しく解説しています。
vw、vh とモバイルのアドレスバー
1vw はビューポートの幅の 1%、1vh は高さの 1% です。全画面のセクションや、なめらかに変わるサイズ (多くは clamp() の中) に便利です。スマートフォンでは vh に落とし穴があります。スクロールするとブラウザのアドレスバーが出たり引っ込んだりし、100vh はバーが ない ときの高さなので、height: 100vh のヒーローはバーが表示されると下が切れます。新しい単位がこれを解決します:
| 単位 | 使われる高さ |
|---|---|
100vh | ほとんどのモバイルブラウザで大きいビューポート (バーが隠れた状態) |
100svh | 小さいビューポート (バーが表示された状態)。常に収まる |
100lvh | 明示的に大きいビューポート |
100dvh | 動的ビューポート。バーの動きに合わせて変わる |
.hero {
min-height: 100vh; /* fallback for older browsers */
min-height: 100svh; /* fits the screen even with the address bar visible */
}
vw にも落とし穴があります。縦のスクロールバーが場所を取るとき (Windows など)、100vw はその幅を含むので、width: 100vw がページより広くなり、横のスクロールバーが出ることがあります。「親の幅いっぱい」には width: 100% を使いましょう。
読みやすい行の長さには ch
ch は「0」の文字の幅なので、max-width: 65ch で、どのフォントサイズでも段落を 1 行あたり約 65 文字 (読みやすい長さ) に制限できます:
どの単位を使うか
| 用途 | 使う単位 | 理由 |
|---|---|---|
| フォントサイズ | rem | どこでも一貫し、読者のフォントサイズの設定を尊重する |
| コンポーネントの padding とすき間 | rem か em | コンポーネント自身の文字と一緒に大きくしたいなら em |
| border、細い線、影 | px | フォントサイズに関係なく細いままにしたい |
| レイアウトの幅 | %、fr、rem や ch の max-width | コンテナに合わせ、行の長さに上限を付ける |
| 全画面のセクション | svh / dvh (vh を代替に) | モバイルのアドレスバーに対応する |
| なめらかに変わる文字サイズ | rem と vw を組み合わせた clamp() | 範囲内で画面に合わせて大きくなる |
rem は読者を尊重し、px はしない理由
ブラウザには標準のフォントサイズの設定があり、大きい文字が必要な人が使っています。この設定はルートのフォントサイズを変えるので、rem と em のものはすべて一緒に大きくなります。font-size: 14px は、読者が何を選んでも 14px のままです。ブラウザのズームは px も拡大しますが、多くの読者が頼りにしているのはフォントサイズの設定のほうです。フォントサイズを rem で指定する一番の理由はこれです。
1rem を 10px にして計算を楽にするために html { font-size: 62.5%; } を指定するサイトもあります。これでも読者の設定は尊重されます (読者が選んだサイズの 62.5%) が、body に読みやすい font-size を指定するのを忘れないでください。忘れると、自分のサイズを持たない要素がすべて 10px の文字になります。
よくある間違い
- 入れ子の要素で
emのフォントサイズを使う。 階層ごとに掛け算されます。フォントサイズにはremを使いましょう。 - 何もしない
height: 50%。 パーセントの高さが効くには、親に高さの指定が必要です。 padding-top: 10%が親の高さに従うと思う。 上下の padding と margin のパーセントは、親の幅が基準です。width: 100vwで横のスクロールバーが出る。 スクロールバーの幅を含むからです。100%を使いましょう。- スマートフォンで
height: 100vhが切れる。100svhか100dvhを使いましょう。 html { font-size: 12px }を指定する。 ルートに px の値を指定すると、ページ全体で読者のフォントサイズの設定を上書きしてしまいます。ルートはそのままにするか、パーセントを使いましょう。
よくある質問
rem と em の違いは何ですか?
rem はルート要素 (<html>) のフォントサイズが基準なので、1.5rem はページのどこでも同じ大きさです。em はその要素自身のフォントサイズ (font-size の場合は親のフォントサイズ) が基準なので、要素を入れ子にすると掛け算で増えていきます。
1rem は何ピクセルですか?
ブラウザはルートのフォントサイズを 16px にしているので、初期状態では 16px です。ユーザーがブラウザの設定で標準のフォントサイズを大きくしたり、html { font-size: ... } を指定したりすると、1rem もそれに合わせて変わります。
フォントサイズには rem と px のどちらを使うべきですか?
フォントサイズには rem を使いましょう。読者がブラウザで設定した標準のフォントサイズを尊重しますが、px はそれを無視します。ブラウザのズームはどちらも拡大しますが、ズームを使わない読者もいます。
rem ではなく em を使うのはどんなときですか?
ボタンの padding や、文字の横のアイコンのサイズなど、要素自身の文字に合わせて大きさが変わるべき余白に em を使います。そうすれば同じクラスがどのフォントサイズでも正しく見えます。フォントサイズとページ全体の余白には、掛け算で増えないように rem を使います。
100vh と 100dvh の違いは何ですか?
モバイルブラウザの 100vh はアドレスバーが隠れたときの高さなので、バーが表示されている間は 100vh のセクションが見えている画面より高くなります。100dvh (動的ビューポートの高さ) はバーの表示と非表示に合わせて変わり、100svh は常に小さいほうの高さです。