公開日: 2012 年 8 月 22 日、最終更新日: 2025 年 4 月 14 日
市場にはさまざまなデバイスが存在するため、画面のピクセル密度は非常に幅広い範囲で利用できます。アプリケーション デベロッパーは、さまざまなピクセル密度をサポートする必要がありますが、これは非常に困難な場合があります。モバイルウェブでは、次のような要因によって課題が複雑になります。
- さまざまなフォーム ファクタを持つ多種多様なデバイス。
- ネットワーク帯域幅とバッテリー駆動時間の制約。
画像に関して、ウェブ デベロッパーの目標は、最高品質の画像をできるだけ効率的に配信することです。ここでは、現在と将来に役立ついくつかのテクニックについて説明します。
可能であれば画像は使用しない
画像を含める必要があると決める前に、ウェブには解像度や DPI に依存しない強力なテクノロジーが多数あることを覚えておいてください。具体的には、テキスト、SVG、ほとんどの CSS は、devicePixelRatio
によるウェブの自動ピクセル スケーリング機能により「問題なく動作」します。
ただし、ラスター画像を避けられないこともあります。たとえば、純粋な SVG や CSS で複製するのが非常に難しいアセットが提供される場合があります。写真の処理を行っている可能性があります。画像を SVG に変換することはできますが、写真のベクター化は意味がありません。通常、拡大したバージョンは見栄えがよくありません。
ピクセル密度の歴史
初期のコンピュータ ディスプレイのピクセル密度は 72 または 96 ドット / インチ(DPI)でした。
ディスプレイの画素密度は、主にモバイル デバイスの進歩によって徐々に向上してきました。これは、ユーザーが通常、スマートフォンを顔の近くに持ってきて、画素をよりはっきりと見えるようにするためです。2008 年までに、150 dpi のスマートフォンが新しい標準になりました。ディスプレイの密度はさらに高まり、現在のスマートフォンは 300 dpi のディスプレイを備えています。
実際には、低密度画像は新しい画面でも古い画面でも同じに見えますが、ユーザーが慣れている高密度画像の鮮明な画像と比較すると、低密度画像は不自然で粗く見えます。次の画像は、2x ディスプレイに 1x 画像が表示された場合の概略的なシミュレーションです。一方、2 倍の画像は非常に良好です。
1x ピクセル | 2x ピクセル |
![]() |
![]() |
ウェブ上のピクセル
ウェブが設計されたとき、ディスプレイの 99% は 96 dpi で、バリエーションに対する規定はほとんどありませんでした。画面サイズと密度が大きく異なるため、すべてのデバイスで画像を適切に表示するための標準的な方法が必要です。
HTML 仕様では、メーカーが CSS ピクセルのサイズを決定するために使用する参照ピクセルを定義することで、この問題に対処しています。
メーカーは、参照ピクセルを使用して、標準ピクセルまたは理想的なピクセルに相対するデバイスの物理ピクセルのサイズを決定できます。この比率をデバイスのピクセル比と呼びます。
デバイスのピクセル比を計算する
スマートフォンの画面の物理的なピクセルサイズが 180 ppi であるとします。デバイスのピクセル比の計算は、次の 3 つのステップで行います。
デバイスを保持している実際の距離と、参照ピクセルの距離を比較します。
仕様では、28 インチで 1 インチあたり 96 ピクセルが理想的とされています。スマートフォンでは、ノートパソコンやデスクトップ パソコンよりも顔がデバイスに近づきます。次の式では、その距離を 18 インチと見積もっています。
距離比を標準密度(96 ppi)に掛けて、指定した距離に最適なピクセル密度を取得します。
idealPixelDensity = (28/18) * 96 = 150 ppi(約)
物理ピクセル密度と理想的なピクセル密度の比率を計算して、デバイスのピクセル比を取得します。
devicePixelRatio = 180/150 = 1.2

