divmagic Make design
SimpleNowLiveFunMatterSimple
Meningkatkan Kinerja Situs dengan Mengirimkan Lebih Banyak CSS
Blogs›kinerja›Meningkatkan Kinerja Situs dengan Mengirimkan Lebih Banyak CSS
kinerja

Meningkatkan Kinerja Situs dengan Mengirimkan Lebih Banyak CSS

DivMagic
DivMagic TeamNovember 2, 2026
12 min read

Meningkatkan Performa Situs dengan Mengirimkan Lebih Banyak CSS

Ada insting yang tertanam dalam pekerjaan frontend modern yang mengatakan bahwa halaman tercepat mengirimkan sesedikit mungkin dari segala hal: lebih sedikit JavaScript, lebih sedikit font, lebih sedikit permintaan. Jadi ketika tim engineering GitHub menulis tentang meningkatkan performa situs dengan mengirimkan lebih banyak CSS, itu terdengar seperti kontradiksi. Perbaikan untuk antarmuka yang lambat dan berat JavaScript bukanlah dengan mencopot styling dari aplikasi. Perbaikannya adalah memasukkan lebih banyak styling kembali, sebagai stylesheet biasa, statis, dan dapat di-cache, serta menghapus JavaScript yang hanya ada untuk menghasilkan style di browser.

Perbedaan inilah inti seluruh artikel. Mengirimkan "lebih banyak CSS" tidak berarti stylesheet yang lebih besar yang membengkakkan critical path Anda. Artinya memindahkan pembuatan style keluar dari runtime dan ke dalam proses build, lalu membiarkan browser melakukan apa yang benar-benar dikuasainya: mem-parsing stylesheet sekali, menyimpannya dalam cache, dan menggunakannya kembali di setiap navigasi.

Biaya Tersembunyi dari Styling Runtime

Library CSS-in-JS memecahkan masalah nyata. Library tersebut memberi penulis komponen scoping, colocation, dan kemampuan untuk menginterpolasi props ke dalam style tanpa menciptakan konvensi penamaan. Tradeoff-nya bersifat arsitektural: library tersebut memindahkan masalah waktu kompilasi ke dalam browser.

Pembuatan style adalah pekerjaan JavaScript

Setiap halaman yang dirender server yang menggunakan library CSS-in-JS runtime meminta browser melakukan pekerjaan yang sama dua kali. Server menyerialkan style ke dalam tag <style>, lalu library klien bangun, menelusuri pohon komponen, melakukan hash nama class lagi, dan merekonsiliasi hasilnya. Pekerjaan itu terjadi di main thread, bersaing dengan langkah layout dan paint yang justru ingin Anda percepat.

// Runtime CSS-in-JS: this stylesheet does not exist until hydration runs
const Button = styled.button`
  background: ${(p) => (p.primary ? "#1f883d" : "transparent")};
  border: 1px solid #d0d7de;
  padding: 6px 16px;
  border-radius: 6px;
  font: inherit;
`;

Komponen yang sama yang diekspresikan sebagai stylesheet waktu build menghilangkan dependensi runtime sekaligus pekerjaan serialisasi:

/* button.module.css, parsed once, cached forever */
.button {
  padding: 6px 16px;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  font: inherit;
  background: transparent;
}
.buttonPrimary {
  background: #1f883d;
  color: #ffffff;
}
import styles from "./button.module.css";

export function Button({ primary, ...props }) {
  const className = primary
    ? `${styles.button} ${styles.buttonPrimary}`
    : styles.button;

  return <button className={className} {...props} />;
}

Tidak ada yang baru di sini. Yang mudah diremehkan adalah seberapa besar bagian bundle yang diam-diam dimiliki oleh stack CSS-in-JS yang matang: library itu sendiri, utilitas interpolasi prop, penyedia tema, serializer, dan kode framework duplikat yang tumbuh ketika setiap paket bergantung pada salinannya sendiri.

Ia berada langsung di critical rendering path

Sebuah <link rel="stylesheet"> memblokir rendering, tetapi memblokirnya sekali, dan browser dapat mem-parsing file tersebut saat aliran HTML masih datang. CSS runtime bekerja berbeda: browser bahkan tidak dapat mulai membangun style komponen sampai JavaScript telah diunduh, di-parse, dikompilasi, dan dieksekusi. Di ponsel kelas menengah, itu berarti satu detik atau lebih pekerjaan main thread sebelum satu tombol pun mendapatkan warna latarnya.

Ia memecah cache Anda

