Font adalah item paling diremehkan dalam anggaran performa. Saya pernah melihat hasil Lighthouse di portfolio ini sendiri di mana largest contentful paint tidak terhambat oleh gambar atau bundle JavaScript — ia menunggu sebuah typeface. Font duduk di critical rendering path, memengaruhi layout shift, dan cara default kebanyakan situs memuatnya — link stylesheet ke CDN pihak ketiga — adalah salah satu opsi paling lambat.
Solusinya: self-host, subset, dan pilih strategi display yang waras — dan di Next.js modul next/font mengerjakan sebagian besar ini untuk Anda, asalkan Anda paham apa yang sebenarnya ia lakukan. Artikel ini menelusuri seluruh rantainya: mengapa CSS font pihak ketiga adalah pajak, bagaimana FOIT dan FOUT sebenarnya bekerja, apa yang dihasilkan next/font di balik layar, dan di mana subsetting serta variable font membuktikan nilainya.
Mengapa CSS Font Pihak Ketiga Adalah Pajak Performa
Embed Google Fonts klasik membebani Anda minimal satu koneksi ke host stylesheet dan koneksi kedua ke host file font: DNS lookup, handshake TCP, negosiasi TLS — sebelum satu glyph pun terunduh. Di koneksi desktop yang cepat overhead itu tersembunyi; di Android kelas menengah lewat seluler yang mendominasi trafik Indonesia, ia rutin menambah ratusan milidetik ke render teks pertama. Dan karena URL font berada di dalam CSS eksternal, browser bahkan tidak bisa mulai mengunduh font sampai stylesheet itu tiba dan selesai diparse.
Self-hosting meringkas semua itu ke koneksi origin Anda yang sudah ada. File font menumpang koneksi HTTP/2 atau HTTP/3 yang sama dengan HTML dan CSS Anda, bisa di-preload dengan percaya diri penuh, dan tidak ada pertanyaan ketersediaan atau privasi pihak ketiga. Poin terakhir ini bukan teori: mengirim IP pengunjung ke CDN font pihak ketiga adalah persis jenis aliran data yang regulasi privasi — termasuk UU PDP Indonesia — membuat Anda bertanggung jawab atasnya. Font self-hosted sederhana saja menghapus percakapan itu.
FOIT vs FOUT: Memilih Mode Kegagalan Anda
Selagi font terunduh, browser harus merender sesuatu. Descriptor font-display memutuskan apa, memakai timeline dua jendela: block period di mana teks tak terlihat, dan swap period di mana teks fallback tampil tapi akan ditukar begitu font tiba. Setiap nilai hanyalah konfigurasi berbeda dari dua jendela itu:
| font-display | Perilaku | Penilaian saya |
|---|---|---|
| block | Block period pendek, lalu swap tanpa batas. Teks tak terlihat sampai sekitar tiga detik — FOIT klasik. | Hindari. Teks tak terlihat di jaringan lambat adalah hasil terburuk bagi pengguna dan bagi LCP. |
| swap | Block nyaris nol, swap tanpa batas. Teks fallback langsung dirender, ditukar kapan pun font tiba — FOUT. | Default saya untuk tipografi penting bagi brand. Pasangkan dengan fallback yang dituning agar pertukarannya tidak menggeser layout. |
| fallback | Block nyaris nol, swap pendek sekitar tiga detik. Jika font melewatkan jendela itu, tampilan halaman ini tetap memakai fallback. | Jalan tengah yang baik untuk body text di mana pertukaran terlambat terasa mengganggu. |
| optional | Block nyaris nol, tanpa swap. Font hanya dipakai jika sudah tersedia, kalau tidak tampilan ini memakai fallback. | Opsi puris-performa yang direkomendasikan web.dev — nol pergeseran akibat swap, dengan biaya branding di kunjungan pertama. |
Tidak ada makan siang gratis: Anda memilih antara teks tak terlihat, reflow yang kelihatan, atau sesekali menampilkan font fallback. Keputusan engineering yang jujur adalah membuat trade-off itu secara eksplisit per proyek, alih-alih mewarisi apa pun yang diputuskan kode embed hasil copy-paste.
Apa yang Sebenarnya Dilakukan next/font
next/font bukan pembungkus embed Google Fonts — ia adalah pipeline font saat build. Ketika Anda mengimpor font dari next/font/google, saat build Next.js:
- Mengunduh CSS dan file font sekali, saat build, dan menyajikannya sebagai aset statis dari origin Anda sendiri — browser tidak pernah menghubungi Google sama sekali.
- Menghasilkan aturan @font-face dengan strategi display pilihan Anda dan nama font-family yang ter-scope dan bebas tabrakan.
- Menyuntikkan tag link preload untuk subset yang Anda deklarasikan, ter-scope per route tergantung apakah Anda memuat font di page, layout, atau root layout.
- Menghitung font fallback yang kompatibel secara metrik lewat adjustFontFallback, menimpa metrik ukuran fallback sehingga pertukaran dari font sistem ke web font nyaris tidak menggerakkan layout — inilah fitur pembunuh CLS.
// app/fonts.ts — one instance, imported everywhere
import { Inter } from "next/font/google"
import localFont from "next/font/local"
export const inter = Inter({
subsets: ["latin"], // only preload the glyphs you use
display: "swap", // text visible immediately
variable: "--font-inter" // expose as CSS variable for Tailwind
})
// Brand font you own the files for:
export const brand = localFont({
src: [
{ path: "./brand-var.woff2", weight: "100 900", style: "normal" },
],
display: "swap",
adjustFontFallback: "Arial", // metric-tuned fallback against CLS
variable: "--font-brand",
})
// app/layout.tsx
// <html className={inter.variable + " " + brand.variable}>
// tailwind.config.js
// fontFamily: { sans: ["var(--font-inter)"], display: ["var(--font-brand)"] }Pola yang saya pakai di setiap proyek adalah satu file fonts yang mengekspor tiap font sekali, dengan CSS variable yang terhubung ke Tailwind. Memanggil font loader di banyak file akan menginstansiasi font berkali-kali — satu file definisi, diimpor di mana-mana, menjaga bundle maupun tag preload tetap terdeduplikasi.
Tahan keinginan untuk preload manual setiap weight yang Anda self-host. Preload melewati prioritisasi bawaan browser, dan tiga file font yang di-preload bersaing dengan gambar LCP Anda memperebutkan bandwidth pada milidetik paling diperebutkan dari pemuatan halaman. Preload satu-dua file yang benar-benar dibutuhkan teks above-the-fold; biarkan sisanya dimuat sesuai kebutuhan.
Subsetting dan WOFF2: Kemenangan Murah
Format dulu: WOFF2 adalah satu-satunya format yang layak dikirim di 2026 — menurut web.dev kompresinya sekitar tiga puluh persen lebih baik dari WOFF, dan semua browser yang Anda pedulikan mendukungnya. Kalau tim desain memberi Anda TTF, konversikan sebelum menyentuh produksi.
Subsetting adalah tuas yang lebih besar. Font multibahasa penuh membawa Cyrillic, Yunani, Vietnam, dan ratusan glyph yang tidak pernah dirender situs Anda. Mendeklarasikan subsets latin di next/font otomatis memangkas font Google; untuk font brand lokal, proses lewat subsetter seperti pyftsubset dan simpan hanya rentang unicode yang Anda sajikan. Di sebuah proyek klien, font headline turun dari 218 KB ke 34 KB dengan subset latin — itu bukan optimasi mikro, itu bandwidth senilai satu gambar penuh yang dikembalikan ke critical path. Teks Indonesia sepenuhnya tercakup subset latin, yang membuat ini keputusan mudah untuk situs berbahasa Indonesia.
Variable Font: Satu File, Semua Weight
Variable font mengemas ruang desain kontinu — weight, width, slant — ke dalam satu file. Mereka mengubah hitungan default anggaran font saya:
Lebih sedikit request, sering kali bobot total lebih kecil
Regular plus medium plus semibold plus bold sebagai file statis berarti empat unduhan. Satu file variable yang mencakup rentang weight 100 sampai 900 adalah satu request dan biasanya lebih kecil dari gabungan tiga potongan statis.
Weight menjadi keputusan desain gratis
Dengan font statis, setiap weight baru yang diinginkan desainer adalah percakapan biaya jaringan tambahan. Dengan variable font, weight 450 atau 620 tidak menambah biaya — axis-nya sudah ada di dalam file.
Kelas satu di next/font
Variable font Google adalah jalur yang direkomendasikan: lewati opsi weight sepenuhnya atau berikan rentang seperti 100 900, dan next/font menyajikan file variable-nya. Axis ekstra seperti slnt bersifat opt-in lewat opsi axes untuk menjaga ukuran.
Awasi pembengkakan axis
Setiap axis tambahan memperbesar file. Font dengan optical-size plus width plus weight bisa melampaui potongan statis yang benar-benar Anda pakai. Subset axis sama seperti Anda men-subset glyph: kirim hanya yang dipakai design system.
Checklist Performa Font
- Self-host semuanya lewat next/font — nol koneksi pihak ketiga, font menumpang koneksi HTTP/2 atau HTTP/3 origin Anda.
- Kirim WOFF2 saja, dan subset ke rentang unicode yang benar-benar dipakai konten Anda — latin mencakup bahasa Inggris maupun Indonesia.
- Pilih font-display dengan sengaja: swap dengan fallback yang dituning metriknya untuk heading, fallback atau optional untuk body text jika reflow terlambat mengganggu Anda.
- Pakai satu variable font per family alih-alih tiga-empat weight statis, dan audit axis mana yang sungguh Anda butuhkan.
- Verifikasi dengan WebPageTest atau Lighthouse yang di-throttle: cek kapan teks pertama dirender, apakah swap menggeser layout, dan tidak ada file font yang menunda elemen LCP Anda.
Kesimpulan
Font layak mendapat perhatian engineering yang sama dengan gambar dan JavaScript, dan biasanya tidak mendapat apa-apa. Stack yang terbukti: self-host lewat next/font, satu file WOFF2 variable per family, subset latin, display swap dengan fallback metrik-kompatibel otomatis, dan menahan diri soal preload. Di portfolio ini kombinasi tersebut mengeluarkan font sepenuhnya dari critical path LCP — teks langsung dirender dengan fallback sistem yang dituning dan font brand masuk tanpa lompatan terlihat. Membosankan, terukur, dan layak dilakukan di setiap proyek.
Buka DevTools, ganti panel Network ke filter Font, dan reload dengan cache dimatikan. Kalau Anda melihat lebih dari dua file font sebelum first paint, atau request apa pun ke CDN font yang bukan milik Anda, Anda baru saja menemukan kemenangan performa termudah minggu ini.

