REM と EM を理解する: CSS の相対単位の完全ガイド

こんにちは！私は山本壮太です。レスポンシブ Web アプリケーションの構築に 9 年間携わり、CSS の冒険を数多く経験してきました。現在はデザイン システム会社でフロントエンド アーキテクチャを率いており、かつて私が直面したのと同じ CSS の課題に何百人もの開発者が苦戦しているのを見てきました。経験豊富な開発者の間でも話題に上るトピックの 1 つは、相対単位 (具体的には rem と em) の適切な使用です。

母のラップトップで、私が作成した「レスポンシブ」なナビゲーション メニューが壊れる理由がわかった日のことを、今でも覚えています。母がブラウザーのデフォルトのフォント サイズを変更したため、ピクセル単位で完璧にレイアウトしていたレイアウトが、トランプの家のように崩れてしまいました。それが、CSS ユニットを本当に理解するきっかけとなり、今日、それ以来の旅で学んだことをすべて皆さんにお伝えします。

誰もが同じような設定の同じようなデバイスでサイトを閲覧していると想定できた時代から、Web は大きく進化しました。ピクセルがすべての答えだと私は思っていました。ピクセルはシンプルで予測可能で、目的を達成できるからです。少なくとも私はそう思っていました。

その後、モバイル デバイスが爆発的に普及しました。突然、私たちは小さなスマートウォッチの画面から巨大な 4K ディスプレイまで、あらゆるものを扱うようになりました。[アクセシビリティのニーズ](https://www.a11yproject.com/checklist/) も加わり、従来のピクセル ベースのアプローチではもはや十分ではないことが明らかになりました。

相対単位 [rem と em](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Values_and_units) を入力します。これらはピクセルの代替手段というだけでなく、Web サイトの適応性とアクセシビリティを高める強力なツールです。しかし、経験上、これらを理解するのは難しい場合があります。それでは、これを段階的に説明しましょう。

### 固定単位の問題

rem と em について詳しく説明する前に、なぜこれらが必要なのかを説明しましょう。ピクセルなどの固定単位はわかりやすいですが、柔軟性に欠けます。ユーザーが [ブラウザのフォント サイズを変更したり、ズームインしたり](https://www.w3.org/WAI/meta/customize/) すると、ピクセル ベースの測定値は固定されたままになります。これは単なる小さな不便ではなく、これらのアクセシビリティ機能に依存しているユーザーにとって Web サイトが使いにくくなる場合があります。

## REMとEMの深掘り

### コアコンセプト

CSS を使い始めた頃、私は em 単位をある種の黒魔術だと思っていました。ある日は間隔が完璧に見えても、次の日には別の要素をネストすると、突然パディングが意図した 2 倍の大きさになります。しかし、これらの単位が実際にどのように機能するかを理解すると、それらは CSS の武器庫の中で信じられないほど強力なツールになります。

#### EMユニット: コンテキストが重要
Em 単位はコンテキストに関係します。親要素を見て、「大きさを教えてください。それに応じてサイズを調整します」と指示します。これにより、比例して拡大縮小するコンポーネントを作成する場合に非常に便利です。

```css
.card {
  font-size: 16px;
  
  /* These will all be relative to 16px */
  .title {
    font-size: 1.5em;    /* = 24px */
    margin-bottom: 0.5em; /* = 12px (relative to title's font-size) */
  }
}
```

#### REMユニット：一貫性が鍵
REM 単位は、ドキュメントのルート フォント サイズへの直接の線を持つようなものです。要素がどれだけ深くネストされていても、常にその単一の真実のソースを参照します。この予測可能性により、デザイン全体で一貫した間隔を維持するのに最適です。

```css
html {
  font-size: 16px;
}

/* These will always be relative to 16px, no matter where they appear */
.deeply-nested-element {
  font-size: 1.25rem;  /* = 20px */
  margin: 1rem;        /* = 16px */
  padding: 0.75rem;    /* = 12px */
}
```

### 技術的実装

長年にわたり、開発者が苦労するのは、rem 単位と em 単位が何であるかを理解していないからではなく、[ブラウザーが実際にそれらを処理する方法](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_box_model) を十分に理解していないからであることに気づきました。これをわかりやすく説明しましょう。

ブラウザが rem 単位に遭遇すると、それは非常に簡単です。単にルート フォント サイズを見て計算するだけです。しかし、em 単位の場合は、さらに興味深いことが起こります。実際に内部で何が起きているかを以下に示します。

```css
.parent {
  font-size: 16px;
}

.child {
  /* Browser first checks parent's font-size (16px) */
  font-size: 1.5em;    /* Now 24px */
  
  /* For other properties, browser uses THIS element's font-size */
  padding: 1em;        /* This is 24px, not 16px! */
  margin-bottom: 0.5em; /* This is 12px (half of 24px) */
}
```

この行動は、私が認めたい以上に何度も私を驚かせました。しかし、一度理解してしまえば、それを有利に利用することができます。

## 例を挙げて実践的に理解する

理論から実践に移りましょう。私はさまざまなプロジェクトで CSS のリファクタリングに数え切れないほどの時間を費やし、一貫してうまく機能するパターンを見つけました。私が学んだことは次のとおりです。

### EMユニットが輝くとき

Em 単位は、1 つの単位として拡大縮小する必要のあるコンポーネントを構築するときに、その真価を発揮します。最近私が取り組んだこのボタン コンポーネントを見てみましょう。

```css
.button {
  font-size: 1rem;     /* Start with a base size */
  padding: 0.75em 1.5em; /* Padding scales with font size */
  border-radius: 0.25em; /* Even the roundness scales! */
  
  &.small {
    font-size: 0.875rem;  /* Everything scales down proportionally */
  }
  
  &.large {
    font-size: 1.25rem;   /* Everything scales up proportionally */
  }
}
```

このアプローチでは、フォント サイズだけを調整すれば、他のすべてが比例して拡大縮小されます。まるで、組み込みのスケーリング システムがあるようです。

### REMユニット: レイアウトの最高の味方

レイアウトと一般的な間隔については、rem 単位のおかげで数え切れないほどの悩みから解放されました。以下は最近のプロジェクトからの実際の例です。

```css
.content-grid {
  /* Consistent gaps regardless of font sizes */
  gap: 2rem;
  padding: 1.5rem;
  
  .card {
    /* Card sizing stays consistent */
    max-width: 20rem;
    margin-bottom: 1.5rem;
    
    /* But internal spacing can scale with content */
    .card-content {
      padding: 1em;
    }
  }
}
```

## 高度な概念

これらのユニットを何年も使ってきた私は、それぞれのユニットをいつ使うべきかについて、強い意見を持つようになりました。しかし、もっと重要なのは、自分のルールを破るべき時を学んだことです。

### 戦略ユニットの選択

ユニットを選択するための実用的なガイドは次のとおりです。

For rem:
```css
/* Global spacing that should stay consistent */
:root {
  --space-sm: 1rem;    /* 16px */
  --space-md: 1.5rem;  /* 24px */
  --space-lg: 2rem;    /* 32px */
}

/* Typography that needs to be predictable */
h1 {
  font-size: 2.5rem;
  margin-bottom: 1rem;
}
```

For em:
```css
/* Components that should scale as a unit */
.alert {
  font-size: 0.875rem;
  padding: 1em 1.25em;
  
  .alert-icon {
    width: 1.5em;
    height: 1.5em;
    margin-right: 0.5em;
  }
}
```

### アクセシビリティを実現する

アクセシビリティは単なる流行語ではありません。私たちのウェブサイトを実際に利用する人々に関するものです。ユーザーから、高コントラストの設定ではドキュメント サイトが読みにくいという報告があったときに、私はこのことを直接学びました。相対単位を使用することで、この問題を解決することができました。

```css
/* This scales beautifully with user preferences */
.documentation {
  font-size: 1rem;
  line-height: 1.6;
  max-width: 65ch;  /* Character-based width for better readability */
  
  code {
    font-size: 0.9em;  /* Slightly smaller than surrounding text */
    padding: 0.2em 0.4em;
  }
}
```

## トラブルシューティングガイド

私が実際に遭遇したデバッグのシナリオとその解決方法をいくつか紹介します。

### 増殖するEMのケース

私のチームメンバーの一人が、次のような不可解な問題を私に持ちかけました。

```css
/* What they had */
.nested-menu {
  font-size: 1.2em;
  
  .submenu {
    font-size: 1.2em;
    
    .submenu-item {
      font-size: 1.2em; /* Oops! Now we're at 1.728em from root */
    }
  }
}

/* What we changed it to */
.nested-menu {
  font-size: 1.2rem;  /* Start fresh from root */
  
  .submenu {
    font-size: 1rem;  /* Reset to base size */
    
    .submenu-item {
      font-size: 0.9rem;  /* Slightly smaller than base */
    }
  }
}
```

### ユニットが衝突するとき

私がよく目にするもう 1 つの一般的な問題は、影響についてよく考えずに単位を混在させることです。

```css
/* This can lead to unexpected results */
.component {
  font-size: 16px;
  padding: 1em;    /* Based on px */
  margin: 1rem;    /* Based on root */
}

/* Better approach */
.component {
  font-size: 1rem;
  padding: 1em;     /* Now consistently based on rem */
  margin: 1rem;     /* Predictable spacing */
}
```

## ベストプラクティス

何年も試行錯誤した結果、最も効果的だとわかった方法は次のとおりです。

### プロジェクトの設定

しっかりとした基礎から始めましょう:

```css
/* Modern CSS setup */
:root {
  /* Define your scale */
  --scale-000: 0.75rem;  /* 12px */
  --scale-100: 1rem;     /* 16px */
  --scale-200: 1.25rem;  /* 20px */
  --scale-300: 1.5rem;   /* 24px */
  
  /* Spacing variables */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 1rem;
  --space-4: 2rem;
}
```
オプションで、rem の計算を簡単にするために、ルート要素のサイズを 62.5% に設定して、1rem = 10px にすることができます。こうすることで、rem のサイズを簡単に計算できます。

```css
html {
  font-size: 62.5%;  /* Makes 1rem = 10px */
}

body {
  font-size: 1.6rem;  /* Brings it back to 16px */
  line-height: 1.5;
}
```

ただし、ルート フォント サイズをパーセンテージで設定するこの方法は使用しません。慣れていない場合、混乱が生じる可能性があるためです。代わりに、CSS 変数 (1 番目の方法のように) を使用してプロジェクトを設定するか、ルート要素のサイズを 16px に設定し、デザインで使用するオンライン コンバーターを使用して px を rem または em に計算します。[この rem](https://cssunitconverter.com/px-to-rem) と [この em](https://cssunitconverter.com/px-to-em) コンバーターをブックマークしていますが、好きなものを使用できます。これにより、デザインが同じように効率的になります。

## 実例

最近構築した実際のコンポーネントにすべてをまとめてみましょう。

```css
.article-card {
  /* Base sizing */
  font-size: 1rem;
  padding: 1.5rem;
  margin-bottom: 2rem;
  max-width: 40rem;
  
  /* Typography */
  .card-title {
    font-size: 1.5rem;
    margin-bottom: 0.5em;  /* Relative to title size */
    line-height: 1.2;
  }
  
  .card-meta {
    font-size: 0.875rem;
    color: var(--text-secondary);
    margin-bottom: 1rem;  /* Consistent spacing */
  }
  
  .card-content {
    line-height: 1.6;
    margin-bottom: 1.5em;
  }
  
  .card-footer {
    font-size: 0.875rem;
    padding-top: 1rem;
    border-top: 1px solid var(--border-color);
  }
}
```

## 結論

大規模な Web アプリケーションの構築と保守に何年も費やしてきた私は、相対単位をマスターすることは、フロントエンド開発者として身に付けられる最も価値のあるスキルの 1 つであると自信を持って言えます。相対単位は、見た目を良くするだけでなく、誰にとっても使いやすいインターフェースを構築するものです。

次にピクセルに手を伸ばしたくなったときは、どこかの誰かが、代わりに相対単位を使用したことに感謝してくれることを思い出してください。より大きなテキストを必要とするユーザーであれ、コードを保守する開発者であれ、あるいは将来の自分自身であれ、今日単位について考えたことは、明日の利益になります。

実験を続け、好奇心を持ち続け、最も複雑な CSS の概念でさえ、練習と粘り強さで明らかになることを覚えておいてください。