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 {i>Reflow<i}, tetapi prosesnya secara efektif sama.

Demikian pula dengan perhitungan gaya, perhatian mendesak untuk biaya tata letak adalah:

  1. Jumlah elemen yang memerlukan tata letak, yang merupakan hasil samping 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 performa; sebisa mungkin Anda harus menghindari memicu tata letak.
  • Hindari layout 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 secepat mungkin. Jumlah waktu yang diperlukan untuk menyelesaikan interaksi—yang 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 dari interaksi adalah untuk memberikan umpan balik visual untuk memberi sinyal kepada pengguna bahwa sesuatu telah terjadi, dan pembaruan visual dapat melibatkan sejumlah pekerjaan tata letak untuk mencapai tujuan itu.

Untuk menjaga INP situs web Anda serendah mungkin, sebaiknya hindari tata letak jika memungkinkan. Jika tidak mungkin menghindari tata letak sepenuhnya, penting untuk membatasi pekerjaan tata letak tersebut sehingga browser dapat menyajikan bingkai berikutnya dengan cepat.

Sebisa mungkin hindari tata letak

Saat Anda mengubah gaya, browser akan memeriksa apakah ada perubahan yang mengharuskan tata letak dihitung, 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 mungkin menghindari tata letak, kuncinya sekali lagi adalah menggunakan Chrome DevTools untuk melihat berapa lama waktu yang dibutuhkan, dan menentukan apakah tata letak menjadi penyebab bottleneck. Pertama, buka DevTools, masuk ke tab Timeline, tekan rekam dan berinteraksilah dengan situs Anda. Saat berhenti merekam, Anda akan melihat perincian performa situs:

DevTools menampilkan waktu yang lama di Tata Letak.

Saat mempelajari rekaman aktivitas 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 memunculkan frame di layar dalam sebuah animasi, hal ini terlalu tinggi. Anda juga bisa melihat bahwa DevTools akan memberi tahu Anda ukuran pohon (1.618 elemen dalam kasus ini), dan berapa banyak simpul yang membutuhkan tata letak (5 dalam hal ini).

Perlu diingat bahwa saran umum di sini adalah menghindari tata letak jika memungkinkan—tetapi tidak selalu mungkin untuk menghindari tata letak. Jika Anda tidak bisa menghindari tata letak, ketahuilah bahwa biaya tata letak memiliki hubungan dengan ukuran DOM. Meskipun hubungan 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 harus dalam urutan berikut:

Menggunakan flexbox sebagai tata letak.

Pertama-tama, JavaScript dijalankan, lalu penghitungan gaya, lalu tata letak. Meskipun demikian, browser dapat memaksa untuk melakukan tata letak lebih awal dengan JavaScript. Ini disebut tata letak sinkron paksa.

Hal pertama yang perlu diingat adalah bahwa karena JavaScript menjalankan semua nilai tata letak lama dari bingkai sebelumnya, telah diketahui dan tersedia untuk Anda kueri. Jadi, jika, misalnya, Anda ingin menuliskan tinggi elemen (sebut saja "box") di awal {i>frame<i}, 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);
}

Perubahan akan menimbulkan masalah jika Anda mengubah gaya kotak sebelum meminta 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), dan kemudian menjalankan tata letak. Hanya dengan cara ini, perangkat akan dapat mengembalikan tinggi yang benar. Ini adalah pekerjaan yang tidak perlu dan berpotensi mahal.

Karena itu, Anda harus selalu mengelompokkan pembacaan gaya Anda 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 lalu mengkueri nilai; menggunakan nilai bingkai terakhir seharusnya sudah cukup. Menjalankan penghitungan gaya dan tata letak secara sinkron dan lebih awal dari browser yang diinginkan akan menjadi bottleneck potensial, dan biasanya bukan hal yang ingin Anda lakukan.

Menghindari layout thrashing

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 pada sekelompok paragraf dan menyetel lebar setiap paragraf agar sesuai dengan lebar elemen yang disebut "box". Ini terlihat tidak berbahaya, tetapi masalahnya adalah 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 (pada iterasi sebelumnya), sehingga 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 mengelompokkan pembacaan dan penulisan Anda, dan akan mencegah Anda memicu tata letak sinkron paksa atau layout thrashing secara tidak sengaja.

Banner besar dari Unsplash, oleh Hal Gatewood.