| name | wsh-font-optimization |
| description | Font optimization for WSH 2026 — font-display swap, font subsetting, WOFF2 conversion, and preloading for ReiNoAreMincho and KaTeX fonts. |
WSH: Font Optimization
The project uses two large OTF font files (13.2MB total) with font-display: block, causing invisible text until fonts load. KaTeX fonts add another 1MB.
Use this skill when optimizing font loading, converting formats, or subsetting fonts.
Techniques
1. font-display: swap
@font-face {
font-family: "Rei no Are Mincho";
font-display: block;
src: url(/fonts/ReiNoAreMincho-Regular.otf) format("opentype");
}
@font-face {
font-family: "Rei no Are Mincho";
font-display: swap;
src: url(/fonts/ReiNoAreMincho-Regular.woff2) format("woff2");
}
Impact: FCP improvement — text visible immediately with fallback font, swaps when loaded
2. Convert OTF to WOFF2
WOFF2 provides ~30-50% better compression than OTF.
pyftsubset ReiNoAreMincho-Regular.otf \
--output-file=ReiNoAreMincho-Regular.woff2 \
--flavor=woff2 \
--layout-features='*'
Or use an online converter / woff2_compress tool.
Impact: 6.5MB OTF → ~3-4MB WOFF2
3. Font Subsetting
Subset to only characters used in the app. Japanese fonts can be subset to JIS X 0208 or commonly used characters.
pyftsubset ReiNoAreMincho-Regular.otf \
--output-file=ReiNoAreMincho-Regular-subset.woff2 \
--flavor=woff2 \
--text-file=used-characters.txt
Impact: 6.5MB → potentially <1MB if subset aggressively
4. Preload Critical Font
<link rel="preload" href="/fonts/ReiNoAreMincho-Regular.woff2" as="font" type="font/woff2" crossorigin>
Pitfalls
| Pitfall | Symptom | Fix |
|---|
| Missing characters in subset | Tofu (□) characters | Include all characters used in the app |
| WOFF2 not served with correct MIME | Font fails to load | Ensure server sends font/woff2 |
| font-display: swap CLS | Layout shift when font swaps | Use size-adjust or fallback font matching |
VRT Risks
| Change | Visual Impact | Mitigation |
|---|
| font-display: swap | FOUT (Flash of Unstyled Text) during load | VRT waits for load, should be fine |
| WOFF2 conversion | Identical rendering | Safe |
| Subsetting | Missing glyphs | Test all pages thoroughly |
Project-Specific Notes
- Font files at
application/public/fonts/
- @font-face in
application/client/src/index.css
- ReiNoAreMincho-Regular.otf: 6.5MB
- ReiNoAreMincho-Heavy.otf: 6.6MB
- KaTeX fonts copied by CopyWebpackPlugin from node_modules
- Font used across the app for body text (Mincho style)