TL;DR
Retinaや高DPIをサポートするディスプレイでラスタ画像がぼやける理由は、画像が引き伸ばされる際に、スムージング(アンチエイリアス)が働くから。
ピクセルの2つ意味
普段使っている「ピクセル」という言葉には、2つの意味があります。
デバイスピクセル(物理ピクセル)
PCやスマートフォンといったデバイスが待つ実際のピクセル数を指します。例えばiPhone8には、750px × 1334px のRetinaディスプレイが搭載されています。
CSSピクセル(論理ピクセル)
デバイスピクセルが実際のピクセル数を表すのに対し、こちらは見かけ上のピクセル数を表します。CSSピクセルは文字通り、CSSの単位として使用されています。従来のデバイスでは「デバイスピクセル=CSSピクセル」であったため、実際のピクセル数と見かけ上のピクセルは同じでした。
Retinaのしくみ
iPhone8のCSSピクセルは375px × 667pxで、デバイスピクセルと比べて縦横ともに半分ずつのサイズとなっています。言い換えると、CSSピクセルの1pxを表現するために、縦横それぞれ2倍のデバイスピクセルを使用している、ということになります。このような、デバイスピクセルとCSSピクセルの比を「デバイスピクセル比」と呼び、iPhone8の場合では「デバイスピクセル比が2である」と表現します。
当然、デバイスが持つ本来の解像度よりも表示領域は狭くなりますが、より高精細に描画することができます。ある意味では、Retinaは「CSSピクセルをより多くのデバイスピクセルで描画するための技術」が詰まったディスプレイ、と捉えることもできるでしょう。
ラスタ画像がぼやける理由
もともと1pxだったものを縦横2倍に引き伸ばして描画するのです。フォントなどのベクタ形式のデータは拡大しても問題なさそうですが、ラスタ形式の画像データなんかは、なにか問題がありそうですよね。
以下のような9px × 9pxのラスタ画像を縦横9pxの領域に描画した様子を、ディスプレイで確認してみます。
デバイスピクセル比が1のディスプレイと、Retina(MacBook Pro)ディスプレイでスクリーンショットを撮影し、拡大したものが以下の画像になります。Reninaでは色の境界部がぼやけているのがわかります。
私の使用しているMacBook Proはデバイスピクセル比が2なので、一度、縦横18pxにまで拡大された後、縦横9pxの領域に収まっています。この拡大(スケーリング)される際にアンチエイリアス(ピクセルのギザギザを抑えてなめらかにする処理)が働き、画像がぼやけてしまっているのです。もしかしたら、以下のような拡大後のイメージを持たれた方もいるかもしれませんが、実際には上の画像のようにぼやけます。
綺麗に表示するには
このままだと「ラスタ画像をReninaディスプレイで表示するとぼやける」という結論になってしまうのですが、もちろん綺麗に表示する方法が用意されています。その方法とは、拡大後のサイズの画像を用意するというものです。先程の例で言えば、縦横18pxの画像を用意しておけば、拡大せずにそのまま使ってくれるので、ぼやけることなく綺麗に表示することができます(デバイスピクセルの多さが活きてくる!)。実際に、縦横18pxの画像を描画したものをRetinaディスプレイで確認してみます。
Retinaなのにぼやけることなく表示されているのがわかると思います。このような対応は「Retina対応」と呼ばれ、実際のコードではsrcset
を用いてデバイスピクセル比に応じてロードする画像を切替えたりして対応します。