CSSの単位px、em、remはどれをどこで使用するのがよいか、ピクセルとアクセシビリティにおける意外な真相
Post on:2022年6月7日
CSSの単位px
、em
、rem
は、どれをどこで使用するのがよいか。
font-size
の値にはどの単位を使用していますか? ほかにもメディアクエリを定義する時、マージンを定義する時、width
やheight
を定義する時、使用する単位はアクセシビリティに配慮する必要があります。
The Surprising Truth About Pixels and Accessibility
by Josh W. Comeau
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- はじめに
- CSSでpxとemとemの各単位がどのように機能するか
- アクセシビリティに関する考慮事項
- どの単位をどこで使用すればよいのか
- どの単位がベストなのかが明らかでない場合
- 簡単にできる小技とメンタルモデル
- ボーナス: remを使用すると便利なテクニック
はじめに
CSSの単位でpx
とrem
(em
)のどれを使うべきですか!?
これはよくある質問で、この言葉の裏には不安や懸念が詰まっています 😅
世の中には相反する意見がたくさんあり、それらを鵜呑みしてしまうことがあります。たとえば、アクセシビリティのためにはrem
の方が良い。または、現在では問題が修正されているのでpx
で問題ないと聞いたことがあるかもしれません。
実は、アクセシブルなものを作りたいのであれば、px
とrem
(em
)の両方を使用する必要があります。どれか一つだけという答えはありません。rem
の方がアクセシブルな状況もありますし、px
の方がアクセシブルな状況もあります。
この記事では、以下について解説します。
px
、em
,rem
の各単位がどのように機能するかを簡単に説明し、すべてが同じ強固な基盤の上に構築されていることを確認します。- アクセシビリティに関する考慮事項、および各単位が考慮事項にどのような影響を与えるかについて説明します。
- どのようなシナリオでも、どの単位を使用するかを決定するのに役立つメンタルモデルを構築します。
- 単位を変換する際に役立つヒントやテクニックも共有します。
この記事を読み終えた後は、どのようなシナリオでどの単位を使用するべきか、判断できるようになるはずです 😄
CSSでpxとemとremの各単位がどのように機能するか
CSSでpx
、em
、rem
の各単位がどのように機能するかを説明します。
px単位がどのように機能するか
CSSでサイズを設定する時に使用する最も一般的な単位は、ピクセルの略称であるpx
単位です。
1 2 3 4 5 |
.box { width: 1000px; margin-top: 32px; padding: 8px; } |
1px
とは、コンピュータのモニターやスマホのスクリーンにおいて1つのドットに相当します。CSSで最も抽象度の低い単位で、最も具体的な単位です。そのため、直感的に理解することができます。
ハードウェアとソフトウェアにおけるピクセル
実は、px
という単位はちょっとウソです。実際には、ハードウェアのピクセルに正確にマッピングされるわけではありません。
顕微鏡で最新のディスプレイを見てみると、R/G/Bの鮮明な矩形で構成されていないことが分かります。下記は、Apple WatchとApple iPhoneのディスプレイの拡大写真です。
ソース: Apple Watch, iPhone
メーカーがピクセルグリッドに工夫を凝らす以前から、画面の物理的なピクセルとCSSで記述するソフトウェアのピクセルは区別されていました。ユーザーがスクリーンの解像度を変更したりズームインしたりするたびに、ソフトウェアピクセルがハードウェアピクセルにどのようにマッピングされるかが変化します。
とはいえ、px
という単位がハードウェアでどう扱われているかは、問題ではありません。px
という単位は、わたし達が使用できる最も具体的な単位です!
em単位がどのように機能するか
em
という単位は面白い存在です。これは相対的な単位で、ベースとなるフォントサイズに基づいてサイズが計算されます。
font-size
の値を変更すると、em
で定義したサイズも変更される
基本的に、em
単位は比率です。
上記のようにパラグラフの下マージンが1.5em
の場合、フォントサイズの1.5倍であることを意味します。このようにある値を別の値に「固定」して、比例して拡大縮小することができます。
たとえば下記はばかげた例ですが、単語ごとにem
値が定義されており、パラグラフがだんだん小さくなって消えていくような印象を与えています。このパラグラフのフォントサイズを大きくすると、すべての単語が「拡大」されます。
font-size
の値を変更すると、em
で定義したサイズも変更される
注: em
の仕組みを理解しやすくするために、ここではピクセルベースのフォントサイズを使用しました。しかし、これはよくない例です。実際の実装には使用しないでください。
rem単位がどのように機能するか
今となっては古い話ですが、かつてCSSにrem
という単位が追加された輝かしい時代がありました。
rem
単位は、em
単位によくあるイライラする問題、つまり計算が重複されてしまうという問題があるために導入されました。
たとえば、下記のCSSをご覧ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<style> main { font-size: 1.125em; } article { font-size: 0.9em; } p.intro { font-size: 1.25em; } </style> <main> <article> <p class="intro"> What size is this text? </p> </article> </main> |
.intro
のフォントは、px
単位でどのくらいのサイズになると思いますか?
その答えを知るには、比率を乗算する必要があります。ルートのフォントサイズはデフォルトで16px
なので、16 × 1.125 × 0.9 × 1.25という式になります。
答えは、20.25px
です。
なぜこうなったのでしょう?
その理由は、フォントサイズは継承可能だからです。.intro
のフォントは1.25em
で、これは「現在のフォントサイズの1.25倍」を意味します。では現在のフォントサイズとはいくつでしょうか? この値は親から継承され、0.9em
です。つまり、親の1.25倍、その親の0.9倍、さらにその親の1.125倍になります。
基本的にはツリー内のすべてのem
値が「固定」値(ピクセル使用)に達するか、ツリーの最上部に到達するまで、乗算します。これは非常に厄介です 😬
この問題を解決するために、CSS言語の設計者はrem
という単位を作成しました。rem
は「Root EM」の略です。
rem
単位はem
単位と似ていますが、ルートノードである<html>
要素のフォントサイズの倍数である点が異なります。継承されたフォントサイズは無視され、常にトップレベルのノードに基づいて計算されます。
ドキュメントのデフォルトのフォントサイズは16pxなので、1rem
は16pxという「ネイティブ」値であることを意味します。わたし達はルートノードのfont-size
を変更することで、1rem
の値を再定義できます。
rem
単位は、常にトップレベルのノードに基づいて計算される
確かにわたし達はルートノードのfont-size
を変更できますが、変更すべきではありません。その理由を理解するために、アクセシビリティについて説明する必要があります。
アクセシビリティに関する考慮事項
px
、em
、rem
のどれを使用すればよいのか、アクセシビリティに関する考慮事項は視覚です。視力の弱い人でもWebサイトやアプリのテキストやパラグラフを快適に読めるようにしたいと考えます。
視覚に障害がある人が文字を大きくするには、いくつかの方法があります。
1つの方法は、ブラウザのズーム機能です。MacOSでは⌘
++
、Windowsではctrl
++
が標準的なキーボードショートカットです。
ブラウザのズーム機能
この記事では、この方法をズームと呼ぶことにします。
WCAGではアクセシビリティを確保するために、Webサイトは200%ズームで使用できるようにすべきであると記述されています。しかし、アクセシビリティを支持する人たちからはこの数値はあくまで最低限であり、視覚障害を持つ多くの人はこれよりもずっと高い倍率で表示することが多いという話を聞いたことがあります。
もう1つの方法はあまり知られていないかもしれません。ブラウザの設定で、デフォルトのフォントサイズを大きくすることもできます。
ブラウザの設定で、フォントサイズを大きくする
この記事では、この方法をスケーリングと呼ぶことにします。
フォントのスケーリングは「ベースライン」フォントサイズ、つまりすべての相対的な単位が基準となるデフォルトのフォントサイズ (rem, em, %) を再定義することで機能します。
上記で、1rem
は16pxに等しいと言ったのを覚えていますか?
これはユーザーがデフォルトのフォントサイズを変更していない場合にのみ当てはまります。もしユーザーがデフォルトのフォントサイズを32pxに変更すると、1rem
は16pxではなく32pxになります。
つまり、フォントのスケーリングとは、1rem
の定義を変更することと考えることができます。
ここで、最初のアクセシビリティの問題にぶつかります。ページ上のフォントサイズにピクセル値を使用すると、ユーザーが選択したデフォルトのフォントサイズに影響されなくなります。
font-size
をpx
で定義すると、デフォルトのフォントサイズに影響されなくなる
これが、テキストのサイズにrem
やem
といった相対単位を使用すべき理由です。これにより、ユーザーはニーズに合わせてその値を再定義できます。
今日、ブラウザのズーム機能のおかげで、以前ほど暗いイメージはありません。
ユーザーがズーム機能を使用すると、すべてが拡大されます。ピクセルも含めすべての単位に倍率が適用され、ビューポート単位(vw
やvh
など)を除くすべてに影響します。これは、すべての主要なブラウザで、もう何年も続いていることです。
では、ユーザーがいつでもズームしてフォントサイズを大きくできるのであれば、フォントのスケーリングにも対応する必要があるのでしょうか? 1つのオプションで十分ではありませんか?
問題は、ズーム機能はサイト単位で使用されることを想定していることです。新しいサイトにアクセスするたびに、手動でズーム機能を設定しなければならないかもしれません。それよりも、快適に読める大きさのフォントサイズを設定し、そのサイズを統一した方がよいと思いませんか?
(誰もが簡単にキーボードショートカットを操作できるわけではないということを頭に入れておいてください)。私は数年前に神経を痛めてしまい、キーボードを使用できなくなりました。その時は口述筆記とアイトラッキングを使用して、操作しました。ある日突然に、キー操作の一つひとつに負担がかかるようになったのです!
一般論として、わたし達はユーザーにできるだけ多くのコントロールを与えるべきで、ユーザーの設定を無効にしたり、機能しないようにしたりしてはいけません。そのため、タイポグラフィにはrem
のような相対単位を使用することが非常に重要です。
どの単位をどこで使用すればよいのか
ここで、あなたは考えるかもしれません。
rem
単位がズームとスケーリングの両方で尊重されるのであれば、常にrem
単位を使用するべきではないか、と。px
単位はもう使用しなくてよいのでは?
では、rem
単位をパディングに使用するとどうなるか見てみましょう。
ラッパーのpadding
にrem
単位を使用するとどうなるか
rem
の値はユーザーのデフォルトのフォントサイズに比例することを覚えていますか。これはタイポグラフィに関しては良いことですが、他のものに関しても良いことなのでしょうか? すべてをフォントサイズに合わせて拡大縮小する必要があるのでしょうか?
テキストのサイズに関しては、暗黙のトレードオフが存在します。テキストが大きくなればなるほど、1行に収まる文字数は少なくなります。ユーザーがテキストを250%に拡大すると、1行の文字数はかなり少しです。
水平方向のパディングにrem
単位を使用すると、この負の副作用が増幅されます。使用可能なスペースが少なくなり、1行に収まる文字数はさらに少なくなります。
これはよくないこと
です。なぜなら段落が
このようになります。
1行に数語しかないような
段落は読みにくいです。
同様に、ボーダーの幅はどうでしょうか。ユーザーが好みのテキストサイズを拡大すると、ボーダーが太くなるのはあまり意味がありません。
このように、単位は戦略的に使い分けたいものです。px
とrem
のどちらを選ぶか、次のような質問を自分自身に投げかけてみてください。
「ユーザーがブラウザのデフォルトのフォントサイズを大きくすると、その値を拡大する必要がありますか?」
この質問文は私が使用しているメンタルモデルです。デフォルトのフォントサイズで値が増加する場合は、rem
を使用します。そうでなければ、px
を使用します。
とはいえ、この質問に対する答えは必ずしも明白ではありません。
いくつか実際の例を見てみましょう。
メディアクエリの定義で使用する単位
メディアクエリの値には、px
とrem
のどちらを使用すべきでしょうか?
1 2 3 4 5 6 |
/* Should we do this: */ @media (min-width: 800px) { } /* …Or this: */ @media (min-width: 50rem) { } |
まずは、px
とrem
の違いを明らかにします。
ユーザーがデフォルトのテキストサイズを標準の2倍の32pxに設定したとします。つまり、50rem
は800pxではなく、1600pxになります。
1600pxになってしまうと、ユーザーはスクリーンサイズが少なくとも1600pxになるまでスマホ向けのレイアウトを見ることになります。ラップトップを使用している場合は、デスクトップ向けではなく、スマホ向けのレイアウトが表示される可能性が非常に高くなります。
最初、これは悪いことのように思えました。実際にはスマホではないのに、なぜスマホ向けレイアウトを表示しなければならないのでしょうか。
しかし、メディアクエリにrem
を使用することは、通常、望ましいことであることに気付きました。
実際の例を見てみましょう。
左側にナビゲーションがあり、右側にコンテンツが表示されています。
左側にナビゲーション、右側にコンテンツ
小さいスクリーンではコンテンツのスペースを最大限に確保したいので、ナビゲーションはトグルになります。
スマホ向けでは、ナビゲーションがトグルに
ユーザーがデフォルトのフォントサイズを32pxにしてアクセスしたとき、メディアクエリにpx
とrem
にした場合にそれぞれどうなるか見てましょう。
メディアクエリにpx
とrem
にした場合
テキストのサイズを大きくすると、左側のナビゲーションの幅がどんどん広くなります(rem
ベースの幅を使用しているため)。その結果、メインのコンテンツエリアはどんどん小さくなります。
しかし、rem
ベースのメディアクエリを使用すると、スマホ向けレイアウトに戻ります。その結果、コンテンツはより読みやすくなり、エクスペリエンスも大幅に向上します。
わたし達はスマホ・タブレット・デスクトップの観点からメディアクエリを考えることに慣れていますが、利用可能なスペースの観点から考える方がより有効だと考えます。
スマホユーザーはデスクトップユーザーよりも利用可能なスペースが少ないため、そのスペースに最適化されたレイアウトをデザインします。同様に、デフォルトのフォントサイズを大きくすると、利用可能なスペースが狭くなるため、同じように最適化する必要があります。
垂直のマージンの定義で使用する単位
続いて、垂直方向のマージンについて考察してみます。
垂直のマージンにpx
とrem
にした場合
英語のような横書きの言語を想定した場合、テキストの垂直方向のマージンは通常、読みやすさを向上させるために使用されます。パラグラフ間にスペースを追加することで、パラグラフがどこで終わり、どこから始まるのかが分かるようになります。
このスペースは文章を書く上で「機能的」な目的を持っており、美的に使用しているわけではありません。
このような理由により、スペースをユーザーが選択したルートフォントサイズに合わせて拡大縮小することは、理にかなっていると思います。また、見出しとパラグラフのスペースに関しては、em
単位が特にうまく機能します。
widthとheightの定義で使用する単位
最後に、幅が固定されたボタンを見てましょう。
ボタンの幅にpx
とrem
にした場合
ボタンのfont-size
はrem
で定義する必要があることは上記の通りですが、width
はどうでしょうか。
ここには興味深いトレードオフがあります。
width
を240px
に設定すると、ボタンはフォントサイズに合わせて大きくならず、行の折り返しとボタンの高さが高くなります。width
を15rem
に設定すると、フォントサイズに合わせてボタンも大きくなります。
px
とrem
、どちらがよいと思いますか?
答えは、状況に依存されます。
ほとんどの場合、rem
を使用するのがより理にかなっていると思います。これは、ボタンの比率と美観を維持するためです。また、ボタンのラベルが特に長い場合、オーバーフローのリスクも軽減されます。
しかし、場合によっては、px
の方が良いこともあります。たとえば、非常に特殊なレイアウトを考えていて、水平方向のスペースよりも垂直方向のスペースの方が豊富な場合です。
注意事項
一般的に、固定の幅と高さを設定するときは、細心の注意を払う必要があります。上記の例ではwidth: 15rem;
を設定すると、多くの場合、スマホでレイアウトが崩れます。ユーザーがデフォルトのフォントサイズを大きくすると、コンテナに対して大きすぎる値が生成される可能性があるからです。
その場合、最大値を100%
にすることでこの問題を回避できます。
1 2 3 |
.button { max-width: 100%; } |
同様に、高さに関しても、height
の代わりにmin-height
を使用したいことがよくあります。それにより、コンテナの高さを必要なだけ大きくして、子要素を収めることができます。ユーザーがフォントサイズを大きくすると、テキストがより多くの行に折り返されるため、重要になります。
どの単位がベストなのかが明らかでない場合
ユーザーのデフォルトのフォントサイズに合わせて値をスケーリングする場合は、rem
単位を使用する必要があることを学びました。
しかし、ボタンの幅のように、どの単位がベストなのかが明らかでない場合はどうしたらよいと思いますか?
そのような場合、一番良いのは実際にテストすることです。ブラウザのデフォルトのフォントサイズを32pxまたは48pxに変更し、どのようになるか確認してください。px
単位で試してみて、次にrem
単位で試してみてください。どの単位が最高のユーザーエクスペリエンスを、最も読みやすいコンテンツを生み出すのか実際に確認するのが一番です。
こういった経験を重ね、特定の状況で何をすべきかを自分の目で確かめることで、強い直感を養うことができます。
ブラウザのデフォルトのフォントサイズを変更する方法がわからない?
各ブラウザのマニュアルは下記の通りです。
お使いのブラウザがリストにない場合は、Googleで検索すると表示されます。
簡単にできる小技とメンタルモデル
私は学習に関してある哲学を持っています。それは、暗記や練習に頼るよりも直感を養う方が良い、ということです。
この記事では、「Xにはpx
を使用し、Yにはrem
を使用する」というルールの簡単なリストかもしれません。しかし、それは実際にどれほど役立つでしょうか?
現実の世界は厄介で複雑です。どんなルールでも、考えられるすべてのシナリオをカバーできるほど包括的ではありません。15年間CSSを書き続けている私でさえ、常に新しいレイアウトの課題に直面します。
直感を働かせることに集中すれば、ルールを覚える必要はありません。正しい答えを導き出すために、自分のメンタルモデルに頼ることができます。その方がずっと実用的です。
しかし、多くの人は「簡単にできるテクニック」から学びます。CSSの中央揃え、Flexboxのちょっとした小技、見出しのスニペットなど、TwitterでCSSのコードを見つけたりします。しかし、そのスニペットが期待通りに動かず、その理由がわからないという問題にぶつかることがあります。
多くのデベロッパーがCSSを書くのを嫌がるのは、これが理由だと思います。CSSのメンタルモデルがバラバラで、そのせいでCSSが脆弱で、予測不可能で、まるで崩壊寸前のトランプの家のように感じられます。
直感を養うこと、CSSが実際にどのように機能するかを学ぶことにフォーカスをあてると、この言語は使用するのが楽しくなります。以前はCSSにイライラを感じていましたが、今ではWeb開発で最も好きな部分の1つです。CSSを書くのが大好きです。
この喜びを分かち合いたいと思い、仕事を辞め、1年かけて自分のペースで学べる総合的なオンラインコースを作りました。その名は「CSS for JavaScript Developers」です。
CSSがどのように機能するかを理解したい人に最適です 💖
ボーナス: remを使用すると便利なテクニック
ここまで見てきたように、最良の結果を得るためには、rem
単位を使用する必要がある場合がたくさんあります。
しかし残念ながら、rem
単位を扱うとイライラすることがあります。頭の中で変換計算をするのは簡単ではありません。また、小数点以下の数字も多いです。
- 14px → 0.875rem
- 15px → 0.9375rem
- 16px → 1rem
- 17px → 1.0625rem
- 18px → 1.125rem
- 19px → 1.1875rem
- 20px → 1.25rem
- 21px → 1.3125rem
このリストを暗記する前に、rem
で作業するエクスペリエンスを改善するためにできることをいくつか紹介します。
ルートフォントサイズを62.5%にするテクニック
まずは、ネット上でよく共有されているテクニックから始めましょう。
1 2 3 4 5 6 7 8 9 10 11 |
html { font-size: 62.5%; } p { /* Equivalent to 18px */ font-size: 1.8rem; } h3 { /* Equivalent to 21px */ font-size: 2.1rem; } |
このアイデアは、ルートフォントサイズを62.5%;
にして、rem
単位が16pxではなく10pxに等しくなるようにするものです。
10pxになると、計算が非常に簡単になるため、多くの人に好まれています。18pxに相当するrem
値をもとめるには、18を16で割る(1.125rem
)のではなく、小数点を移動する(1.8rem)だけです。しかし、正直なところ、このアプローチはお勧めしません。いくつか理由があります。
まず、サードパーティとの互換性が損なわれる可能性があります。もし、rem
ベースのフォントサイズを使用するライブラリを使用する場合、それらのテキストは、本来あるべきサイズよりも37.5%小さくなってしまいます。同様に、エンドユーザーが持っているブラウザの拡張機能も壊れる可能性があります。
Webでは、1rem
が読み取り可能なテキストを作成するという基本的な前提があります。その前提を崩したくはありません。
また、この方法には移行に関する大きな課題もあります。この方法を「段階的に採用する」合理的な方法はありません。アプリ全体でrem
単位を使用するすべての宣言を更新する必要があります。さらに、その手間をかける価値があることを、チーム全員に納得してもらう必要があります。ロジカルに考えても、ほとんどのチームにとって現実的とは思えません。
それでは、いくつかの代替案を見てみましょう。
代替案: calc()関数を使用する
CSSのcalc()
関数は、px
値をrem
値に変換できます。
参考: CSSのcalc()関数の使い方のまとめ -レイアウト・要素の配置・フォントサイズの定義など
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
p { /* Produces 1.125rem. Equivalent to 18px */ font-size: calc(18rem / 16); } h3 { /* Produces 1.3125rem. Equivalent to 21px */ font-size: calc(21rem / 16); } h2 { /* Produces 1.5rem. Equivalent to 24px */ font-size: calc(24rem / 16); } h1 { /* Produces 2rem. Equivalent to 32px */ font-size: calc(32rem / 16); } |
これの元となるアイデアは、@cahnoryです。CSS宣言の中で計算をすれば、calc()
関数が正しい答えを返してくれます。
これは実行可能な方法ですが、ちょっとだけ手間がかかります。また、rem
値を使用するたびに入力する必要があります。
もう1つの代替案を見てみましょう。
代替案: CSS変数を使用する
これは私のお気に入りの方法です。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
html { --14px: 0.875rem; --15px: 0.9375rem; --16px: 1rem; --17px: 1.0625rem; --18px: 1.125rem; --19px: 1.1875rem; --20px: 1.25rem; --21px: 1.3125rem; } h1 { font-size: var(--21px); } |
すべての計算を一度だけ行い、CSS変数を使用してそれらを保存しておきます。必要なときにpx
値を入力するのと同じくらい簡単で、完全にアクセシブルです ✨
CSS変数をこのように数字で始めるのは少し型破りですが、これは仕様に準拠しており、すべての主要なブラウザで動作します。
複数のスケールが必要なデザインシステムを使用している場合、同じ方法を使用できます。
1 2 3 4 5 6 7 8 9 10 |
html { --font-size-xs: 0.75rem; --font-size-sm: 0.875rem; --font-size-md: 1rem; --font-size-lg: 1.125rem; --font-size-xl: 1.3125rem; --font-size-2xl: 1.5rem; --font-size-3xl: 2.652rem; --font-size-4xl: 4rem; } |
CSS変数は非常に便利です。
参考: CSS変数(カスタムプロパティ)の優れた使い方、コンポーネントのバリエーションを実装するのに役立つ
CSS for JavaScript DevelopersでもCSS変数を使用してできることをたくさん解説しています。
最終的に、ここで紹介した方法はすべて機能します。好みがあると思いますが、重要なのはエンドユーザーのエクスペリエンスです。ページ上のすべてのテキストのサイズを調整できるのであれば、あなたは正しいことをしていることになります 💯
sponsors