rem へ寄せてゆく

アカベコ

CSS におけるサイズ単位のひとつである rem。これは主に文字を対象とするものだが、これを他の要素へ適用することについて考察する。

CSS のサイズ単位

CSS のサイズ単位は絶対長と相対長へ大別される。詳細は以下の記事を参照のこと。

絶対長は他の長さに影響されず、サイズは常に一定。代表的なものは pxpt など。ディスプレイ (以降、本記事ではこの語を PC 向けディスプレイとして用いる) や紙面などの出力媒体で定められた長さとなる。CSS は主に Web ブラウザーを対象とするため px を利用することが多い。本書のように紙面も想定しているならば @media printptcm へ切り替えることもある。

相対長はなんらかの長さに対してサイズが変化する。この性質により出力媒体によるサイズの差へ対応しやすい。代表的なものは em、そして本記事の主題である rem など。% は単位ではなく割合だが、用途としては相対なので本記事ではこちらに含める。

絶対・相対長の課題と rem

先に絶対長と相対長それぞれの課題を挙げ、それらを解決する手段としての rem を考察する。

絶対長

絶対長はそれ自体の長さこと絶対的だが、出力媒体には依存する。媒体が紙面であれば物理サイズとしての出力は固定なのでよい。しかしディスプレイを対象とする場合、解像度とピクセル密度による可変性が課題となる。

かつてディスプレイのピクセルは固定的であった。しかし 2010 年に iPhone 4 が採用した Retina ディスプレイのあたりから、表示上の長さは変えず、ピクセル密度を高めて精細化する方式が普及し始める。そして現在 (2022 年) は様々なプラットフォームで高解像度・高精細化が一般化して、ピクセル固定を前提とする px への影響が目立つようになった

px を指定しても OS や Web ブラウザーがディスプレイ解像度とピクセル密度を加味して、よしなに長さを変更してくれる。しかしこの処理にも限界があって、例えば 4K ディスプレイ (3840 × 2160) 上で font-size: 12px の文字を表示する際、解像度そのままだとディスプレイの物理サイズによっては読めたものではない。物理サイズが 27 インチぐらいあればよいのだが、15 インチなどでは文字が点のように見えるだろう。そのため OS のディスプレイ設定で拡大指定する必要がある。

では 14px16px のように大きくしてゆけばよいのだろうか?そうした場合、逆に低解像度の環境としては大きすぎるかもしれない。ここに課題の本質がある。それは絶対長を想定しても実際には可変、つまり相対長のように振る舞うことである。絶対長を保証するには出力媒体を固定しなければならない。

相対長

相対長は基準に応じて長さを変える柔軟性があるため、出力媒体の差を緩和した表示を可能とする。ただし基準が課題となる。

em% は親に指定された長さを基準とするため、サイズ予想が難しい。例えば以下の HTML/CSS において <p>font-size は親の .parent に指定された 12px を基準とした 0.9em となる。そのため 10.8px として出力されるが、これは想定どおりだろうか?

<style>
  .parent {
    font-size: 12px;
  }

  p {
    font-size: 0.9em;
  }
</style>
<div class="parent">
  <p>テキスト</p>
</div>

親のサイズ指定が絶対長ならば、まだよい。これが相対長になるとますます予想は難しくなる。例えば以下の HTML/CSS で <p> のサイズを予想できるだろうか?正解は 9.72px だが、<p> の位置を .parent 直下へ移動すると前述の 10.8px になる。

<style>
  .parent {
    font-size: 12px;
  }

  .child {
    font-size: 0.9em;
  }

  p {
    font-size: 0.9em;
  }
</style>
<div class="parent">
  <div class="child">
    <p>テキスト</p>
  </div>
</div>

この難しさもあってか、em よりも px を選ばれることがある。もしくは em を採用しつつも HTML/CSS を慎重に設計する、BEM のような CSS 命名で親子関係の明確化とある程度の一意性を担保する、などの方法により想定内へ収めたりする。

しかし親の長さを基準とする以上、本質的な課題は解決していない。

rem

相対長のひとつに rem がある。

これは長さの基準を親ではなくページのルート要素に設定された文字サイズとする点が特徴。HTML のルート要素は <html> なので、ここが font-size: 16px ならば 1rem16px になる。<html> の既定文字サイズは Web ブラウザーの設定となるため、rem にも反映される。

つまり相対長でありながら基準をひとつとすることで、絶対長のように扱える。試しに相対長の課題として挙げた HTML/CSS へ rem を適用してみよう。これを Web ブラウザーで表示すると、<p> の文字は 14.4px になった。1rem に変えたら 16px となるので、このサイズに対する 0.9 ということなのだろう。

<style>
  .parent {
    font-size: 12px;
  }

  .child {
    font-size: 0.9em;
  }

  p {
    /* 0.9em を 0.9rem に変更 */
    font-size: 0.9rem;
  }
</style>
<div class="parent">
  <div class="child">
    <p>テキスト</p>
  </div>
</div>

