はじめに

レスポンシブデザインを実装する上で、CSSの単位選択は非常に重要な要素です。同じ数値でも使用する単位によって、デバイスの画面サイズやユーザーの設定に応じた挙動が大きく異なります。

「なぜ16px1remは同じサイズなのに使い分けが必要なのか」「vw%はどちらを使うべきか」といった疑問を持つ方は多いのではないでしょうか。これらの疑問に答えるためには、各単位の特性と適切なユースケースを理解する必要があります。

本記事では、CSSの単位について以下の内容を解説します。

  • 絶対単位と相対単位の違いと特徴
  • rememの使い分けと実践例
  • ビューポート単位(vwvhvminvmax)の活用法
  • clamp()関数による流動的サイジングの実装
  • 実務で使える単位選択の判断基準

前提条件

本記事を読み進めるにあたり、以下の知識があることを前提としています。

  • HTMLとCSSの基本構文
  • CSSプロパティの基本的な使い方
  • レスポンシブデザインの基本概念(メディアクエリなど)

動作確認環境

  • Google Chrome 131以降
  • Firefox 133以降
  • Safari 18以降
  • Microsoft Edge 131以降

CSSの単位を理解する

CSSで使用できる長さの単位は、大きく絶対単位相対単位の2種類に分類されます。

flowchart TB
    subgraph units["CSSの長さ単位"]
        direction TB
        subgraph absolute["絶対単位"]
            px["px(ピクセル)"]
            cm["cm(センチメートル)"]
            mm["mm(ミリメートル)"]
            pt["pt(ポイント)"]
        end
        subgraph relative["相対単位"]
            subgraph font["フォント相対単位"]
                rem["rem"]
                em["em"]
                ch["ch"]
            end
            subgraph viewport["ビューポート単位"]
                vw["vw"]
                vh["vh"]
                vmin["vmin"]
                vmax["vmax"]
            end
            subgraph other["その他"]
                percent["%(パーセント)"]
            end
        end
    end

絶対単位とは

絶対単位は、外部の要因に関係なく常に同じサイズを維持する単位です。

単位 名称 説明
px ピクセル 画面上の1ピクセル(96dpiで1/96インチ)
cm センチメートル 物理的な長さ(1cm = 96px/2.54)
mm ミリメートル 1cm = 10mm
in インチ 1in = 2.54cm = 96px
pt ポイント 1pt = 1/72インチ

Web開発で主に使用される絶対単位は**px(ピクセル)**です。他の単位(cmmmptなど)は印刷用途で使われることがありますが、画面表示ではpxが標準的に使用されます。

1
2
3
4
5
6
/* 絶対単位の例 */
.box {
  width: 300px;   /* 常に300ピクセル */
  height: 200px;  /* 常に200ピクセル */
  border: 2px solid #333;
}

相対単位とは

相対単位は、他の値を基準としてサイズが決定される単位です。基準となる値が変化すると、相対単位で指定されたサイズも連動して変化します。

1
2
3
4
5
/* 相対単位の例 */
.container {
  width: 80%;    /* 親要素の幅の80% */
  font-size: 1.5rem;  /* ルート要素のフォントサイズの1.5倍 */
}

相対単位を使用することで、レスポンシブデザインの実装が容易になります。画面サイズやユーザー設定に応じて自動的にサイズが調整されるためです。

絶対単位:pxの特徴と使いどころ

pxの基本

pxはWeb開発で最も広く使用されている単位です。ピクセルという名前ですが、実際にはデバイスの物理ピクセルとは異なるCSSピクセルを指します。

