perf(images): WebP banners, text-only related cards, resized list thumbnails
Deploy / build (push) Successful in 56s

Measured before/after with headless Chrome + CDP (not by eye):

- article banner: <picture> WebP q78 with the PNG as fallback, because the PNG
  must stay for og:image (social scrapers do not reliably render WebP cards).
  70 banners: 6.02 MB -> 2.52 MB (42%). JPEG measured *larger* than PNG here
  (q85 = 129%) — the art is flat terminal-style with sharp text edges.
- post page related cards: dropped four 1200x630 PNGs (183 KB) to display
  526x276 where the embedded code is illegible; now text-only cards with a
  category badge, date and reading time.
- list thumbnails (home + archive): new /og/thumb/<name>-{400,800}.webp served
  via srcset/sizes. Rows display at ~398px but were pulling full 1200x630 PNGs.
  Homepage thumbnails ~450 KB -> 62 KB; archive (71 rows) ~3.2 MB -> 436 KB.
- desktop banner capped at 720px centred: 67% -> 45% of a 900px viewport,
  keeping the art intact instead of cropping it.

Post page totals: images 277 KB -> 38 KB; page height 5758 -> 5065 (desktop)
and 9423 -> 8807 (mobile). Build: 163 pages.

Script: scripts/optimize-images.py; policy: docs/design-guide.md §3; runbook
step added to docs/ops-runbook.md.
This commit is contained in:
hoelee committed 2026-10-16 17:11:27 +08:00
1 parent 9462ab2373
commit f364084284
219 files changed
+158 -15

No files matched your search

+10
View File
@@ -32,6 +32,16 @@ Read this **before** touching theme, layout, typography, color, or SEO markup. P
- **Mobile-first**: design 390px, then desktop 1280px.
- **Astro Image** for automatic optimization/WebP (Core Web Vitals win).
- **Image format policy (measured 2026-10-16 — do not guess this one):**
| Asset | Served as | Why |
|---|---|---|
| `og:image` / `twitter:image` | **PNG** (1200×630) | Social scrapers (WhatsApp / LinkedIn / FB / Telegram) do not reliably render WebP share cards. Compatibility beats bytes here. |
| Article banner in-page | **WebP q78** + PNG fallback via `<picture>` | 6.02 MB → 2.52 MB across 70 banners (42%); JPEG would be *larger* (q85 = 129% of PNG) because the art is flat terminal-style with sharp text edges. |
| List/related thumbnails | **WebP q72 at 400w + 800w** (`/og/thumb/<name>-400.webp`) | Rows display at ~398px; they used to fetch the 1200×630 PNG (~45 KB). 400w is 5.8 KB, 800w is 16.1 KB. The homepage went from ~450 KB of thumbnails to ~62 KB. |
| Real photos (author, hardware) | **WebP q82** + JPEG fallback | Continuous-tone images are the opposite case from the flat art above. |
Regenerate all derivatives after adding a post: `uv run --with pillow python scripts/optimize-images.py`.
- **Declare `og:image:width/height` explicitly** — mis-declared dimensions get preview cards rejected by WhatsApp/Telegram/LinkedIn.
- **Favicon**: reference all sizes (`.ico` + 32×32 + 192×192 PNG + apple-touch 180×180). "Favicon not showing" is usually browser cache, not a missing asset — `curl` the live files before "fixing".