高画素密度ディスプレイへの対策 第1回 仕組みと画像表示の最適化

精細で滑らかな表示を可能にする、高画素密度なディスプレイが普及してきていますが、これらのディスプレイでブラウザ上の画像を表示した場合にぼやけてしまう場合があります。この表示の仕組みを知り、対策を考えてみましょう。

発行

著者 森 大典 フロントエンド・エンジニア
高画素密度ディスプレイへの対策 シリーズの記事一覧

はじめに

昨今ではスマートフォンやアップルのRetinaディスプレイをはじめ、画面を大型化せずとも精細で滑らかな表示を可能にする、高画素密度なディスプレイが普及しています。

JavaScriptによる実装を行う際、これらディスプレイにおける表示の鮮明度という観点で、なにかコードを工夫するという場面はあまりないのではないでしょうか? 一方で、デザイナーやマークアップ・エンジニアにおいては、この工夫が必要になる場面が度々あります。

それは画像をぼやけさせずに鮮明に表示させるという工夫です。高画素密度ディスプレイはきれいな画質で表示できる一方、なんの施策もせずブラウザで画像を表示した場合、ぼやけた表示になるという問題があるためです。

しかし、JavaScriptの実装においてもCanvasを表示する場合、あるいはCanvasから画像を生成する場合は、上記のぼやけ問題の対策が必要になります。

本稿ではまず、高画素密度ディスプレイの仕組みと併せ、JPGやPNGなどのラスター画像の表示をぼやけさせない方法を紹介します。さらに、Canvasの実装における上記の対策についてを、次回解説します。

高画素密度ディスプレイとは

まずは高画素密度ディスプレイについて、おさらいしておきましょう。一番よく知られている高画素密度ディスプレイは、iPhoneやMacBookに採用されているRetinaディスプレイかもしれません。アップルは製品に搭載されている高画素密度ディスプレイのことを「Retinaディスプレイ」と呼んでおり、アップルのサイトでRetinaディスプレイを次のように紹介しています。

Retinaディスプレイのピクセル密度はとても高く、通常画面を見るときの距離では、人間の目で一つ一つのピクセルを見分けることはできません。そのため、コンテンツが色鮮やかに細部まで再現され、画面の美しさに圧倒されます。
(・・・省略・・・)
2019年に発売された16インチモデルのMacBook Pro。標準解像度は3072×1920、1インチ当たりのピクセル数(ppi)は226です。数百万色に対応しています。

ディスプレイにおける解像度は、画面上にドットとして配置されたピクセル(画素)の総数を、「横×縦」の形式で表現します。上記例では「標準解像度は3072×1920」という記述がそれにあたり、この数値が大きいほど高解像度であると言えます。

また、このピクセル数がディスプレイサイズに対し、多ければ多いほど「画素密度」が高い高画素密度な状態と言え、より精細な表示が可能になります。上記のMacBook Proの例では、「16インチモデル」の16がディスプレイサイズにあたり、これはディスプレイの対角線の長さを示しています。

そして、表示の精細さを示すスペックの単位にはppi(pixel par inch)が用いられ、「1インチ当たりのピクセル数(ppi)は226」が、それにあたります。

この文章のとおり、ppiとは1インチ(2.54cm)当たりに配置されるピクセル数のことで、ディスプレイの表示領域のサイズを変えずに、画素と画素の距離(画素ピッチ)を縮めることでppiは増し、より高精細な表示になります。

高画素密度ディスプレイという名称

「高画素密度ディスプレイ」は、特に規格として定められているわけではありません。そのため、同じようなディスプレイでも、「高解像度ディスプレイ」「高精細ディスプレイ」「HiDPIディスプレイ」など、さまざまな呼び方をされていますが、本シリーズでは高画素密度ディスプレイと呼ぶことにします。

ピクセルのスケーリング

ディスプレイのサイズに対し、ピクセル数が多ければ多いほど精細な表示が可能になると述べましたが、これはスマートフォンのように、画面の大きさに物理的な制限があるデバイスでもメリットと呼べるものでしょうか?

iPhoneを例に取ると、RetinaディスプレイはiPhone 4で初めて搭載され、物理的な画面の大きさは前機種のiPhone 3の320×480のまま、ピクセル数のみが倍の640×960になりました。単純に考えるとピクセル密度が倍になったことで、見た目上のサイズは従来の1/2となり小さくて見づらいものになりそうです。しかし、実際には従来と同じ大きさのまま、より精細に表示されます。

これはOS側のスケーリング技術で、従来「1px × 1px」で表示させていた情報を、「2px × 2px」に引き伸ばして表示しているためです。

このスケーリング技術により、1ピクセルで表現していた情報を4ピクセルで表現できるようになり、精細かつ視認性の高い表示を実現しているというわけです。

このように、複数のピクセルで構成された仮想的なピクセルのことを、仮想ピクセルまたはCSSピクセルと呼び、その仮想ピクセルを表示するために、実際に使用されている物理的なピクセルのことを、物理ピクセルまたはデバイスピクセルと呼びます。

また、上記のように1ピクセルをn倍に引き伸ばす表示において、この倍数のことをデバイスピクセル比(device pixel ratio)と呼びます(DPRと省略して表記される場合もあります)。

デバイスピクセル比は、物理ピクセル ÷ 仮想ピクセルの計算式で求められます。これらのピクセル数は正方形の面積ではなく、一辺の1インチあたりのピクセル数で考えるため、上記のiPhone 4の例では、「2px/1px=2」という計算式になり、デバイスピクセル比は「2」となります。