Nama class yang dihasilkan berubah setiap kali sumber komponen berubah, yang berarti stylesheet menjadi tidak valid pada hampir setiap deploy. Pecah hal itu ke puluhan bundle tingkat route dan Anda mendapatkan cache hit rate yang terlihat sehat di dashboard tetapi jarang terpicu pada kunjungan berulang. Sebaliknya, stylesheet statis dengan hash konten dapat disajikan dengan Cache-Control: public, max-age=31536000, immutable dan secara efektif tidak akan pernah diunduh dua kali.

Ia menggandakan pekerjaan selama hydration

Ketidakcocokan hydration antara style yang disuntikkan server dan yang dihasilkan klien adalah sumber flicker klasik. Browser melukis satu set aturan, lalu library klien menggantinya di tengah interaksi, memaksa perhitungan ulang style dan terkadang pergeseran layout. Nama class statis yang dihitung pada waktu build identik di kedua sisi, sehingga paint pertama juga merupakan paint terakhir.

Main-thread work before first contentful paint

Apa yang Sebenarnya Diubah GitHub

Migrasi ini paling baik dipahami sebagai lima langkah arsitektural, bukan satu refactor. Tidak satu pun dari langkah tersebut mengharuskan Anda meninggalkan model komponen, dan tidak satu pun mengharuskan penulisan ulang total.

web design, laptop, html, design, computer, internet, web, technology, website, development, office, business, web design, web design, web design, web design, web design, html, html, website, website, website, England, United Kingdom, Appledore

Token desain menjadi properti kustom CSS

Skala warna, spacing, radius, dan tipografi dipindahkan ke blok :root global sebagai properti kustom. Komponen merujuk ke var(--color-bg-default) alih-alih mengimpor objek tema JavaScript. Inilah yang membuat CSS statis cukup ekspresif untuk menggantikan style dinamis dalam sebagian besar kasus, dan memungkinkan tema runtime (mode gelap, kontras tinggi) tanpa JavaScript sama sekali.

Style komponen dikompilasi lebih awal

Setiap komponen mendapatkan stylesheet sungguhan, yang dihasilkan pada waktu build dan di-scope berdasarkan hash atau konvensi modul. Output-nya adalah CSS biasa yang dapat di-parse browser mana pun dengan kecepatan parsing.

Critical CSS di-inline di head dokumen

Hanya aturan yang dibutuhkan untuk viewport pertama yang di-inline ke dalam HTML. Biasanya berukuran 8–14 KB setelah gzip, dan itu berarti paint pertama tidak pernah menunggu perjalanan bolak-balik jaringan untuk stylesheet yang membentuk halaman terlihat.

<head>
  <!-- Critical: exactly what the first viewport needs, nothing more -->
  <style>
    /* reset + tokens + header + hero + above-the-fold grid */
  </style>

  <!-- Everything else: one hashed, immutable, long-cached file -->
  <link
    rel="stylesheet"
    href="/assets/app.8f3a1c2d.css"
    media="print"
    onload="this.media='all'"
  />
  <noscript>
    <link rel="stylesheet" href="/assets/app.8f3a1c2d.css" />
  </noscript>
</head>

Markup yang dirender server membawa nama class final

Karena nama class sudah ada pada waktu build, HTML yang dikembalikan server sudah memiliki style. Tidak ada proses kedua, tidak ada langkah rekonsiliasi, dan tidak ada flash konten tanpa style pada koneksi lambat.

Cascade layer menggantikan hack specificity

Sistem desain bersama hidup atau mati berdasarkan urutan cascade yang dapat diprediksi. Mendeklarasikan urutan layer sekali di awal membuat override deterministik dan menghilangkan dorongan untuk menggunakan !important atau selector yang semakin dalam.

@layer reset, tokens, base, components, utilities;

@layer components {
  .card {
    background: var(--color-canvas-default);
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-2);
    padding: var(--space-4);
  }
}

@layer utilities {
  .mt-4 { margin-top: var(--space-4); }
}

Angka-Angkanya: Apa yang Berubah Saat Anda Mengirimkan Lebih Banyak CSS

Memindahkan pembuatan style ke waktu build mengubah bentuk dari apa yang Anda kirimkan, bukan hanya volumenya. Byte yang tersisa itu murah: terkompresi dengan baik, dibagikan di setiap route, dan di-cache selama satu tahun.

Bytes shipped vs bytes executed

Hasil arsitekturalnya muncul di empat tempat sekaligus: lebih sedikit JavaScript yang perlu diunduh, lebih sedikit pekerjaan main thread sebelum paint pertama, stylesheet yang dapat di-cache dan dibagikan di seluruh navigasi, serta markup yang identik di server dan klien.

0
JavaScript bytes executed to apply a static stylesheet at runtime
~40%
of client-side JavaScript in a typical CSS-in-JS app is style generation code and its dependencies
ApproachJS shipped (gzip)CSS shipped (gzip)Runtime style workCacheable across deploys
Runtime CSS-in-JS~180 KB~12 KBHighNo
Single monolithic stylesheet~96 KB~88 KBNoneYes
Inline critical + split static sheets~78 KB~54 KBNoneYes
Utility-first CSS~85 KB~40 KBNoneYes