1
2
3
4
5
.button {
  padding: 8px 16px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

pxを使用するべき場面

pxは以下の用途で使用することが推奨されます。

用途 理由
ボーダー(border 1pxの線は明確に見える必要があるため
シャドウ(box-shadow 影のぼかし具合を正確に制御するため
極小の装飾要素 スケールすると見えなくなる可能性があるため
メディアクエリのブレークポイント デバイスの画面幅を正確に判定するため
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/* pxが適切な使用例 */
.card {
  border: 1px solid #e0e0e0;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* メディアクエリ */
@media (min-width: 768px) {
  .container {
    max-width: 720px;
  }
}

pxのデメリット

pxには以下のデメリットがあります。

  1. ユーザーのフォントサイズ設定を無視する: ブラウザの設定でフォントサイズを変更しても、pxで指定された要素は変化しない
  2. スケーラビリティがない: 画面サイズに応じて自動調整されない
  3. アクセシビリティの問題: 視覚に困難を抱えるユーザーがテキストサイズを変更できない
1
2
3
4
/* アクセシビリティ上問題のある例 */
.text {
  font-size: 14px;  /* ユーザーがフォントサイズを大きくしても変化しない */
}

フォント相対単位:remとem

remの基本

rem(root em)は、ルート要素(<html>)のフォントサイズを基準とする単位です。ブラウザのデフォルトでは、ルート要素のフォントサイズは16pxに設定されています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
/* ルート要素のデフォルトは16px */
html {
  font-size: 16px;  /* 明示的に設定することも可能 */
}

.heading {
  font-size: 2rem;    /* 16px × 2 = 32px */
  margin-bottom: 1rem; /* 16px × 1 = 16px */
}

.paragraph {
  font-size: 1rem;    /* 16px × 1 = 16px */
  line-height: 1.5rem; /* 16px × 1.5 = 24px */
}

remの最大の利点は、ルートのフォントサイズを変更するだけで、すべてのrem指定要素が比例してスケールする点です。

1
2
3
4
5
6
7
8
9
/* ルートのフォントサイズを変更すると全体がスケール */
html {
  font-size: 18px;  /* 16pxから18pxに変更 */
}

/* 上記の変更により */
.heading {
  font-size: 2rem;    /* 18px × 2 = 36px に自動変更 */
}

emの基本

emは、親要素のフォントサイズを基準とする単位です。これがremとの最大の違いです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
.parent {
  font-size: 20px;
}

.parent .child {
  font-size: 1.5em;  /* 20px × 1.5 = 30px */
}

.parent .child .grandchild {
  font-size: 1.5em;  /* 30px × 1.5 = 45px(親の.childを基準) */
}

上記の例のように、emはネストするごとに累積的にサイズが変化します。この特性は意図的に活用することもできますが、予期しない結果を招くこともあります。

remとemの使い分け

rememの使い分けは、以下の指針に基づいて判断します。

用途 推奨単位 理由
フォントサイズ rem 一貫したスケーリングを保証
マージン・パディング(グローバル) rem ページ全体で一貫した間隔を維持
コンポーネント内の間隔 em フォントサイズに連動した間隔が必要な場合
メディアオブジェクトの装飾 em テキストサイズに比例させたい場合

以下は、emが効果的に機能するコンポーネントの例です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/* ボタンコンポーネント:フォントサイズに応じてパディングも変化 */
.button {
  font-size: 1rem;
  padding: 0.5em 1em;  /* フォントサイズに比例したパディング */
  border-radius: 0.25em;
}

.button--large {
  font-size: 1.25rem;
  /* パディングも自動的に大きくなる */
}

.button--small {
  font-size: 0.875rem;
  /* パディングも自動的に小さくなる */
}
flowchart LR
    subgraph rem["remを使う場面"]
        A["フォントサイズ"]
        B["ページ全体のマージン"]
        C["メディアクエリの値"]
    end
    subgraph em["emを使う場面"]
        D["コンポーネント内のパディング"]
        E["アイコンサイズ"]
        F["ボタンの角丸"]
    end

アクセシビリティとrem

remを使用することで、アクセシビリティが向上します。ユーザーがブラウザの設定でフォントサイズを変更した場合、remで指定された要素はその設定を尊重してスケールします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* アクセシビリティに配慮した実装 */
html {
  font-size: 100%;  /* ユーザー設定を尊重(通常16px) */
}

body {
  font-size: 1rem;
  line-height: 1.6;
}

h1 {
  font-size: 2.5rem;  /* ユーザー設定に応じてスケール */
}

h2 {
  font-size: 2rem;
}

p {
  font-size: 1rem;
  margin-bottom: 1rem;
}

ビューポート単位:vw・vh・vmin・vmax

ビューポート単位の基本

ビューポート単位は、ブラウザの表示領域(ビューポート)のサイズを基準とする単位です。

単位 基準 説明
vw ビューポートの幅 1vw = ビューポート幅の1%
vh ビューポートの高さ 1vh = ビューポート高さの1%
vmin 幅と高さの小さい方 1vmin = min(vw, vh)
vmax 幅と高さの大きい方 1vmax = max(vw, vh)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* ビューポート単位の基本例 */
.hero {
  width: 100vw;   /* ビューポート幅いっぱい */
  height: 100vh;  /* ビューポート高さいっぱい */
}

.half-screen {
  width: 50vw;   /* ビューポート幅の半分 */
  height: 50vh;  /* ビューポート高さの半分 */
}

vwとvhの活用例

フルスクリーンセクション

1
2
3
4
5
6
.fullscreen-section {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

ビューポート幅に応じたフォントサイズ

1
2
3
.responsive-heading {
  font-size: 5vw;  /* ビューポート幅に応じて変化 */
}

ただし、vw単独でフォントサイズを指定すると問題が発生します。

1
2
3
4
5
6
/* 問題のある例 */
.text {
  font-size: 3vw;
}
/* 320px幅: 3vw = 9.6px(小さすぎる) */
/* 1920px幅: 3vw = 57.6px(大きすぎる) */

この問題は後述するclamp()関数で解決できます。

vminとvmaxの活用例

vminvmaxは、デバイスの向き(縦向き・横向き)に関係なく一貫したサイズを維持したい場合に有効です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* 正方形の要素を作成(どの向きでも画面に収まる) */
.square-box {
  width: 80vmin;
  height: 80vmin;
}

/* 大きなタイポグラフィ */
.hero-text {
  font-size: 10vmin;  /* 縦横どちらが小さくても適切なサイズ */
}

モバイルブラウザでのvhの問題と解決策

モバイルブラウザでは、アドレスバーの表示/非表示によってビューポートの高さが変化するため、100vhが期待通りに動作しないことがあります。

1
2
3
4
/* 従来の問題のある実装 */
.fullscreen {
  height: 100vh;  /* モバイルでアドレスバー分はみ出す可能性 */
}

この問題に対処するため、新しいビューポート単位が導入されました。

単位 説明
svh Small viewport height(アドレスバー表示時のビューポート高さ)
lvh Large viewport height(アドレスバー非表示時のビューポート高さ)
dvh Dynamic viewport height(動的に変化するビューポート高さ)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* モダンな解決策 */
.fullscreen {
  height: 100dvh;  /* 動的なビューポート高さに追従 */
}

/* フォールバック付きの実装 */
.fullscreen {
  height: 100vh;
  height: 100dvh;  /* サポートしているブラウザではこちらが適用 */
}

パーセント単位(%)

パーセント単位の基本

パーセント単位は、親要素のサイズを基準として計算されます。ただし、プロパティによって何を基準とするかが異なります。

プロパティ 基準
width 親要素の幅
height 親要素の高さ
padding 親要素の幅(上下左右すべて)
margin 親要素の幅(上下左右すべて)
font-size 親要素のフォントサイズ
line-height 要素自身のフォントサイズ
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
.parent {
  width: 600px;
  height: 400px;
}

.child {
  width: 50%;     /* 300px(親の幅の50%) */
  height: 50%;    /* 200px(親の高さの50%) */
  padding: 5%;    /* 30px(親の幅の5%) */
  margin: 10%;    /* 60px(親の幅の10%) */
}

heightに%を使用する際の注意点

heightにパーセントを使用する場合、親要素に明示的な高さが設定されている必要があります

1
2
3
4
5
6
7
8
/* うまく動作しない例 */
.parent {
  /* heightが未設定 */
}

.child {
  height: 100%;  /* 親の高さが不明なため計算できない */
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/* 正しく動作する例 */
html, body {
  height: 100%;  /* ルートから高さを設定 */
}

.parent {
  height: 100%;
}

.child {
  height: 50%;  /* 正しく計算される */
}

レスポンシブレイアウトでのパーセント活用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* フレキシブルなカードレイアウト */
.card-container {
  display: flex;
  flex-wrap: wrap;
  gap: 2%;
}

.card {
  width: 32%;  /* 3列レイアウト */
}

@media (max-width: 768px) {
  .card {
    width: 48%;  /* 2列レイアウト */
  }
}

@media (max-width: 480px) {
  .card {
    width: 100%;  /* 1列レイアウト */
  }
}

clamp()関数による流動的サイジング

clamp()関数の基本

clamp()関数は、最小値、推奨値、最大値の3つの引数を取り、値を特定の範囲内に制限します。

1
2
/* clamp()の構文 */
property: clamp(最小値, 推奨値, 最大値);

clamp(MIN, VAL, MAX)は、max(MIN, min(VAL, MAX))と等価です。推奨値が最小値と最大値の間にある場合はその値が使用され、範囲外の場合は最小値または最大値が適用されます。

1
2
3
4
5
6
7
8
9
/* フォントサイズの例 */
h1 {
  font-size: clamp(1.5rem, 4vw, 3rem);
}
/* 
  - ビューポートが狭い場合: 最小1.5rem
  - ビューポートが広い場合: 最大3rem
  - その間: 4vwが適用される
*/

流動的タイポグラフィの実装

clamp()を使用することで、メディアクエリなしで流動的に変化するフォントサイズを実装できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
/* 流動的タイポグラフィ */
:root {
  /* 見出し */
  --font-size-h1: clamp(2rem, 5vw + 1rem, 4rem);
  --font-size-h2: clamp(1.5rem, 4vw + 0.5rem, 3rem);
  --font-size-h3: clamp(1.25rem, 3vw + 0.5rem, 2rem);
  
  /* 本文 */
  --font-size-body: clamp(1rem, 1vw + 0.75rem, 1.25rem);
  --font-size-small: clamp(0.875rem, 0.5vw + 0.75rem, 1rem);
}

h1 { font-size: var(--font-size-h1); }
h2 { font-size: var(--font-size-h2); }
h3 { font-size: var(--font-size-h3); }
body { font-size: var(--font-size-body); }
small { font-size: var(--font-size-small); }

推奨値の計算式

clamp()の推奨値には、vwと固定値を組み合わせた計算式を使用することが一般的です。

1
2
3
4
5
6
7
/* 推奨値の計算パターン */
font-size: clamp(1rem, 0.5vw + 0.9rem, 1.5rem);
/*
  0.5vw + 0.9rem という計算式により:
  - ビューポートが小さい場合でも最低限のベースサイズを確保
  - ビューポートが大きくなるにつれて滑らかにサイズが増加
*/

計算式を設計する際のポイントは以下の通りです。

  1. vwの係数が大きいほど、変化が急激になる
  2. 固定値(remなど)を加えることで、最小サイズを保証
  3. 最小値と最大値で安全な範囲を設定

clamp()の活用例

流動的な余白

1
2
3
4
.section {
  padding: clamp(1rem, 5vw, 4rem);
  margin-bottom: clamp(2rem, 8vw, 6rem);
}

コンテナの幅

1
2
3
4
.container {
  width: clamp(300px, 90%, 1200px);
  margin: 0 auto;
}

流動的なギャップ

1
2
3
4
5
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: clamp(1rem, 3vw, 2rem);
}

実践的な単位選択ガイド

プロパティ別推奨単位

以下の表は、各プロパティで推奨される単位をまとめたものです。

プロパティ 推奨単位 理由
font-size remclamp() アクセシビリティと一貫性
line-height 単位なし(1.5など) フォントサイズに比例
width(コンテナ) %clamp() レスポンシブ対応
max-width rempx 読みやすさの上限を設定
paddingmargin remem 一貫した間隔
border px 細い線を明確に表示
border-radius remem% スケーラブルな角丸
box-shadow pxrem 影の精密な制御

決定フローチャート

単位選択の判断フローを以下に示します。

flowchart TD
    A["サイズを指定したい"] --> B{"ユーザー設定に<br/>応じてスケールすべき?"}
    B -->|Yes| C{"要素のフォントサイズに<br/>連動すべき?"}
    B -->|No| D["px を使用"]
    C -->|Yes| E["em を使用"]
    C -->|No| F{"ビューポートに<br/>応じて変化すべき?"}
    F -->|Yes| G{"最小・最大値の<br/>制限が必要?"}
    F -->|No| H["rem を使用"]
    G -->|Yes| I["clamp() を使用"]
    G -->|No| J["vw/vh を使用"]

実践例:完全なコンポーネント

以下は、さまざまな単位を適切に組み合わせたカードコンポーネントの例です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/* カードコンポーネント */
.card {
  /* コンテナ幅はパーセントで柔軟に */
  width: 100%;
  max-width: 400px;  /* 最大幅はpxまたはrem */
  
  /* パディングはremで一貫性を保つ */
  padding: 1.5rem;
  
  /* ボーダーはpxで明確に */
  border: 1px solid #e0e0e0;
  border-radius: 0.5rem;  /* 角丸はremでスケーラブル */
  
  /* シャドウはpxで精密に */
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.card__title {
  /* フォントサイズはclamp()で流動的に */
  font-size: clamp(1.25rem, 2vw + 0.5rem, 1.75rem);
  margin-bottom: 0.75rem;  /* 間隔はrem */
}

.card__description {
  font-size: 1rem;  /* 本文はremで一貫性 */
  line-height: 1.6;  /* 行の高さは単位なし */
  color: #666;
}

.card__button {
  /* ボタン内のパディングはemでフォントに連動 */
  padding: 0.5em 1em;
  font-size: 0.875rem;
  border: 1px solid currentColor;
  border-radius: 0.25em;
}

まとめ

本記事では、CSSの単位について以下の内容を解説しました。

  • **絶対単位(px)**は、ボーダーやシャドウなど、スケールが不要な細かい装飾に使用します
  • remは、フォントサイズやページ全体の間隔など、一貫したスケーリングが必要な場面で使用します
  • emは、コンポーネント内でフォントサイズに連動させたい要素に使用します
  • **ビューポート単位(vw、vh)**は、画面サイズに応じた動的なサイズ指定に使用しますが、単独使用には注意が必要です
  • clamp()関数を使用することで、最小値と最大値を設定した流動的なサイジングを実現できます

適切な単位を選択することで、アクセシビリティに配慮し、さまざまなデバイスに対応したレスポンシブデザインを効率的に実装できます。実際のプロジェクトでは、本記事で紹介した判断基準を参考に、各プロパティに最適な単位を選択してください。

参考リンク