Setiap kali tampilan halaman berubah, misalnya tombol di-hover, class baru ditambahkan JavaScript, atau animasi berjalan, browser menjalankan ulang langkah-langkah menggambarnya. Langkah-langkah itu disebut rendering pipeline: Style, Layout, Paint, Composite. Bayangin bikin mading kelas. Kalau satu kertas dibikin lebih lebar, semua kertas di sebelahnya harus digeser dan diatur ulang. Kalau cuma warna tulisan di satu kertas yang diganti, cukup tulis ulang kertas itu. Kalau kertasnya ditempel di plastik transparan, kamu bisa menggeser plastiknya tanpa menulis ulang apa pun. Properti CSS yang kamu ubah menentukan pekerjaan mana yang harus diulang.
🧪 Tebakan cepat: tombol berubah warna latar (
background-color) waktu di-hover. Tahap mana yang dilewati browser: Layout, Paint, atau gak ada yang dilewati? Jawabannya ada di bagian "Properti mana memicu tahap mana".
Empat tahap, selalu berurutan
Di pelajaran Critical Rendering Path kamu sudah lihat tahap ini waktu halaman pertama dibuka. Setelah halaman tampil, tiap perubahan melewati jalur yang sama:
- Style. Browser mencocokkan selector dan menghitung style akhir (computed style) tiap elemen yang kena perubahan.
- Layout. Browser menghitung posisi dan ukuran tiap elemen. Satu elemen melebar, maka tetangga, parent, dan anak-anaknya ikut dihitung ulang. Tahap ini juga disebut reflow.
- Paint. Browser mengisi piksel: teks, warna, border, bayangan, gambar. Hasilnya bisa dibagi ke beberapa lapisan (layer).
- Composite. Lapisan-lapisan itu ditumpuk jadi satu gambar di layar. Pekerjaan ini dibantu GPU, dan bisa berjalan di luar main thread.
Di depannya biasanya ada JavaScript (atau hover, atau animasi CSS) yang memicu perubahan. Urutannya selalu Style → Layout → Paint → Composite. Tahap yang jalan memicu semua tahap sesudahnya: kalau Layout jalan, Paint dan Composite pasti ikut. Yang bisa terjadi cuma melewati tahap di tengah.
Properti mana memicu tahap mana
| Yang berubah | Tahap yang jalan | Contoh properti |
|---|---|---|
| Ukuran atau posisi (geometri) | Style → Layout → Paint → Composite | width, height, margin, padding, top, left, font-size, display |
| Tampilan saja | Style → Paint → Composite | color, background-color, box-shadow, border-color, visibility |
| Lapisan saja | Style → Composite | transform, opacity |
Itu jawaban tebakannya: background-color melewati Layout. Ukuran tombol gak berubah, jadi posisi elemen lain gak perlu dihitung ulang. Piksel tombolnya tetap harus dicat ulang.
transform dan opacity cuma butuh Composite kalau elemennya sudah punya layer sendiri. Browser biasanya membuat layer itu otomatis waktu animasi transform atau opacity berjalan.
Contoh di Lab: satu kartu, dua tetangga
Di Lab ada tiga kartu berjajar, masing-masing lebar 72 px. Yang diubah cuma kartu tengah.
| Perubahan di kartu tengah | Tetangganya bergeser? | Tahap yang jalan |
|---|---|---|
width: 72px jadi 108px |
ya, kartu kanan terdorong 36 px | Style, Layout, Paint, Composite |
background-color biru jadi oranye |
gak | Style, Paint, Composite |
transform: scale(1.5) |
gak, kartunya tampak membesar dan menimpa tetangga, tempat aslinya tetap | Style, Composite |
width: 108px dan scale(1.5) sama-sama bikin kartu tampak selebar 108 px. Bedanya, width mengubah geometri, jadi browser harus menghitung ulang letak kartu kanan. transform cuma memperbesar gambar kartu yang sudah jadi, tanpa menyentuh layout.
/* Mahal: tiap frame transisi menjalankan Layout */
.kartu {
width: 72px;
transition: width 0.3s;
}
.kartu:hover {
width: 108px;
}
/* Murah: kelihatan membesar, cuma Composite */
.kartu-hemat {
transition: transform 0.3s;
}
.kartu-hemat:hover {
transform: scale(1.5);
}
transition: width 0.3smenganimasikanwidthselama 0,3 detik. Di layar 60 Hz itu sekitar 18 frame, dan tiap frame menjalankan Layout, Paint, dan Composite.transform: scale(1.5)memperbesar 1,5 kali dari tengah. Layout-nya tetap 72 px, jadi tetangganya gak bergerak.transition: transform 0.3scukup Composite di tiap frame.
Kenapa Layout paling mahal
- Layout merembet. Satu elemen berubah ukuran bisa menggeser semua yang ada di sebelah dan di bawahnya. Di halaman dengan ribuan elemen, perhitungannya ikut banyak.
- Paint sebanding dengan luas. Mengecat ulang tombol kecil murah, mengecat ulang latar seluruh halaman atau bayangan besar yang blur jauh lebih berat.
- Composite cuma menumpuk lapisan yang sudah jadi. GPU bisa menggeser, memperbesar, atau memudarkan lapisan tanpa menggambar ulang isinya.
Untuk perubahan sekali klik, bedanya sering gak terasa. Untuk animasi, pekerjaan ini diulang di tiap frame, jadi pilihan properti menentukan mulus atau patah-patahnya gerakan.
⚠️ Jebakan yang sering ketemu
- Menganimasikan
width,height,top, atauleft. Tiap frame menjalankan Layout. Ganti dengantransform: scale()atautransform: translate(). - Mengira
display: nonedanvisibility: hiddensama.display: nonemengeluarkan elemen dari layout, jadi tetangganya bergeser (Layout).visibility: hiddencuma menyembunyikan pikselnya dan tempatnya tetap ada (Paint). - Mengira ganti warna itu gratis. Layout memang dilewati, tapi Paint tetap jalan. Bayangan besar yang blur atau latar seluas halaman tetap mahal kalau diubah tiap frame.
- Mengira urutan tahapnya bisa diacak. Urutannya selalu Style, Layout, Paint, Composite. Yang mungkin cuma melewati tahap, bukan menukar urutannya.
TL;DR: Tiap perubahan tampilan melewati Style → Layout → Paint → Composite, dan tahap yang jalan memicu semua tahap sesudahnya. Properti geometri (width, height, margin, padding, top, left, font-size) menjalankan keempatnya, jadi mengubah width memicu Layout, Paint, dan Composite. Properti tampilan (color, background-color, box-shadow) melewati Layout. transform dan opacity cukup Composite. Di Lab, width: 108px mendorong kartu kanan 36 px, sementara transform: scale(1.5) tampak sama besar tanpa menggeser apa pun.