🖥️

本当はややこしい px の話

2022/08/12に公開

ディスプレイと OS の解像度

「解像度」という言葉は厄介で、何の解像度かによって意味が変わります。

例えば、「ディスプレイの解像度」というと、一般的にはそのディスプレイに搭載されている「画素数」のことを指します。ディスプレイの代表的な解像度(画素数)には名前が付いており、例えばフルハイビジョン(FHD/2K)という解像度は、横が 1920 画素、縦が 1080 画素のディスプレイになります。

以下ではいろいろな解像度が登場しますので、ここでは混乱を避けるため、FHD などを指すディスプレイの解像度のことを「ディスプレイの画素数」と表現します。

ディスプレイの画素数が同じ場合、ディスプレイの物理的なサイズが小さいほど 1 画素のサイズも小さくなります。1 画素のサイズが小さくなるほど表示が細かくなるので、これが本来の「ディスプレイの解像度」と呼ぶべきものですね。

一方、Windows や Mac などの OS の画面設定にも「解像度」があります。こちらは dpi(dots per inch)あるいは ppi(pixels per inch)という単位で表現されます。これはその名のとおり、1 インチ(2.54 cm)の幅に何画素並んでいるかという単位です。しかし、こちらも本当の意味での解像度とは少し異なります(後述)。

ここでは、OS で設定される解像度を「画面解像度」と呼ぶことにします。また、画面解像度は画素(ピクセル)の話なので単位には ppi のほうを使います。画面解像度の意味でも dpi のほうがよく見かけるので、余計に混乱させてしまったらごめんなさい。

Windows の解像度は 96ppi、Mac の解像度は 72ppi ですが、この値は OS の設定であとから変更できます。Windows では、ディスプレイ設定メニューの「拡大/縮小」と「解像度」がそれです(アプローチが違うだけでいずれも OS の画面解像度を変化させる設定)。Mac での設定は、ディスプレイメニューの「サイズ調整」です。

さて、「1 インチの幅に何画素あるか」という定義からすれば、画面解像度が高いほど画素(pixel)が小さくなって繊細な表示になるはずです。しかし OS の画面解像度は、高くするほど画面に表示されているものが拡大されます。解像度が高いほど拡大する…というこの振る舞いは、一見、ppi の定義と逆であるようにも感じます。

これは、画面解像度においては、「1 インチ」という長さを固定と考えるのではなく、「1 画素」のサイズのほうを固定して考えるからです。つまり、1 インチが指す長さを(概念的に)変化させるのです。OS の設定を変えても目の前のディスプレイが物理的に大きくなったり小さくなったりするわけではありませんからね。

これが画面解像度のややこしいところで、OS の設定で「解像度」という言葉が使われなくなり、「拡大/縮小」や「サイズ調整」という表現に変わった理由だと思います(しらんけど)。画面解像度を上げると画面表示が拡大されて細かい部分まで見えるようになる=解像度が上がった…と理解しておきましょう。

プリンターと画像の解像度

さて、ウェブページをディスプレイで見ているかぎりは、閲覧者の使っているディスプレイの画素数や画素のサイズ、OS の画面解像度の設定がわからないので、CSS の「1 px」が指す実際の長さ(実寸)を気にしても仕方がないはずです(気にはなりますが)。Windows の既定の画面解像度が 96ppi だからといって、font-size: 96px; と指定しても、閲覧者のディスプレイ上でその文字が 1 インチ(2.54cm)で表示されている保障はありません。

ところが、ウェブページを印刷するときには、ウェブページに含まれる「画像」の解像度が問題になります。また、Apple の Retina ディスプレイの登場以来、「1 画素 = 1px」という図式も崩れてしまっており、ウェブ専門であっても CSS の px という単位とディスプレイの解像度の関係について理解しておく必要があります。

ここまで、「ディスプレイの画素数」と「OS の画面解像度」の話をしてきましたが、“解像度” はプリンターやスキャナーにも設定があります。前出の dpi(dots per inch)の「ドット」はプリンターの印刷の最小単位やスキャナーのスキャンの最小単位を意味します。プリンターやスキャナーの解像度は、1 インチの長さを固定して考える本来の解像度です。

