スクショ最適化:文字にじみ・バンディング・圧縮ノイズを消す(PNG/WebP/AVIF)
UIのスクリーンショットはわずかな処理の違いで「文字がにじむ」「グラデが割れる」「圧縮ノイズが出る」ことがあります。 原因は縮小アルゴリズム・減色・色差圧縮のいずれか。この記事は、撮り方と書き出し方をセットで最短ルール化します。
先に結論(運用ルール)
- スクショは2xで撮って1/2に縮小(
-filter point
)。 - UI/文字はPNG8/PNG24かWebPロスレス。写真混在はAVIF/WebP有損も検証。
- 減色は色数+ディザでバンディングを抑える。
- 公開前は /compare で劣化を確認、容量は /compressor で最適化。
要点(TL;DR)
- 2xで撮影 → 1/2に縮小(
-filter point
)。整数倍以外の縮小はにじみやすい。 - UI/文字はPNG8/PNG24 or WebPロスレスを基本に。JPEGは避ける。
- グラデのバンディングは色数を増やす or ディザ強度を上げる。
- 透過・角丸があるならPNG/AVIFで安全に。OGPは 安全域設計 を。
1. なぜ起きる?(原因)
縮小の補間(双三次/ランチョス等)は写真向けで、UIの鮮鋭なエッジには不向きです。整数倍で point/nearest
を使うと輪郭を保ちやすい。また、減色で色数が不足するとグラデが段階化(バンディング)。 さらに有損圧縮は色差を間引き、文字周りにノイズが発生します。
2. 最短フロー(撮る→縮小→書き出す)
- スクリーンショットは高解像度(2x)で取得。
- 整数倍で縮小(例:2x→1x)。ImageMagickは
-filter point -resize 50%
。 - 文字/UIは PNG8/PNG24 or WebPロスレスを軸に。写真混在はAVIF/WebP有損を検証。
3. 実装レシピ(コピペOK)
3.1 ロスレス系(UI向け)
// CMD / ImageMagick# ImageMagick:ロスレスWebP/PNG24(UI/文字向け)
# WebPロスレス(テキスト/UIに最適・高圧縮)
magick input.png -define webp:lossless=true -quality 100 -strip output.webp
# PNG24(写真のないUIスクショで“完全無劣化”)
magick input.png -strip PNG24:output.png
3.2 PNG8 減色+ディザ
// CMD / ImageMagick# ImageMagick:PNG8(減色)+ディザで容量削減(UI/図版向け)
# 128色 + Floyd-Steinbergディザ → 透明/半透明も扱う場合は要検証
magick input.png -colors 128 -dither FloydSteinberg -define png:color-type=3 PNG8:output-128.png
# バンディングが出るなら色数を増やす or ディザ強度を調整
magick input.png -colors 192 -dither FloydSteinberg PNG8:output-192.png
3.3 縮小のにじみを防ぐ
// CMD / ImageMagick# ImageMagick:縮小のにじみを防ぐ(整数倍ダウンサンプル)
# 2xで撮って 1/2 に下げる(nearest/pointでエッジを維持)
magick input@2x.png -filter point -resize 50% -strip output-1x.png
# 3x→1x は一度 33.333% ではなく 300%→100%の整数比の段階縮小が安定(例)
magick input@3x.png -filter point -resize 66.666% -filter point -resize 50% -strip output-1x.png
3.4 Node(Sharp) 自動バッチ
// TypeScript / Node (Sharp)// Node(Sharp):PNG8(減色)/ロスレスWebPを自動化
import fs from "node:fs/promises";
import path from "node:path";
import sharp from "sharp";
const IN = "shots";
const OUT = "out";
await fs.mkdir(OUT, { recursive: true });
for (const name of await fs.readdir(IN)) {
const src = path.join(IN, name);
const base = path.parse(name).name;
// PNG8(128色 + ディザ)
await sharp(src)
.png({ palette: true, colors: 128, dither: 0.8 })
.toFile(path.join(OUT, base + "-png8.png"));
// WebPロスレス
await sharp(src)
.webp({ lossless: true })
.toFile(path.join(OUT, base + "-lossless.webp"));
}
3.5 CSS 表示の注意
// CSS/* CSS:ピクセルアート以外は基本auto。UIスクショを拡大表示するなら crisp-edges を検討 */
img.screenshot {
image-rendering: auto; /* 既定:テキスト/UIはこれが安全 */
/* image-rendering: crisp-edges; */ /* 一部ブラウザのみ。拡大時のにじみ抑制に効く場合あり */
/* image-rendering: pixelated; */ /* ピクセルアート用。UI/テキストには不向き */
}
4. 応用と使いどころ
- ダークUIの薄いグラデはバンディングが見えやすい。色数↑/ディザ↑で緩和。
- OGPサムネに使う場合は、安全域 と文字サイズ基準を満たす。
- 劣化の有無は /compare、容量は /compressor で定量検証。
5. 公開前チェック
- 縮小は整数倍で
-filter point
を使っている。 - UI/文字はロスレス(PNG/WebP)や十分な色数で書き出している。
- グラデのバンディングが目立つ場合は色数↑/ディザ↑で再出力。
- 透過や角丸は正しく表現されている(Premultiplied問題なし)。
- /compare と /compressor で最終確認。
6. まとめ
スクショ品質は撮り方×縮小×書き出しの三位一体です。テンプレを決めて自動化(Sharp/バッチ化)すれば、 いつでも安定品質で量産できます。サムネは OGP安全域、本文は CLSゼロ設計 と合わせて完成度を高めましょう。
FAQ(よくある質問)
画像形式の基本方針は?(写真/スクショ/透過)
写真は AVIF / WebP(画質80–85%目安)、UIやスクショはPNG / WebP Lossless、単色ロゴはSVGが基本です。 実装の詳細は srcset/sizes設計ガイド と スクショ最適化 を参照してください。
圧縮しても画質を落とさないコツは?
実表示幅に合わせたリサイズ → 過大ダウンロードを防ぎ、
srcset/sizes
を 実描画幅に一致させます。画質は写真で 80–85% を起点に、ノイズやエッジを目視確認。 仕上げは /compare で Before/After を見比べるのがおすすめです。