そのため、ブラウザが理想的な解像度または標準解像度に応じて画面に収まるように画像のサイズを変更する方法を知る必要がある場合、ブラウザはデバイスのピクセル比 1.2 を参照します。つまり、このデバイスでは、理想的なピクセルごとに 1.2 個の物理ピクセルがあります。理想的なピクセル(ウェブ仕様で定義)と物理的なピクセル(デバイス画面上のドット)を変換する式は次のとおりです。
physicalPixels = window.devicePixelRatio * idealPixels
これまで、デバイス ベンダーは devicePixelRatios
(DPR)を四捨五入する傾向がありました。Apple の iPhone と iPad は DPR が 1 で、Retina 相当のデバイスは 2 です。CSS 仕様では、次のことを推奨しています。
ピクセル単位は、参照ピクセルに最も近いデバイス ピクセルの整数値を指します。
比率を丸めるとサブピクセル アーティファクトが少なくなるため、比率を丸めるほうが良い場合があります。
ただし、実際のデバイス環境ははるかに多様であり、Android スマートフォンの DPR は 1.5 であることが多いです。Nexus 7 タブレットの DPR は約 1.33 です。これは、前の例と同様の計算によって得られた値です。今後、DPR が可変のデバイスはさらに増える予定です。そのため、クライアントの DPR が整数であると想定してはいけません。
HiDPI 画像の手法
最高品質の画像をできるだけ早く表示する問題を解決するための手法は数多くありますが、大きく分けて次の 2 つのカテゴリに分類できます。
- 単一画像の最適化。
- 複数の画像の選択の最適化。
単一画像アプローチ: 1 つの画像を使用するが、巧妙に処理する。これらのアプローチには、低 DPI の古いデバイスでも HiDPI 画像をダウンロードする必要があるため、パフォーマンスを犠牲にしなければならないという欠点があります。単一画像の場合のアプローチは次のとおりです。
- 圧縮率の高い HiDPI 画像
- 素晴らしい画像形式
- プログレッシブ イメージ形式
複数の画像アプローチ: 複数の画像を使用しますが、読み込む画像を賢く選択します。これらのアプローチには、同じアセットの複数のバージョンを作成し、意思決定戦略を策定するという、デベロッパーに固有のオーバーヘッドがあります。指定できる広告タイプは次のとおりです。
- JavaScript
- サーバーサイド配信
- CSS メディアクエリ
- ブラウザの組み込み機能(
image-set()
、<img srcset>
)
圧縮率の高い HiDPI 画像
画像は、平均的なウェブサイトのダウンロードに費やされる帯域幅の 60% を占めています。すべてのクライアントに HiDPI 画像を提供することで、この数を増やすことができます。どれくらい大きくなりますか?
いくつかのテストを行い、JPEG 品質を 90、50、20 に設定して、1x と 2x の画像フラグメントを生成しました。
この小さな非科学的なサンプルから、大きな画像を圧縮すると、品質とサイズのバランスが取れているようです。私から見ると、圧縮率の高い 2 倍の画像は、圧縮されていない 1 倍の画像よりも見栄えがします。
ただし、画質が低く圧縮率の高い 2x 画像を 2x デバイスに配信することは、高画質の画像を配信するよりも悪い結果をもたらします。このアプローチでは、画質のペナルティが発生します。quality: 90
画像と quality: 20
画像を比較すると、画像の鮮明さが低下し、粒状感が強くなります。quality:20
を含むアーティファクトは、高品質の画像が重要な場合(写真ビューア アプリケーションなど)や、妥協を許さないアプリ デベロッパーには適さない場合があります。
この比較は、圧縮された JPEG のみを使用して行いました。広く実装されている画像形式(JPEG、PNG、GIF)には多くのトレードオフがあることに注意してください。
WebP: 優れた画像形式
WebP は、画像の忠実度を維持しながら非常に優れた圧縮を実現する、非常に魅力的な画像形式です。
WebP のサポートを確認する方法の 1 つは、JavaScript を使用する方法です。data-uri
を使用して 1 ピクセルの画像を読み込み、読み込みイベントまたはエラーイベントが発生するのを待ってから、サイズが正しいことを確認します。Modernizr には、Modernizr.webp
で利用可能なこのような機能検出スクリプトが付属しています。
ただし、image() 関数を使用して CSS で直接行う方が適切です。たとえば、WebP 画像と JPEG フォールバックがある場合は、次のように記述します。
#pic {
background: image("foo.webp", "foo.jpg");
}
このアプローチにはいくつかの問題があります。まず、image()
は広く実装されていません。2 つ目の理由は、WebP 圧縮は JPEG を圧倒的に上回るものの、このWebP ギャラリーに基づくと、サイズは約 30% 小さくなる程度で、比較的小さな改善にすぎません。したがって、高 DPI の問題に対処するには WebP だけでは不十分です。
プログレッシブ イメージ形式
JPEG 2000、プログレッシブ JPEG、プログレッシブ PNG、GIF などのプログレッシブ画像形式には、画像が完全に読み込まれる前に画像が表示されるというメリットがあります(議論の余地あり)。サイズのオーバーヘッドが発生する可能性がありますが、この点については矛盾する証拠があります。プログレッシブ モードでは「PNG 画像のサイズが約 20%、JPEG 画像と GIF 画像のサイズが約 10% 増加する」と Jeff Atwood は主張しています。ただし、Stoyan Stefanov は、大規模なファイルの場合、プログレッシブ モードの方が(ほとんどの場合)効率的であると主張しています。
一見すると、プログレッシブ イメージは、最高品質の画像をできるだけ早く提供するという観点から非常に有望な技術に見えます。追加データによって画質が向上しない(忠実度が向上するのはすべてサブピクセル単位である)ことが判明したら、ブラウザは画像のダウンロードとデコードを停止できます。
接続はすぐに終了しますが、再起動には多くの場合コストがかかります。画像が多いサイトでは、1 つの HTTP 接続を存続させ、できるだけ長く再利用するのが最も効率的な方法です。1 つの画像が十分にダウンロードされたために接続が早期に終了した場合、ブラウザは新しい接続を作成する必要があります。これは、低レイテンシ環境では非常に遅い場合があります。
この問題を回避する 1 つの方法は、HTTP Range リクエストを使用することです。これにより、ブラウザは取得するバイト範囲を指定できます。スマート ブラウザは、HEAD リクエストを送信してヘッダーを取得し、処理して、実際に必要な画像の量を決定してから取得できます。残念ながら、HTTP 範囲はウェブサーバーで十分にサポートされていないため、このアプローチは実用的ではありません。
最後に、このアプローチの明らかな制限は、読み込む画像を選択できないこと、同じ画像の忠実度のみを変更できることです。そのため、この機能は「アート ディレクション」のユースケースには対応していません。
JavaScript を使用して読み込む画像を決定する
読み込む画像を決定する最初のアプローチとして、クライアントで JavaScript を使用する方法があります。この方法では、ユーザー エージェントに関するすべての情報を把握し、適切な対応を取ることができます。window.devicePixelRatio
を使用してデバイスのピクセル比を特定したり、画面の幅と高さを取得したりできます。また、navigator.connection を使用してネットワーク接続のスニッフィングを行うことも、foresight.js ライブラリのように偽のリクエストを発行することもできます。これらの情報をすべて収集したら、読み込む画像を決定できます。
この手法を使用する 100 万個の JavaScript ライブラリがあります。残念ながら、どれも特に優れたものではありません。
大きな欠点の 1 つは、先読みパーサーが完了するまで画像の読み込みが遅れることです。つまり、pageload
イベントが発生するまで、イメージのダウンロードは開始されません。詳しくは、Jason Grigsby の記事をご覧ください。
サーバーに読み込む画像を決定する
サーバーサイドで決定を遅らせるには、提供する画像ごとにカスタム リクエスト ハンドラを作成します。このようなハンドラは、User-Agent(サーバーと共有される唯一の情報)に基づいて Retina のサポートを確認します。次に、サーバーサイド ロジックで HiDPI アセットを提供するかどうかに基づいて、適切なアセット(既知の規則に従って命名されたアセット)を読み込みます。
残念ながら、User-Agent には、デバイスで高画質または低画質の画像を受け取るべきかどうかを判断するのに十分な情報が必ずしも含まれていません。また、User-Agent
を使用してスタイルを決定するソリューションは避けてください。
CSS メディアクエリを使用する
CSS メディアクエリは宣言型であるため、意図を明記し、ブラウザに適切な処理を任せることができます。メディアクエリの最も一般的な用途であるデバイスサイズの一致に加えて、devicePixelRatio
を一致させることもできます。関連するメディアクエリは device-pixel-ratio で、予想どおり、最小値と最大値のバリエーションが関連付けられています。
高 DPI 画像を読み込み、デバイスのピクセル比がしきい値を超える場合は、次の方法があります。
#my-image { background: (low.png); }
@media only screen and (min-device-pixel-ratio: 1.5) {
#my-image { background: (high.png); }
}
すべてのベンダーのプレフィックスが混在すると、特に「min」と「max」のプレフィックスの配置の違いが大きいため、状況は少し複雑になります。
@media only screen and (min--moz-device-pixel-ratio: 1.5),
(-o-min-device-pixel-ratio: 3/2),
(-webkit-min-device-pixel-ratio: 1.5),
(min-device-pixel-ratio: 1.5) {
#my-image {
background:url(high.png);
}
}
このアプローチでは、JavaScript ソリューションで失われた先読み解析のメリットを再び利用できます。また、レスポンシブ ブレークポイントを選択する柔軟性も得られます(低 DPI、中 DPI、高 DPI の画像など)。これは、サーバーサイド アプローチでは不可能でした。
残念ながら、まだ使い勝手が悪く、CSS が奇妙な見た目になったり、前処理が必要になったりすることがあります。また、このアプローチは CSS プロパティに制限されているため、<img src>
を設定することはできず、画像はすべて背景のある要素である必要があります。最後に、デバイスのピクセル比に厳密に依存すると、ハイ DPI のスマートフォンが EDGE 接続中に巨大な 2x 画像アセットをダウンロードする結果になる可能性があります。これは最適なユーザー エクスペリエンスではありません。
image-set()
は CSS 関数であるため、<img>
タグの問題には対処しません。@srcset を入力すると、この問題が解決します。次のセクションでは、image-set
と srcset
について詳しく説明します。
高 DPI をサポートするブラウザ機能
最終的には、高 DPI サポートへのアプローチは、特定の要件によって異なります。上記のすべてのアプローチには欠点があります。
image-set
と srcset
が広くサポートされているため、これらが最適なソリューションです。古いブラウザとの互換性を高めるためのその他のベスト プラクティスもあります。
これらの 2 つの機能の違いは何ですか?image-set()
は CSS 関数で、CSS プロパティ background の値として使用できます。srcset
は <img>
要素に固有の属性で、構文も類似しています。どちらのタグでも画像宣言を指定できますが、srcset
属性を使用すると、ビューポートのサイズに基づいて読み込む画像を構成することもできます。
画像セットのベスト プラクティス
image-set()
構文は、カンマ区切りの 1 つ以上の画像宣言を受け取ります。この宣言は、URL 文字列または url()
関数と、それに続く適切な解像度で構成されます。次に例を示します。
image-set(
url("image1.jpg") 1x,
url("image2.jpg") 2x
);
/* You can also include image-set without `url()` */
image-set(
"image1.jpg" 1x,
"image2.jpg" 2x
);
これにより、選択できる画像が 2 つあることをブラウザに伝えます。1 つの画像は 1x ディスプレイ用に、もう 1 つの画像は 2x ディスプレイ用に最適化されています。ブラウザは、さまざまな要素(ブラウザが十分にスマートであればネットワーク速度も含む)に基づいて、どちらを読み込むかを選択します。
ブラウザは正しい画像を読み込むだけでなく、適切に画像をスケーリングします。つまり、ブラウザは 2 倍の画像が 1 倍の画像の 2 倍の大きさであると想定し、2 倍の画像を 2 倍に縮小して、ページ上で同じサイズに見えるようにします。
1x、1.5x、Nx を指定する代わりに、特定のデバイスのピクセル密度を DPI で指定することもできます。
image-set
プロパティをサポートしていない古いブラウザが懸念される場合は、フォールバック画像を追加して、画像を確実に表示できます。次に例を示します。
/* Fallback support. */
background-image: url(icon1x.jpg);
background-image: image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x
);
image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x
);
このサンプルコードは、image-set をサポートしているブラウザで適切なアセットを読み込み、そうでない場合は 1x アセットにフォールバックします。
ここで、image-set()
をポリフィル(JavaScript シムを作成)して、それで終わりにしない理由について説明します。結局のところ、CSS 関数に効率的なポリフィルを実装するのは非常に困難です。(理由の詳細については、この www スタイルのディスカッションをご覧ください)。
画像の srcset
srcset
要素は、image-set
が提供する宣言に加えて、ビューポートのサイズに対応する幅と高さの値も取り、最も関連性の高いバージョンを提供しようとします。
<img alt="my awesome image"
src="banner.jpeg"
srcset="banner-HD.jpeg 2x, banner-phone.jpeg 640w, banner-phone-HD.jpeg 640w 2x">
この例では、ビューポートの幅が 640 ピクセル未満のデバイスには banner-phone.jpeg
、小画面の高 DPI デバイスには banner-phone-HD.jpeg
、画面が 640 ピクセルを超える高 DPI デバイスには banner-HD.jpeg
、それ以外のデバイスには banner.jpeg
を配信します。
画像要素に image-set を使用する
img 要素を背景付きの <div>
に置き換えて、イメージセット アプローチを使用するのは魅力的ですが、これは、いくつかの注意事項を伴って機能します。欠点は、<img>
タグに長いセマンティック値があることです。実際には、ユーザー補助とウェブ クローラーにとって重要です。
content CSS プロパティを使用すると、devicePixelRation
に基づいて画像が自動的にスケーリングされます。次に例を示します。
<div id="my-content-image"
style="content: -webkit-image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x);">
</div>
ポリフィル srcset
srcset
の便利な機能の一つは、自然なフォールバックが付属していることです。srcset 属性が実装されていない場合、すべてのブラウザは src 属性を処理します。また、HTML 属性にすぎないため、JavaScript でポリフィルを作成することもできます。
このポリフィルには、できるだけ仕様に近づけるように単体テストが付属しています。また、srcset がネイティブに実装されている場合、ポリフィルがコードを実行できないようにするチェックも用意されています。
まとめ
高 DPI 画像に最適なソリューションは、SVG と CSS を使用することです。ただし、画像が多いウェブサイトでは、これが現実的な解決策であるとは限りません。
JavaScript、CSS、サーバーサイド ソリューションのアプローチにはそれぞれ長所と短所があります。最も有望なアプローチは、image-set
と srcset
を使用することです。
まとめると、推奨事項は次のとおりです。
- 背景画像には、image-set を使用し、サポートしていないブラウザには適切な代替手段を用意します。
- コンテンツ画像の場合は、srcset ポリフィルを使用するか、image-set を使用する(上記を参照)にフォールバックします。
- 画質を犠牲にできる場合は、圧縮率の高い 2x 画像の使用を検討してください。