Memahami & Memperbaiki “Ubah posisi/geometri yang dipaksa” (forced reflow)
Peringatan ini muncul ketika JavaScript memaksa browser menghitung ulang ukuran/posisi elemen (layout) berulang-ulang. Biasanya disebabkan oleh pola kode yang melakukan read dari properti geometri (mis. offsetWidth, clientHeight, getBoundingClientRect()) setelah melakukan write (mengubah DOM/CSS). Hasilnya: performa menurun, animasi patah-patah, dan skor Lighthouse turun.
Mengapa Ini Berbahaya?
- Memicu banyak perhitungan layout sinkron (forced layout) → CPU sibuk → frame rate turun.
- Terutama buruk di perangkat lemah (hp murah) dan pada halaman yang kompleks.
- Bisa muncul dari kode tema, plugin, atau library pihak ketiga (contoh pada laporanmu: file AMP runtime
/v0.js).
Bagaimana Browser Menjalankan Layout (sederhana)
Secara garis besar: read (membaca properti layout) & write (mengubah DOM/CSS) harus dipisah agar browser bisa menggabungkan operasi dan menghitung layout satu kali. Kalau kamu lakukan write → read → write secara bergantian, browser akan menghitung ulang berkali-kali.
Pola yang Sering Memicu Forced Reflow
- Membaca
offsetWidth/clientHeight/scrollTopsetelah mengubah style. - Loop yang tiap iterasi melakukan read lalu write pada elemen DOM (DOM thrashing).
- Kode pihak ketiga yang mengukur elemen berulang-ulang saat scrolling atau resize tanpa optimasi.
Solusi Praktis & Contoh Kode
1) Pisahkan "read" dan "write" (batching)
Jangan baca lalu ubah lalu baca lagi di dalam loop yang sama. Kumpulkan semua pembacaan dulu, lalu lakukan perubahan.
// BAD: baca dan tulis bergantian (memicu reflow berulang)
const items = document.querySelectorAll('.item');
items.forEach(el => {
const w = el.offsetWidth; // READ (memicu layout)
el.style.width = (w / 2) + 'px'; // WRITE
});
// GOOD: batch reads then batch writes
const items = document.querySelectorAll('.item');
const widths = [];
items.forEach(el => {
widths.push(el.offsetWidth); // semua READ dulu
});
items.forEach((el, i) => {
el.style.width = (widths[i] / 2) + 'px'; // lalu WRITE
});
2) Gunakan requestAnimationFrame untuk scheduling
Jika update visual perlu dilakukan, jadwalkan perubahan di rAF sehingga browser bisa menggabungkan rendering.
// Contoh: tunggu next frame sebelum menulis style
const newWidth = calculateSomething(); // read-heavy operation done earlier
requestAnimationFrame(() => {
element.style.width = newWidth + 'px';
});
3) Hindari properti yang memaksa layout bila memungkinkan
Properti seperti offsetWidth, scrollHeight, dan getBoundingClientRect() memicu layout. Gunakan data yang sudah kamu simpan atau solusi CSS (lihat poin 4).
4) Pakai transform & opacity untuk animasi
Memindahkan elemen sebaiknya menggunakan transform: translate() bukan mengubah top/left, karena transform tidak memicu reflow (hanya composite).
/* BAD: memodifikasi top => layout recalculation */
element.style.top = '100px';
/* GOOD: gunakan transform => cheaper */
element.style.transform = 'translateY(100px)';
5) Gunakan will-change & contain secara hati-hati
will-change: transform memberi tahu browser untuk menyiapkan kompositasi, dapat meningkatkan performa animasi. contain: layout membantu membatasi reflow. Gunakan dengan bijak karena penggunaan berlebihan juga bisa memengaruhi memori.
6) Debounce / throttle event handlers
Untuk scroll/resize, jangan jalankan perhitungan berat tiap event. Gunakan throttle atau debounce.
// contoh sederhana: throttle
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
window.requestAnimationFrame(() => {
// kerja yang relatif ringan
ticking = false;
});
ticking = true;
}
});
7) Untuk AMP: gunakan atribut layout & komponen AMP
- Pastikan gambar `
` memiliki atribut `width` & `height` atau `layout="responsive"` sehingga browser tidak perlu menghitung ulang saat gambar dimuat. - Hindari menjalankan kode kustom yang mengukur DOM di runtime AMP; gunakan komponen AMP standar (amp-carousel, amp-accordion) yang dioptimalkan.
- Minimalkan skrip pihak ketiga yang tidak perlu; ekstensi AMP yang salah dipakai bisa memicu reflow.
Diagnosa & Alat
- Chrome DevTools > Performance — rekam dan lihat bagian yang memakan waktu layout / style / paint.
- Lighthouse — memberi peringatan dan rekomendasi.
- WebPageTest — profil lebih dalam pada perangkat nyata.
- Perhatikan laporan: file sumbernya bisa jadi
/v0.js(AMP runtime) atau library pihak ketiga. Kalau sumbernya AMP, perhatikan penggunaan extension atau komponen yang memicu pengukuran.
Checklist Perbaikan Cepat (urut prioritas)
- Tentukan fungsi/skrip yang memanggil properti layout (offsetWidth, getBoundingClientRect, dll).
- Batch semua read → lalu lakukan semua write.
- Gunakan
requestAnimationFrameuntuk penjadwalan visual updates. - Ganti animasi berbasis layout dengan transform/opacity.
- Debounce/throttle event-heavy handlers (scroll/resize).
- Untuk AMP: berikan width/height pada amp-img dan gunakan komponen AMP yang sesuai.
Contoh nyata: perbaiki kode pengukuran saat resize
// BAD: melakukan reflow di setiap resize event
window.addEventListener('resize', () => {
const w = document.body.offsetWidth; // triggers layout
element.style.fontSize = (w / 100) + 'px'; // write
});
// GOOD: throttle + batch dengan rAF
let resizeTimeout;
window.addEventListener('resize', () => {
if (resizeTimeout) return;
resizeTimeout = true;
requestAnimationFrame(() => {
const w = document.body.clientWidth; // read in rAF
element.style.fontSize = (w / 100) + 'px'; // write in same frame
resizeTimeout = false;
});
});
Jika Sumbernya /v0.js (AMP runtime) atau library pihak ketiga
Sering kali laporan menunjukkan file library (contoh: /v0.js). Artinya problem mungkin bukan kode kamu langsung — tetapi cara kamu menggunakan komponen. Tindakan yang bisa diambil:
- Pastikan komponen AMP yang dipakai dikonfigurasi benar (mis. amp-img dengan dimensi).
- Kurangi jumlah ekstensi AMP yang tidak perlu.
- Periksa plugin/skrip pihak ketiga yang berjalan di halaman dan pertimbangkan menonaktifkan sementara untuk uji A/B.
Verifikasi Perbaikan
- Rekam halaman dengan Chrome DevTools Performance → bandingkan total waktu reflow/layout sebelum & sesudah perbaikan.
- Jalankan Lighthouse untuk melihat apakah peringatan menghilang dan skor performa meningkat.
- Uji di perangkat nyata (mobile) karena perbedaan terasa lebih besar di perangkat lemah.
Kesimpulan Ringkas
Forced reflow muncul karena pola kode read-write yang tidak efisien. Perbaiki dengan batching, requestAnimationFrame, menggunakan transform untuk animasi, dan optimasi event handler. Untuk AMP, pastikan elemen AMP diset dengan benar (dimensi) dan minimalisir skrip eksternal. Lakukan pengukuran ulang untuk memastikan perbaikan berhasil.
Rujukan & Sumber
- Google Developers — Reflow & Repaint (Render Performance)
- MDN — Layout and paint
- AMP Project docs — best practices for performance
