高DPI(Retina)向けアセット運用—1x/2x/3xの最短ルート
すべてを2x/3xにする必要はありません。UIの性質で密度の要否を切り分け、SVG/PNGの使い分けを決め、命名と配信を揃えるのが近道です。
関連ツール
まとめて出すなら /density-export、命名は /rename が便利です。
要点(TL;DR)
- 可変表示のアイコン/テキストはSVG優先。写真や装飾のみPNG運用。
- PNGは必要箇所だけ 1x/2x/3x を用意。命名は
name@2x.png
/@3x
。 - 実装は
srcset
orimage-set()
、CLSゼロを厳守。 - Retina/非Retinaで目視確認(にじみ・ぼけ・線の滲み)。
1. 実装パターン(HTML/CSS/Next.js)
<!-- HTML (img: 密度ベース) --> <img src="/img/badge.png" srcset="/img/badge.png 1x, /img/badge@2x.png 2x, /img/badge@3x.png 3x" alt="バッジ" width="120" height="120" decoding="async" /> <!-- HTML (img: 幅ベース) --> <img src="/img/hero-800.png" srcset="/img/hero-800.png 800w, /img/hero-1200.png 1200w" sizes="(max-width: 768px) 92vw, 1200px" alt="ヒーロー" width="1200" height="720" /> /* CSS (image-set) */ .logo { background-image: image-set( url("/img/logo.png") 1x, url("/img/logo@2x.png") 2x ); }
Next.js の <Image>
を使う場合は、密度ではなく幅ベースに寄せるのが原則です。
2. いつ2x/3xが必要か
- 写真の装飾:1xで十分な場合が多い(レイアウト幅に依存)。
- 小さなビットマップアイコン:2xで滲み低減、3xは限定的に。
- 細い線/ピクセルアート:2x/3xでジャギー抑制。
3. 命名と出力の自動化
命名は /rename、出力は /density-export を採用。命名の例:
button.png button@2x.png button@3x.png
4. 公開前チェック(8項目)
- SVGで代替できる箇所はないか。
- PNG命名は
@2x/@3x
に統一。 - 実装は srcset/sizes で実幅一致。
- CLSゼロ(寸法明示)。
- Retina/非Retinaでにじみ無し。
- Before/After を /compare で確認。
- 指紋(v2/ハッシュ)でキャッシュ更新担保。
- GA4ダウンロード計測(zip_download等)が発火。
5. まとめ:必要なところだけ密度を上げる
2x/3xは万能ではありません。UIの性質で切り分け、必要箇所だけ密度を上げましょう。実務は /density-export と /rename を軸にすると迷いません。