画像密度の低いディスプレイではたいていデバイスピクセル比は1になりますが、画素密度の高いディスプレイでも設定によって、デバイスピクセル比を1に変更できるものもあります。このように物理ピクセルと仮想ピクセルが1:1の関係にある状態を、ドットバイドット(dot by dot)と呼びます。

デバイスピクセル比のバリエーション

本文で例として挙げたiPhone 4のデバイスピクセル比は2ですが、デバイスピクセル比が3や4のデバイスも存在します。iPhoneのデバイスピクセル比と画面解像度の関係は、次のサイトでわかりやすく図解されています。

画像がぼやける理由

ここまで高画素密度ディスプレイの仕組みについて見てきましたが、その表示性能においては、精細かつ視認性の高い表示を実現するというメリットしか感じなかったのではないでしょうか。

しかし、それをブラウザ上の画像で実現するには、本稿の冒頭で述べたようにぼやけさせない工夫が必要になります。なぜ画像の場合は、ぼやけた表示になってしまうのでしょうか?

画像もディスプレイと同様に、1ピクセル単位に表示する色情報を持っています。前述のように、1ピクセルをn倍に引き伸ばして表示した状態では、ブラウザはこの1ピクセル相当の色情報を、n倍のピクセル数に引き伸ばして表示することになります。

Retinaディスプレイ対応のMacBookなど高画素密度ディスプレイをお持ちでしたら、試しにGoogleのトップページに表示されるロゴの「G」の字をスクリーンショットで撮り、その画像をブラウザにドロップしてみてください*。次のように縦横2倍のサイズでぼやけて表示されることでしょう。

*注:スクリーンショットとブラウザへのドロップ

macOSの場合は、command+shift+4キーで選択範囲のスクリーンショットが撮れ、画像はデスクトップに保存されます。

これはスクリーンショットを撮った際に、論理ピクセルの「1px × 1px」中に詰められた「2px × 2px」分の物理ピクセルの情報が、画像そのものの大きさとして画像ファイルに反映されたためです。

操作者側の視点としては、たとえば300ピクセル分の範囲を指定しているつもりでも、そこには600ピクセル分の物理ピクセルが存在しており、これらの情報は画像ファイルに記録されます。

さらにブラウザは、この画像の1ピクセル分の情報を、4ピクセルに引き伸ばして表示しようとするため、ぼやけた表示になるというわけです。

画像のぼやけを解消する方法

前節のぼやけ表示問題に対し「デザイナーやマークアップ・エンジニアは、画像をぼやけさせない工夫をする」と、冒頭で述べました。業務で携わってる方はすでにご存知かもしれませんが、こちらについても紹介しておきます。

この工夫とは、画像が引き伸ばされて表示されることを前提に、あらかじめ2〜3倍程度の大きさで画像を作成しておき、CSSで等倍の表示に戻すという処置のことです。たとえば、ある画像を背景画像として表示しようとしたとき、実際に表示したいサイズが「1000px × 600px」であった場合、「2000px × 1200px」の大きさで画像を作成し、次のようなCSSで等倍に戻します。

css

.header {
  background-image: url("...");
  background-size: 1000px 600px;
  ...省略
}

この処置により、本来1ピクセルで表現したかった画像の4ピクセル分の情報が、論理ピクセル上の1ピクセルで表現されるようになり、引き伸ばされることなくぼやけが解消された表示になります。

画像にSVG形式を使う

ここではJPGやPNGのようなラスター画像を想定していますが、表示したい画像の内容によっては、画像にSVGを利用することも可能です。SVGはベクター形式のため、引き伸ばされてもぼやけません。SVGについては、次のシリーズを参考にしてください。

ディスプレイの精細度に応じた画像の出し分け

前節の「大きく画像を作りCSSで縮小する」という処置は、あくまで高画素密度ディスプレイの利用者向けの対策です。

ドットバイドットのディスプレイでは、4ピクセル分の情報をCSSで1ピクセルに縮小したところで、1ピクセルの物理ピクセルでしか表示できません。実際の表示に反映されない無駄に大きいサイズの画像を読み込んでいることになり、パフォーマンスの観点からも非効率な処理といえるでしょう。

画像の容量が小さい場合は、さほど気にする必要はないかもしれませんが、大きな画像を扱う場合は、サイズの異なる2種類の画像を作っておき、ディスプレイの精細度に応じて画像を出し分けるとよいでしょう。

具体的には、resolution(解像度)というメディア特性を用いたメディアクエリで、利用する画像を出し分けることができます。前節の例で用いた画像であれば、次のような記述になります。

/* 基本、等倍サイズの画像を表示する */
.header {
  background-image: url(...); /* 1000px 600pxの画像 */
  ...省略
}

/* デバイスピクセル比が2以上の場合は、倍サイズの画像を表示する */
@media screen and (min-resolution: 2dppx) {
  .header {
    background-image: url(...); /* 2000px 1200pxの画像 */
    background-size: 1000px 600px;
    ...省略
  }
}

resolutionメディア特性の使い方については、次の記事でも紹介しているので参考にしてみてください。

また、img要素のsrcset属性を使ってピクセル密度に応じた画像を出すことも可能です。img要素のsrcset属性については次の記事で紹介しています。

ここまでのまとめ

ディスプレイの仕様の読み方と併せ、視認性を維持したまま高精細な表示をする、高画素密度ディスプレイの仕組みについて解説しました。

また、高画素密度ディスプレイで画像の表示がぼやける理由と、その対策についても解説しましたが、次回は、Canvas利用時における最適化の方法について紹介します。