Stylesheet tercepat adalah stylesheet yang di-parse browser sekali, di-cache selama satu tahun, dan tidak pernah harus dibuat ulang.

Playbook Migrasi yang Praktis

Anda tidak memerlukan basis kode GitHub untuk menerapkan penalaran yang sama. Migrasinya bertahap dan setiap langkah dapat dikirim secara independen.

html, css, responsive, site design, themplate design, website development, html code, layout sites, programming, code, html, css, programming, programming, programming, programming, programming, code

1. Inventarisasi apa yang benar-benar dirender saat runtime

Buka DevTools, muat halaman, dan hitung document.styleSheets. Jika Anda menemukan puluhan tag <style> yang disuntikkan dengan nama class ber-hash, Anda telah menemukan target Anda. Cocokkan dengan panel Performance: cari tugas panjang antara DOMContentLoaded dan first contentful paint.

60%
of total page bytes can often be moved off the critical path by deferring non-critical CSS

2. Ekstrak CSS above-the-fold

Mulailah dengan blok inline sekecil mungkin. Heuristik yang andal adalah meng-inline reset, token, dan aturan yang digunakan oleh dua tinggi viewport pertama. Semua yang berada di bawah lipatan dimuat dari stylesheet yang ditunda.

3. Ubah komponen runtime menjadi class statis

Kerjakan komponen demi komponen, dimulai dari yang paling sering digunakan. Varian yang digerakkan prop menjadi class modifier atau properti kustom yang diatur pada wrapper. Pertahankan API komponen tetap identik agar lokasi pemanggilan tidak berubah.

// Genuinely dynamic values still belong in an inline style, not a generated sheet
<div
  className={styles.progressBar}
  style={{ "--progress": `${percent}%` }}
  role="progressbar"
  aria-valuenow={percent}
/>
.progressBar {
  width: var(--progress, 0%);
  transition: width 200ms ease-out;
}

Pola ini adalah andalan seluruh migrasi: struktur style bersifat statis dan dapat di-cache, sementara nilainya tetap dinamis dan tidak memakan biaya untuk diperbarui.

4. Tetapkan urutan layer lebih awal

Deklarasikan urutan @layer di bagian atas stylesheet entri Anda sebelum Anda memiliki masalah specificity, bukan sesudahnya. Menambahkan layer secara retroaktif ke cascade lama jauh lebih menyakitkan daripada memulainya dengan layer.

5. Hash nama file dan cache secara immutableHashing konten ditambah immutable adalah yang mengubah "lebih banyak CSS" menjadi "CSS gratis". Tampilan halaman kedua dalam satu sesi harus mengenai cache HTTP untuk setiap aturan gaya di situs.

6. Pertahankan gaya yang benar-benar dinamis tetap dinamis

Transformasi, posisi gulir, dan nilai yang digerakkan oleh pengukuran termasuk dalam gaya inline, requestAnimationFrame, atau Web Animations API. Jangan memperkenalkan kembali mesin gaya runtime untuk menyelesaikan masalah yang sudah dipecahkan oleh properti kustom CSS.

Cara Mengukur Peningkatan

Ukur tiga hal yang sama sebelum dan sesudah: waktu paint, tugas panjang thread utama, dan jumlah stylesheet. Skrip PerformanceObserver kecil memberi Anda ketiganya tanpa menambahkan ketergantungan pemantauan.

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(entry.name, Math.round(entry.startTime));
  }
}).observe({ type: "paint", buffered: true });

new PerformanceObserver((list) => {
  const long = list.getEntries().filter((e) => e.duration > 50);
  console.log(`${long.length} long tasks after load`);
}).observe({ type: "longtask", buffered: true });

console.log("stylesheets:", document.styleSheets.length);

Harapkan pergerakan terbesar dalam waktu hingga paint pertama pada kunjungan berulang dan pada profil seluler yang dibatasi, di mana biaya parsing JavaScript yang dihilangkan mendominasi. Largest contentful paint cenderung meningkat lebih bertahap, rilis demi rilis.

p75 Largest Contentful Paint across releases

Jebakan yang Perlu Dihindari

Pendekatan ini tidak bebas risiko, dan sebagian besar kegagalan berasal dari penerapannya yang terlalu agresif.

