画像のRetinaディスプレイ対応

高解像度のディスプレイで画像を表示すると、ぼやけることがあります。

本ページでは、画像をRetinaディスプレイ対応する方法を説明します。

高解像度のディスプレイでの画像表示

iPhoneは、Retinaディスプレイが使われているため、小さなディスプレイでも高解像度です。また、Androidでも高解像度ディスプレイが多く採用されています。

高解像度にもかかわらず、画像を表示するとぼやけることがあります。

ぼやけた「あ」とぼやけていない「あ」

上記の2つの文字は、スマートフォンで表示した画像です。左の「あ」の文字は、普通に表示しています。右の「あ」の文字は、高解像度ディスプレイに対応した画像を表示しています。左の文字の方が、ぼやけているのがわかると思います。

ぼやける原因

ぼやける原因は、画像の縦横をCSSピクセルで決めているためです。

ビューポートの説明と設定」で説明したとおり、高解像度ディスプレイは横幅を本来表示できる能力ではなく、414pxなどと認識しています。このため、文字も大きく表示されますが、画像もCSSピクセルに合わせて拡大されています。

以下のように、1pxごとに格子がある画像を作ったとします。

9px × 9pxの画像で1pxごとに格子

これを、高解像度ディスプレイで表示して、1pxごとに格子を付けると、以下のようになります。

27px × 27pxの画僧で1pxごとに格子

9px × 9pxだった画像が、27px × 27pxに拡大されて、白黒だった格子は灰色などで埋め合わせられています。これが、ぼやける原因です。

スマートフォンは、CSSピクセルで絵画するため、9px × 9pxの画像をデバイスピクセル換算にして、27px × 27pxで表示しています。

今回は、9pxが27pxと縦横3倍に拡大された例ですが、この比率(デバイスピクセル比と言います)は機種によって1.5倍や2倍など、さまざまです。

対策

最後には27px × 27pxで表示されるため、最初から27px × 27pxの画像を使い、CSSでは9px × 9pxで指定します。使う画像は以下です。

27px × 27pxの画像で3pxごとに格子

先ほどは1px × 1px毎でしたが、上の図では3px × 3pxを1マスにして白黒の格子にしています。

HTMLでは、以下のように9px × 9px(CSSピクセル)で表示するようにします。

【27px × 27pxの画像を9px × 9pxで表示するHTML】
<img src="images/image1.png" alt="" style="width:9px;height:9px;">

これをスマートフォンで表示して、1pxごとの格子を付けると、以下のようになります。

27px × 27pxの画像で3pxごとに格子

灰色などで埋め合わせられるのではなく、元々の画像で表示されているのが確認できます。つまり、縦横3倍の画像を使えば、デバイスピクセルに画像の1pxを対応させて表示できるため、ぼやけないという訳です。

対策の効果

対策の効果の確認です。16pxの文字をそのまま画像にして表示したものと、48pxの文字で作成した画像を1/3にして表示したもので比較してみます。以下は、スマートフォンのスクリーンショットです。

16pxの文字をそのまま画像にして表示
文字がすべてぼやけて表示
48pxの文字で作成した画像を1/3にして表示
文字がぼやけずに表示

画像を大きく作って縮小した方(下の方)が、綺麗に見えると思います。

srcset属性

縦横3倍の画像を用意したとします。この場合、デバイスピクセル比が1.5倍や2倍の機種は、画像を縮小して表示する必要があります。

この対応として、デバイスピクセル比に応じて、表示する画像を切り替えることもできます。以下は、HTMLの例です。

【imgでsrcset属性を使うHTMLの例】
<img class="test"
  srcset="images/image-300w.png,
          images/image-450w.png 1.5x,
          images/image-600w.png 2x,
          images/image-900w.png 3x"
  src="image-900w.png" alt="画像の説明">

赤字部分は、画像の横幅がわかるように名前を付けています。例えば、300wであれば300pxです。各サイズで、ぼやけていない画像を準備する必要があります。青字部分は、デバイスピクセル比です。

デバイスピクセル比が1倍であればimage-300w.png、1.5倍であればimage-450w.png、2倍であればimage-600w.png、3倍であればimage-900w.pngが表示されます。最後の属性srcで指定した画像は、srcsetに対応していないブラウザの時に表示されます。

CSSでは、以下のようにクラスtestの幅を300pxに指定します。

【クラスtestの幅を300pxにするCSS】
.test {
  width: 300px;
}

これで、どの画像が使われてもCSSピクセルとして300pxの横幅で表示されます。横幅は300pxですが、デバイスピクセル比に応じて大きな画像が使われるため、ぼやけずに表示ができます。

sizes属性

先の例では、パソコンなどの大きなディスプレイでも、300pxで表示されます。大きなディスプレイの時は、大きなサイズで画像を表示したい場合、sizes属性が使えます。以下は、例です。

【imgでsizes属性を使うHTMLの例】
<img
  srcset="images/image-300w.png 300w,
          images/image-450w.png 450w,
          images/image-600w.png 600w,
          images/image-900w.png 900w"
  sizes="(max-width: 899px) 300px,
                            900px"
  src="images/image-900w.png" alt="画像の説明">

赤字部分は、画像の横幅(px)をw幅記述子で示します。青字部分は、メディアクエリです。上の例では、899px以下、それ以上で条件分けしています。緑字部分は、表示する横幅です。メディアクエリの条件によって300px、900pxで表示するようにしています。

このため、ビューポートが899px以下であれば横幅300pxのimage-300w.png、900px以上であれば横幅900pxのimage-900w.pngが表示されます。

ただし、これはデバイスピクセル比が1の時です。デバイスピクセル比が1.5、2や3の時は、1.5倍(450w)、2倍(600w)や3倍(900w)の画像が使われて、sizesで指定したCSSピクセルの横幅で表示されます。

つまり、スマートフォンではデバイスピクセル比に応じた画像が使われて、横幅300px(CSSピクセル)で表示されます。パソコンでは、900pxの画像が横幅900pxで表示されます。

次のページ表のレスポンシブ対応