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, konten elemen, atau elemen induk. Proses ini disebut Tata Letak di Chrome.

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, konten elemen, atau elemen induk. Proses ini disebut Layout in Chrome (dan browser turunan seperti Edge), dan Safari. Di Firefox ini disebut Reflow, tetapi prosesnya pada dasarnya sama.

Serupa dengan penghitungan gaya, masalah 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 efek langsung pada latensi interaksi
  • Tata letak biasanya mencakup keseluruhan dokumen.
  • Jumlah elemen DOM akan memengaruhi kinerja; Anda harus menghindari pemicuan tata letak jika memungkinkan.
  • Menghindari tata letak sinkron paksa dan layout thrashing; membaca nilai gaya, lalu membuat perubahan gaya.

Efek tata letak pada latensi interaksi

Saat pengguna berinteraksi dengan halaman, interaksi tersebut harus berjalan 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 mungkin untuk menghindari tata letak sepenuhnya, Anda harus membatasi tata letak tersebut agar berfungsi sehingga browser bisa menampilkan bingkai berikutnya dengan cepat.

Hindari tata letak jika memungkinkan

Bila Anda mengubah gaya, browser akan memeriksa apakah ada perubahan yang mengharuskan penghitungan tata letak, dan agar hierarki render 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 memungkinkan untuk menghindari layout maka kuncinya adalah sekali lagi menggunakan Chrome DevTools untuk melihat berapa lama waktu yang dibutuhkan, dan menentukan apakah tata letak merupakan penyebab bottleneck. Pertama, buka DevTools, buka tab Linimasa, tekan rekam, dan berinteraksilah dengan situs Anda. Saat berhenti merekam, Anda akan melihat perincian performa situs:

DevTools menampilkan waktu yang lama di Layout.

Saat menelusuri jejak pada contoh di atas, kita melihat bahwa lebih dari 28 milidetik dihabiskan di dalam tata letak untuk setiap frame, yang jika kita memiliki 16 milidetik untuk mendapatkan bingkai di layar dalam animasi, terlalu tinggi. Anda juga bisa melihat bahwa DevTools akan memberi tahu Anda ukuran pohon (1.618 elemen dalam kasus ini), dan berapa banyak node yang membutuhkan tata letak (dalam hal ini 5 elemen).

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, ketahuilah bahwa biaya tata letak ada hubungannya dengan ukuran DOM. Meskipun hubungan di antara keduanya tidak terkait erat, DOM yang lebih besar umumnya akan menimbulkan biaya tata letak yang lebih tinggi.

Menghindari tata letak sinkron paksa

Pengiriman bingkai ke layar ditentukan berdasarkan urutan berikut:

Menggunakan flexbox sebagai tata letak.

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

Hal pertama yang perlu diingat adalah karena JavaScript menjalankan semua nilai tata letak lama dari bingkai sebelumnya telah diketahui dan tersedia untuk kueri. Jadi jika, misalnya, Anda ingin menulis tinggi elemen (sebut saja "box") di awal bingkai Anda dapat menulis 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 bermasalah jika Anda telah 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 penambahan class super-big), lalu kemudian menjalankan tata letak. Hanya dengan cara ini, widget dapat mengembalikan tinggi yang benar. Ini adalah pekerjaan yang tidak perlu dan berpotensi mahal.

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

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');
}

Biasanya, Anda tidak perlu menerapkan gaya lalu mengkueri nilai; menggunakan nilai {i>frame<i} terakhir seharusnya cukup. Menjalankan penghitungan gaya dan tata letak secara sinkron dan lebih awal dari browser kemungkinan akan menjadi bottleneck, dan biasanya hal ini tidak akan Anda lakukan.

Menghindari layout thrashing

Ada cara untuk memperburuk tata letak sinkron paksa: 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 pada sekelompok paragraf dan menyetel lebar setiap paragraf agar sesuai dengan lebar elemen yang disebut "box". Ini terlihat cukup tidak berbahaya, tetapi masalahnya adalah setiap iterasi loop membaca nilai gaya (box.offsetWidth), lalu segera 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 browser harus menerapkan perubahan gaya, dan menjalankan tata letak. Hal ini akan terjadi di setiap iterasi..

Perbaikan untuk contoh ini adalah sekali lagi read lalu write 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 mengelompokkan operasi baca dan tulis untuk Anda, serta mencegah Anda memicu tata letak sinkron paksa atau thrashing tata letak secara tidak sengaja.

Banner besar dari Unsplash, oleh Hal Gatewood.