coding, computer, hacker, hacking, html, programmer, programming, script, scripting, source code, coding, coding, coding, coding, computer, computer, hacker, hacker, hacker, hacker, hacker, hacking, hacking, programming, programming

  • **CSS kritis yang tidak lengkap.**Jika Anda salah menebak viewport pertama, Anda akan mendapatkan reflow yang terlihat saat lembar yang ditangguhkan tiba. Hasilkan blok kritis secara otomatis dari render nyata, bukan dengan tangan. -**Menanamkan semuanya.**Menanamkan stylesheet lengkap ke dalam setiap respons HTML mengalahkan caching dan memperbesar ukuran dokumen. Tanamkan yang minimum, tunda sisanya. -**Naluri menggabungkan semuanya.**Saran lama untuk menggabungkan semua CSS menjadi satu file raksasa mendahului HTTP/2. Memisahkan berdasarkan rute seringkali lebih baik sekarang, selama primitif bersama di-cache secara terpisah. -Mencampur dua sistem. Menjalankan runtime CSS-in-JS dan stylesheet statis berdampingan terlalu lama akan menggandakan permukaan gaya Anda dan membuat debugging kaskade menjadi menyebalkan. Tetapkan tenggat waktu migrasi per direktori komponen.

Jebakan non-teknis yang paling umum adalah memperlakukan ini sebagai penulisan ulang besar-besaran. Tim yang berhasil mengonversi segelintir komponen dengan lalu lintas tinggi, mengukur delta, dan menggunakan data itu untuk membenarkan batch berikutnya.

Menggunakan DivMagic untuk Rekayasa Balik Arsitektur CSS Nyata

Salah satu bagian yang diremehkan dari migrasi ini adalah melihat bagaimana situs produksi yang matang benar-benar menyusun stylesheet mereka. Saat Anda memeriksa situs yang mengirimkan CSS statis dengan baik, Anda dapat belajar lebih banyak dalam lima menit daripada satu jam membaca dokumentasi: bagaimana mereka melapisi kaskade, bagaimana mereka membatasi token, bagaimana mereka memisahkan kritis dari yang ditangguhkan, dan bagaimana mereka menamai pengubah.

DivMagic dibangun untuk alur kerja itu. Alih-alih menyalin gaya elemen dari DevTools satu per satu aturan, Anda memilih UI apa pun di halaman mana pun dan menarik HTML dan CSS yang dihasilkan langsung ke editor Anda, siap untuk diadaptasi. Itu benar-benar berguna dalam dua situasi: membuat prototipe komponen dari desain referensi, dan mempelajari bagaimana situs berkinerja tinggi yang Anda kagumi mengatur kaskadenya sehingga Anda dapat mencerminkan pola tersebut dalam sistem desain Anda sendiri.

Ini juga mempersingkat bagian membosankan dari langkah ketiga di atas. Saat Anda mengonversi komponen runtime menjadi kelas statis, memiliki gaya akhir yang dihitung dalam bentuk yang dapat diedit, daripada sebagai gaya inline yang tersebar dan blok <style> yang disuntikkan, menghilangkan sebagian besar pekerjaan transkripsi.

Poin Penting

  • Pembuatan gaya runtime adalah pekerjaan JavaScript thread utama yang terjadi setelah unduhan JavaScript, langsung di jalur rendering kritis Anda.
  • CSS statis diurai sekali, di-cache selama setahun ketika di-hash konten, dan dibagikan di setiap rute dan setiap navigasi.
  • Tanamkan hanya aturan yang dibutuhkan viewport pertama; tunda sisanya di belakang <link> yang tidak memblokir dan kebijakan cache yang panjang.
  • Properti kustom CSS ditambah @layer mencakup sebagian besar kasus yang dulu memerlukan interpolasi gaya berbasis prop.
  • Migrasikan secara bertahap, komponen demi komponen, dan ukur waktu paint p75 dan tugas panjang daripada rata-rata.

Mengirimkan lebih banyak CSS terdengar seperti kemunduran sampai Anda menyadari bahwa Anda menukar stylesheet yang di-cache dan diurai sekali dengan megabita JavaScript yang membangunnya kembali pada setiap pemuatan halaman.

Pelajaran ini berlaku secara umum jauh melampaui GitHub. Setiap abstraksi yang berjalan di browser adalah biaya yang dibayar oleh pengguna, di perangkat mereka, di jaringan mereka, setiap saat. Memindahkan pembuatan gaya ke waktu build adalah salah satu pertukaran leverage tertinggi yang tersedia untuk frontend berbasis komponen, Anda mengirimkan file statis yang sudah diketahui cara menanganinya oleh browser, dan Anda menghapus mesin yang dulu menghalangi jalannya.

Mulai Membangun dengan DivMagic Sekarang

Bergabunglah dengan 10.000+ pengembang, desainer, dan pemilik bisnis untuk menyalin kode dari situs web mana pun dan menggunakannya dalam proyek mereka sendiri.

Get DivMagic for 42% off

Limited time deal for 22:45