一般に印刷物(紙)はディスプレイよりも近い距離で見るため、72dpi や 96dpi といった解像度で印刷すると粗が目立ちます。したがってプリンターでは、150〜400dpi で印刷するのが標準で、綺麗に見せたい写真などでは 600〜1200dpi で印刷することもあります。

ところで、スマートフォンやデジタルカメラで撮影した写真を PC で 100% 表示すると、写真の一部しか画面に入らないという経験をした人もいるかもしれません。1200 万画素のカメラで撮った画像は 4200 × 2900 画素くらいになりますが、 それを 96ppi(96 画素を 1 インチの幅)で表示すると実寸で約 110cm になるためです。50 インチ以上の大型ディスプレイで表示しないと写真が全部入り切りません。

一方、この横幅 4200 画素の写真を 1200dpi のプリンターで印刷すれば、その横幅は 9cm 弱になります。つまり、iPhone などの 1200 万画素のカメラというのは、撮った写真をディスプレイで見るためではなく、印刷して閲覧することを想定した画素数ということになります。

ディスプレイでしか写真を見ないなら、画質(写真の画素数)を落としたほうがストレージの節約になります。ウェブサイトもデータが小さいほうが読み込みが早いので、無意味に大きな画像データを使う必要はありません。Retina ディスプレイですら 254ppi 程度ですので(2022 年現在)、1200 万画素のカメラは宝の持ち腐れです。

印刷を想定した画像の px 数

ではまず、ウェブページの印刷を考えてみましょう。

フォントサイズについては 72ppi あるいは 96ppi で考えて構いません。フォントサイズの単位であるポイント(pt)の DTP 業界での定義が 72 ポイント/インチであるためか、DTP では 72ppi が一般的なようです。いずれにせよ、フォントは拡大しても粗くならないベクター形式で扱われるので、印刷時の解像度で問題になることは基本的にはありません。

フォントサイズで考えるべきなのは、他のフォントとの大きさのバランスです。ルート要素(html 要素)以外のフォントサイズは基本的に rem もしくは em の相対値で指定しておくのがよいでしょう。解像度が関係するのは、ルート要素のフォントサイズを何 px あるいは何 pt にするかを決めるときの話になります。

問題は画像です。JPEG や PNG などの代表的な画像フォーマットはラスター形式です。ラスター形式というのは各画素に色が入っているだけのものですから、拡大されると荒くなります。
前述のとおり、1200 万画素のカメラで撮った横幅 4200 画素の写真は、表示媒体が 96ppi だと 110cm にもなるのに、1200 dpi だと 9cm 弱になります。逆に、96ppi で 5cm 幅の写真をディスプレイで表示させるには 200px 幅の画像で十分ですが、それを 300dpi で印刷したらボケてしまいます。

ウェブページが印刷されることを想定するならば、プリンターの解像度を想定しておく必要があります。テキスト中心のウェブサイトだと、300〜400dpi を想定するのが一般的なようです。400dpi は 1 インチ 400px なので、5cm(約 2 インチ)の画像なら 800px となります。

埋め込んだ画像がどのくらいの実寸で印刷されるかも想定しておく必要があります。それは印刷時のレイアウトや用紙サイズにも依存します。CCS ファイルを読み込む link 要素の media 属性や CSS のメディアクエリー(@media)でそれらを指定することも可能です。

なお、ウェブページに配置する画像データそのもののサイズ(px 数)と、ディスプレイ上で表示する画像のサイズは別物です。横幅 800px の画像データを用意して CSS に width: 200px; と記述しておけば、ディスプレイ上では 200px で表示され、印刷時には 800px のデータが使用されます。
ディスプレイで表示するときにまで 800px の画像をダウンロードさせるのは…という場合は、ディスプレイ用と印刷用の画像を用意しておいて、img 要素の srcset 属性と sizes 属性で選択することができます(たぶん[1])。

ところで、プリンターの解像度と画像の印刷サイズから px 数を頭で計算するのは大変です。しかし、大抵の画像編集ソフトウェア(Photoshop など)には、開いている画像の解像度を設定する機能があります。画像編集ソフトウェアの解像度を 300dpi なり 400dpi にしておいた上で、画像の縦横の大きさを cm で指定すれば、裏で適切なピクセル数の画像サイズに設定してくれます。

