Menghindari tata letak yang besar dan kompleks serta layout thrashing

Tata letak adalah tempat browser mengetahui informasi geometris untuk elemen - ukuran dan lokasinya di laman. Setiap elemen akan memiliki informasi ukuran yang eksplisit atau implisit berdasarkan CSS yang digunakan, materi elemen, atau elemen induk. Proses ini disebut Tata Letak di Chrome.

Layout adalah tempat browser mengetahui informasi geometris untuk elemen: ukuran dan lokasinya di halaman. Setiap elemen akan memiliki informasi ukuran yang eksplisit atau implisit berdasarkan CSS yang digunakan, materi elemen, atau elemen induk. Proses ini disebut Layout di Chrome (dan browser turunan seperti Edge), dan Safari. Di Firefox ini disebut Reflow, tetapi prosesnya pada dasarnya sama.

Demikian pula dengan penghitungan gaya, persoalan mendesak untuk biaya tata letak adalah:

  1. Jumlah elemen yang memerlukan tata letak, yang merupakan produk sampingan dari ukuran DOM halaman.
  2. Kompleksitas tata letak tersebut.

Ringkasan

  • Tata letak memiliki pengaruh langsung terhadap latensi interaksi
  • Tata letak biasanya mencakup keseluruhan dokumen.
  • Jumlah elemen DOM akan memengaruhi performa; sebisa mungkin Anda harus menghindari memicu tata letak.
  • Hindari tata letak sinkron paksa dan layout thrashing; baca nilai gaya lalu buat perubahan gaya.

Efek tata letak pada latensi interaksi

Saat pengguna berinteraksi dengan halaman, interaksi tersebut harus dilakukan secepat mungkin. Jumlah waktu yang diperlukan untuk menyelesaikan interaksi—berakhir saat browser menampilkan frame berikutnya untuk menampilkan hasil interaksi—dikenal sebagai latensi interaksi. Ini adalah aspek performa halaman yang diukur oleh metrik Interaction to Next Paint.

Jumlah waktu yang diperlukan browser untuk menampilkan frame berikutnya sebagai respons terhadap interaksi pengguna dikenal sebagai penundaan presentasi interaksi. Tujuan suatu interaksi adalah untuk memberikan masukan visual untuk memberi sinyal kepada pengguna bahwa sesuatu telah terjadi, dan pembaruan visual dapat melibatkan sejumlah pekerjaan tata letak untuk mencapai tujuan tersebut.

Untuk menjaga INP situs serendah mungkin, sebaiknya hindari tata letak jika memungkinkan. Jika tidak dapat menghindari tata letak sepenuhnya, penting untuk membatasi pekerjaan tata letak tersebut agar browser dapat menampilkan frame berikutnya dengan cepat.

Hindari tata letak jika memungkinkan

Saat Anda mengubah gaya, browser akan memeriksa untuk mengetahui apakah perubahan tersebut mengharuskan tata letak dihitung, dan untuk itu pohon render akan diperbarui. Perubahan pada "properti geometris", seperti lebar, tinggi, kiri, atau atas, semuanya memerlukan tata letak.

.box {
  width: 20px;
  height: 20px;
}

/**
  * Changing width and height
  * triggers layout.
  */

.box--expanded {
  width: 200px;
  height: 350px;
}

Tata letak hampir selalu mencakup keseluruhan dokumen. Jika Anda memiliki banyak elemen, akan butuh waktu lama untuk mengetahui lokasi dan dimensi semuanya.

Jika tidak mungkin menghindari tata letak, kuncinya adalah menggunakan Chrome DevTools lagi untuk melihat berapa lama waktu yang diperlukan, dan menentukan apakah tata letak menjadi penyebab bottleneck. Pertama-tama, buka DevTools, buka tab Linimasa, pilih rekam, lalu berinteraksilah dengan situs Anda. Saat berhenti merekam, Anda akan melihat perincian performa situs Anda:

DevTools menampilkan waktu yang lama di Layout.

Saat meneliti rekaman aktivitas dalam contoh di atas, kita akan melihat bahwa lebih dari 28 milidetik dihabiskan dalam tata letak untuk setiap frame, yang mana, jika kita memiliki 16 milidetik untuk mengambil frame di layar dalam animasi, hal itu terlalu tinggi. Anda juga dapat melihat bahwa DevTools akan memberi tahu ukuran hierarki (1.618 elemen dalam kasus ini), dan banyaknya node yang memerlukan tata letak (5 dalam kasus ini).

