CJK fonts are large and need split loading
Aliases: CJK subset · unicode-range split · Chinese font chunks · on-demand glyphs
What it is
A full Chinese or pan-CJK face is often several megabytes, sometimes past twenty—orders of magnitude above a few-hundred-kilobyte Latin file. Shipping it as one asset holds the whole text run until download and parse finish. Split loading (subsetting / unicode-range splitting) cuts by code point, glyph frequency, or the page’s actual repertoire, sends the slice the first screen needs, and backfills the rest. The problem is bytes and request shaping, not which flash form to show, and not how far fallback metrics diverge from the web font.
Why it happens
Han, punctuation, extension blocks, and CJK compatibility glyphs make an enormous glyphtable. Decoding the whole table costs bandwidth, memory, and main-thread time. unicode-range lets the engine request only files whose ranges the page hits; build-time subsetting emits even smaller packages from the page charset or a frequency table. A typical cut is Latin-and-digits, frequent Han, rare/extension, then punctuation and vertical forms. Without a cut, the engine waits on the whole package, or stays on fallback for as long as that package is—volume itself stretches the gap.
Splitting buys more requests. Under HTTP/2, parallel small files usually still beat one giant; over-splitting turns handshake and queueing into a new bottleneck, and lets different code points in one paragraph arrive on different schedules, swapping glyph by glyph. Granularity should follow first-screen coverage: the first slice must include characters actually in the title and lead, not a mechanical Unicode-block split.
Where it stops holding
If the user already has the target CJK face installed, the web font need not ship at all, and splitting earns nothing. UI with a handful of Han characters (two or three on a button) is often cheaper as a system font or SVG. A variable font may collapse weights into one file and save, or grow the table and cost more—measure bytes. Mail, EPUB, and some mini-program runtimes do not fetch unicode-range slices on demand. Offline readers or bundled apps that install the face at package time are not on this runtime path.
Applying it
- At build time, tally glyphs actually used per page or route and emit subsets; keep a site-wide base of frequent Han, and put the long tail in a second slice.
- Declare each slice with
unicode-range, and preload the first slice so first-screen Chinese does not wait on extension blocks. - Cap the number of slices: one for the first screen, one for site-frequent glyphs, rare glyphs on demand—not one file per Unicode block.
- Verify on a cold load: bytes and completion time of files used by first-screen Chinese; lead-paragraph characters should live in slice one. Later requests should appear only when rare characters scroll into view. The full package must not sit on the first-screen critical path.