高解像度ディスプレイへの対応

最後に、Retina ディスプレイをはじめとする高解像度ディスプレイとの関係について触れておきます。

元々、CSS の 1px というのはディスプレイの 1 画素を表していました。本記事のここまでの話もそれを前提にしてきました。ところが、ディスプレイ技術の発展により、1 インチに詰め込める画素数がどんどん上がり、Apple の Retina ディスプレイはそれまでのディスプレイの 4 倍の画素数(縦 2 倍・横 2 倍)を持つまでになりました。

画素数が増えても PC やスマートフォンのディスプレイサイズが大きくなるわけではありません。つまり、1 画素のサイズが小さくなって、従来の 2 倍の数の画素が 1 インチの幅に詰め込まれるようになりました。本来の意味でのディスプレイの解像度(ppi)が 2 倍になったということです。

こうなると、たとえば font-size: 32px; の文字の実寸が、Retina とそうではないディスプレイで面積にして 4 倍も違うのです。この問題に対して Apple はどうしたかというと、物理的な画素 4 個分を CSS の 1px としたのです。こうして、CSS の 1px は必ずしもディスプレイの 1 画素を表さなくなってしまいました。

それによって、「ピクセル」という言葉も二つの意味を持つようになります。ディスプレイの物理的なピクセル(画素)と、CSS の 1px が意味するピクセルです。日本語では「画素」と「ピクセル」でいいやん…となりそうですが、英語はどちらも pixel ですので呼び分けが必要です。
そこで、物理的な画素を「デバイスピクセル」と呼び、CSS の 1px を「CSS ピクセル」と呼ぶことになりました。

さて、このことについて、ウェブ作成者は何を気をつけなくてはならないでしょうか。

まず、フォントに関しては印刷と同様、72ppi もしくは 96ppi で考えて構いません。CSS ピクセルの 1px は、Retina ディスプレイでもそうでないディスプレイでもおおよそ同じ大きさで表示されます。Retina のほうは勝手に 1 CSS ピクセル を 4 デバイスピクセルで表示してくれるのです。フォントはベクター形式なので拡大しても粗くなりません。

しかし、画像に関してはそうはいきません。ラスター形式の画像データの各画素は、Retina ディスプレイのデバイスピクセルに対応します。つまり、100px × 100px の画像データを width:100px; height:100px; で表示させると、Retina ディスプレイではデバイスピクセルでいう 200px × 200px の領域に 100px × 100px の画像が引き伸ばされて表示されます。

Retina ディスプレイをはじめとする高解像度ディスプレイに対応するためには、印刷を想定していなくとも、画像データは 4 倍の大きさ(縦 2 倍・横 2 倍)で作成しておく必要があります。200px × 200px の画像データを width:100px; height:100px; で表示することによって Retina ディスプレイで画像が引き伸ばされなくなります。

とはいえ、低解像度(CSS ピクセルとデバイスピクセルが 1:1 対応する)ディスプレイで大きな画像を読み込ませるのは通信帯域の関係で無駄です。そこで、CSS ピクセルに対するデバイスピクセルの 倍数によって画像ファイルを選択する(img 要素の)srcset 属性 を使用することができます。

HTML
<img src="100x100.jpg"
     srcset="100x100.jpg,
             150x150.jpg 1.5x,
             200x200.jpg 2x">
CSS
img {
  width: 100px;
}

srcset 属性の値は、「画像ファイル名 倍率」のペアをコンマ区切りで列挙したものです。単位「x」で倍率を表現します。
このように記述しておけば、ブラウザーが CSS ピクセルに対するデバイスピクセルの倍率をみて、適切な画像をサーバーからブラウザーにダウンロード(表示)してくれます。

脚注
  1. sizes 属性にはメディアクエリーが指定できるのですが、ここで印刷(print)を指定した例が世の中に見当たらないので、もしかしたら印刷用に srcset と sizes(あるいは picture 要素)で画像を選択することはできないのかもしれません。 ↩︎

Discussion