Perlu diingat bahwa saran umum di sini adalah menghindari tata letak jika memungkinkan—tetapi Anda tidak selalu dapat menghindari tata letak. Jika Anda tidak dapat menghindari tata letak, ketahui bahwa biaya tata letak memiliki hubungan dengan ukuran DOM. Meskipun hubungan antara keduanya tidak terikat erat, DOM yang lebih besar umumnya akan menimbulkan biaya tata letak yang lebih tinggi.

Menghindari tata letak sinkron paksa

Pengiriman bingkai ke layar harus dalam urutan ini:

Menggunakan flexbox sebagai tata letak.

Pertama-tama JavaScript berjalan, lalu penghitungan gaya, kemudian tata letak. Namun, browser dapat dipaksa untuk melakukan tata letak lebih awal dengan JavaScript. Hal ini disebut tata letak sinkron paksa.

Hal pertama yang harus diingat adalah karena JavaScript yang menjalankan semua nilai tata letak lama dari bingkai sebelumnya telah diketahui dan tersedia untuk kueri. Jadi, jika misalnya Anda ingin menuliskan tinggi elemen (sebut saja "kotak") di awal bingkai, Anda dapat menuliskan beberapa kode seperti ini:

// Schedule our function to run at the start of the frame:
requestAnimationFrame(logBoxHeight);

function logBoxHeight () {
  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);
}

Semuanya akan rumit jika Anda mengubah gaya kotak sebelum Anda menanyakan tingginya:

function logBoxHeight () {
  box.classList.add('super-big');

  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);
}

Sekarang, untuk menjawab pertanyaan tinggi, browser harus terlebih dahulu menerapkan perubahan gaya (karena menambahkan class super-big), lalu kemudian menjalankan tata letak. Hanya dengan cara ini, widget dapat mengembalikan tinggi yang benar. Ini merupakan pekerjaan yang tidak perlu dan kemungkinan berat.

Oleh karena itu, Anda harus selalu melakukan pembacaan gaya serentak dan melakukannya terlebih dahulu (bila browser bisa menggunakan nilai tata letak bingkai sebelumnya) kemudian melakukan penulisan:

Jika dilakukan dengan benar, fungsi di atas akan menjadi:

function logBoxHeight () {
  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);

  box.classList.add('super-big');
}

Umumnya Anda tidak perlu menerapkan gaya baru kemudian mengkueri nilai; penggunaan nilai bingkai terakhir seharusnya sudah cukup. Menjalankan penghitungan gaya dan tata letak secara sinkron dan lebih dahulu daripada browser kemungkinan akan menjadi bottleneck, dan biasanya hal itu tidak Anda inginkan.

Menghindari thrashing tata letak

Ada cara untuk membuat tata letak sinkron paksa menjadi lebih buruk lagi: lakukan banyak tata letak secara berurutan. Lihat kode ini:

function resizeAllParagraphsToMatchBlockWidth () {
  // Puts the browser into a read-write-read-write cycle.
  for (let i = 0; i < paragraphs.length; i++) {
    paragraphs[i].style.width = `${box.offsetWidth}px`;
  }
}

Kode ini melakukan loop melalui sekelompok paragraf dan menyetel lebar setiap paragraf agar sama dengan lebar elemen yang disebut "box". Kelihatannya ini tidak berbahaya, namun masalahnya adalah karena setiap iterasi loop membaca nilai gaya (box.offsetWidth) lalu langsung menggunakannya untuk memperbarui lebar paragraf (paragraphs[i].style.width). Pada iterasi loop berikutnya, browser harus memperhitungkan fakta bahwa gaya telah berubah sejak offsetWidth terakhir diminta (dalam iterasi sebelumnya), sehingga ia harus menerapkan perubahan gaya, dan menjalankan tata letak. Hal ini akan terjadi pada setiap iterasi.

Perbaikan untuk contoh ini adalah sekali lagi membaca, lalu menulis nilai:

// Read.
const width = box.offsetWidth;

function resizeAllParagraphsToMatchBlockWidth () {
  for (let i = 0; i < paragraphs.length; i++) {
    // Now write.
    paragraphs[i].style.width = `${width}px`;
  }
}

Jika Anda ingin menjamin keamanan, pertimbangkan untuk menggunakan FastDOM, yang secara otomatis menyerempakkan pembacaan dan penulisan Anda, dan akan mencegah Anda memicu layout sinkron paksa atau layout-thrashing secara tidak sengaja.