ここでひとつ注意が必要。ルート要素 <html> の文字サイズがどこのように決定されるか?である。これは Web ブラウザーによって挙動が異なるようだ。MacBook Pro 15 2019 (Monterey) 上で試したところ、以下のようになった。

  • Firefox 103.0.2
    • <html> の既定は 16px
    • <html> 要素へ明示的に font-size: 1rem を指定すると Firefox に設定された文字サイズが反映される
  • Chrome 104.0.5112.101
    • <html> 要素の指定がなくとも Chrome に設定されたサイズ (この環境だと大 = 20px) が反映される
  • Safari 15.6.1
    • <html> の既定は 16px
    • Safari は最小の文字サイズのみ設定可能、これを下回る font-size は無視されて最小サイズ設定が反映される
    • 既定値 16px を基準とした rem が最小サイズを上回れば、それが反映される
    • 最小サイズ 24px1rem だと既定の 16px なので 24px になるが、2rem なら 32px なのでそのまま反映される

ユーザーが明示的に文字サイズを指定した場合を考慮すると、<html> に対して明示的に 1rem を指定するのがよさそうだ。そうすれば em% と異なり、親要素になにが設定されていても妥当なサイズを設定してくれるだろう。

rem へ寄せてゆく

基本的に rem は文字サイズに対する相対長の単位として使用される。ならば文字と文章が主体となりがちな Web ページは、px% よりも rem でレイアウトするほうが管理しやすいのではなかろうか?

ページの本文幅

例えばヘッダー、フッター、1 カラム中央寄せの本文で構成されたブログがあるとする。HTML として以下を想定。

<header>
  <h1>ブログ</h1>
  <nav>メニュー</nav>
</header>
<article>
  <h1>記事 1</h1>
  <p>本文</p>
</article>
<footer>連絡先</footer>

<article> の横書き本文を中央寄せにしたい。全体レイアウトは中央寄せとレスポンシブともに適用済みで、ページ幅が十分に広い場合の max-width を想定している。その際、<article> の幅へ指定するサイズはどうしたらよいだろうか?サイズ指定の候補としては絶対長から px、相対長は %rem を選んだ。

  • px
    • 絶対長なので 1024px などの固定値を指定
    • ディスプレイの解像度によっては極端に狭い幅となる可能性あり
  • %
    • 90%80% などを指定
    • ディスプレイ解像度によっては極端に広い幅となる可能性あり
  • rem
    • 40rem など 1 行に表示したいおおよその文字数を指定
    • 文字が基準なので本文幅はページ幅の大小に左右されず常に一定

本文幅の指定として px は現代でも多数ではなかろうか。しかし狭まる分にはレスポンシブレイアウトするとしても、広くなる場合は想定されていないのではなかろうか?高解像度ディスプレイで Web ブラウザーを広げたとき、幅 1024px ですら狭く感じられることがある。

% はあまり見かけない。しかし稀に 90%80% を指定しているサイトがあり、ページ幅が広いと行長が 100 文字を超えて文章を読むに厳しいことがある。

rem はどうか。手前味噌だが私のサイト akabeko.me では max-width: 45rem を指定している。他に rem 幅の例を見たことはないが、少なくとも私のサイトは高解像度ディスプレイの広いページ幅でみても、行長としては最大 45rem なので広くも狭くも感じない。

メンテナンス性についても % は論外として、px のように解像度を気にしなくて済むため、意外によい方法ではなかろうか?

余白

marginpadding の指定についても rem を推したい。

これらは font-size のサイズ単位とあわせることでレイアウト予想を立てやすくなる。font-sizepx なら pxrem なら rem へ統一するのが好ましい。

画像

画像のサイズ指定は種類による。図や写真などのラスター画像はピクセル数とアスペクト比、本文などのコンテンツ幅を加味して px% を指定するのがよいだろう。ラスター画像のサイズはピクセル単位となるため、整数倍 px 以外を指定すると綺麗に描画されない可能性もある。

UI 画像 (ボタンのアイコンなど) は文字と併置される機会も多いため、rem が好ましい。かつて rem がない時代は UI 画像と文字サイズを px 統一してレイアウトすることが多かった。ラスター画像の描画的にも px 指定は理にかなっている。現在も font-sizepx を採用する向きがあるのは、この慣習が一因かもしれない。

しかし現代は rem があり、UI 画像も SVG やアイコンフォントのようなベクター画像を選べる。ベクター画像はサイズを変更しても滑らかに描画されるため、rem 指定を採用するよい機会といえる。

おわりに

CSS のサイズ単位を rem 寄せにした場合の考察をまとめてみた。「ページの本文幅」で触れているように、私のサイトで導入してみたところ意外によく、React などの View 系ライブラリーで UI コンポーネントを実装する際もレイアウト予想を立てやすいので導入を検討している。

本記事は Vivliostyle の本なので、おわりに本記事の主題と関係する Vivliostyle の新機能を紹介する。

Vivliostyle は v2.17.0 で CSS 変数へ対応した。

この機能を利用することでサイズ単位を抽象化できるかもしれない。Web と印刷を @media で分岐するように、サイズ指定をすべて CSS 変数化して出力媒体にあったものへ切り替えるのはどうか。

レイアウト検証としても役立ちそうだ。

例えばサイズ単位が px 中心のページがあるとする。これを rem へ移行させる場合、まずはサイズ指定を役割や値の内容で命名した CSS 変数へ括りだす。それらをレイアウト検証しながら少しずつ rem へ置き換えてゆくのはどうか。検証で問題が起きたら CSS 変数の値を px へ戻せばよい。

このように可能性のある機能で、本書のように Vivliostyle を利用したコンテンツの作成が大きく改善しそうな予感がある。