Apa yang harus dilakukan ketika CSS memblokir parsing halaman?

Baru-baru ini, saya melakukan audit terhadap satu situs dan menemukan pola preload/polyfillyang sudah saya lihat dengan beberapa klien. Saat ini, penggunaan pola yang sebelumnya populer ini tidak dianjurkan. Namun, penting untuk mempertimbangkannya untuk mengilustrasikan pentingnya penggunaan yang hati-hati dari mekanisme bahan preloading oleh browser web. Hal ini juga menarik karena memungkinkan Anda untuk menunjukkan contoh nyata bagaimana urutan elemen dalam dokumen dapat mempengaruhi kinerja (ini adalah apa yang dibahas dalam ini artikel Harry Roberts indah). Bahan, terjemahan yang kami terbitkan hari ini, dikhususkan untuk analisis situasi di mana penanganan sumber daya CSS yang tidak tepat dan tidak tepat waktu mempengaruhi kinerja halaman web.





Tentang loadCSS


Saya penggemar berat Grup Filament - mereka merilis banyak sekali proyek hebat. Selain itu, mereka terus-menerus membuat alat yang tak ternilai dan membagikannya demi meningkatkan web. Salah satu alat ini adalah loadCSS , yang untuk waktu yang lama adalah alat yang saya rekomendasikan semua orang gunakan untuk memuat sumber daya CSS yang tidak penting.

Meskipun ini sekarang telah berubah (dan Grup Filament telah menerbitkan artikel yang bagus tentang apa yang lebih disukai karyawannya saat ini), saya masih, ketika saya mengaudit lokasi, sering melihat bagaimana mereka loadCSSmenggunakannya dalam produksi.

Salah satu pola yang saya temui adalah polanyapreload/polyfill. Dengan menggunakan pendekatan ini, file apa pun dengan gaya dimuat dalam mode preload (atribut reltautan yang sesuai diatur ke preload). Setelah itu, ketika mereka siap untuk digunakan, terapkan acara mereka onloaduntuk menghubungkannya ke halaman.

<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="path/to/mystylesheet.css"></noscript>

Karena tidak semua browser mendukung desain <a href="https://caniuse.com/#feat=link-rel-preload"><link rel="preload"></a>, proyek loadCSSmemberikan pengembang polyfill yang nyaman, yang ditambahkan ke halaman setelah deskripsi tautan yang relevan:

<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">
<noscript>
    <link rel="stylesheet" href="path/to/mystylesheet.css">
</noscript>
<script>
/*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */
(function(){ ... }());
</script>

Gangguan dalam prioritas jaringan


Saya tidak pernah menjadi penggemar berat dari pola ini. Preloading adalah alat yang kasar. Materi yang diunduh menggunakan tautan atribut rel="preload"berhasil berkelahi dengan materi lain untuk sumber daya jaringan. Penggunaan preloadmengasumsikan bahwa stylesheet yang memuat secara tidak sinkron karena fakta bahwa mereka tidak memainkan peran penting dalam output halaman menerima prioritas yang sangat tinggi dari browser.

Gambar berikut, diambil dari WebPageTest, menunjukkan masalah ini dengan sangat baik. Di baris 3-6, Anda dapat melihat pemuatan file CSS yang tidak sinkron menggunakan suatu pola preload. Tapi, sementara pengembang menganggap file-file ini tidak begitu penting sehingga mengunduhnya akan memblokir rendering, gunakanpreload berarti bahwa mereka akan dimuat sebelum browser menerima sumber daya yang tersisa.


File CSS yang menggunakan pola preload ketika dimuat akan tiba di browser lebih awal dari sumber daya lainnya, meskipun mereka bukan sumber daya yang penting untuk rendering awal halaman

Kunci parser HTML


Masalah yang terkait dengan prioritas pemuatan sumber daya sudah cukup untuk menghindari penggunaan pola di sebagian besar situasi preload. Tetapi dalam kasus ini, situasinya diperparah dengan kehadiran stylesheet lain, yang dimuat dengan cara biasa.

<link rel="stylesheet" href="path/to/main.css" />
<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">
<noscript>
    <link rel="stylesheet" href="path/to/mystylesheet.css">
</noscript>
<script>
/*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */
(function(){ ... }());
</script>

Ada masalah yang sama ketika menggunakan preloadmengarah pada fakta bahwa bukan file yang paling penting mendapatkan prioritas tinggi. Tapi itu sama pentingnya, dan mungkin kurang jelas, apa efeknya pada kemampuan browser untuk mengurai halaman.

Sekali lagi, ini telah ditulis secara rinci , jadi saya sarankan membaca materi itu untuk lebih memahami apa yang terjadi. Di sini saya akan membicarakan ini secara singkat.

Biasanya, memuat gaya memblokir rendering halaman. Browser perlu melakukan query dan mem-parsing style agar dapat menampilkan halaman. Namun, ini tidak mencegah browser mem-parsing sisa kode HTML.

Script, di sisi lain, memblokir parser jika mereka tidak ditandai sebagai deferatau async.

Karena peramban harus berasumsi bahwa skrip dapat memanipulasi konten halaman itu sendiri atau gaya yang diterapkan padanya, ia harus berhati-hati ketika skrip ini dijalankan. Jika browser tahu bahwa beberapa kode CSS sedang dimuat, itu akan menunggu kedatangan kode CSS ini, dan setelah itu akan menjalankan skrip. Dan karena browser tidak dapat melanjutkan penguraian dokumen sampai skrip dieksekusi, ini berarti bahwa style tidak lagi hanya memblokir rendering. Mereka mencegah browser mem-parsing HTML.

Perilaku ini berlaku untuk skrip eksternal dan skrip yang disematkan di halaman. Jika CSS dimuat, skrip inline tidak berjalan sampai CSS ini tiba di browser.

Studi masalah


Cara yang paling dapat dimengerti untuk memvisualisasikan masalah ini adalah dengan menggunakan alat pengembang Chrome (saya sangat suka tingkat perkembangan alat ini).

Di antara alat Chrome ada tab di Performancemana Anda dapat merekam profil pemuatan halaman. Saya sarankan secara artifisial memperlambat koneksi jaringan sehingga masalah memanifestasikan dirinya lebih cerah.

Dalam hal ini, saya diuji menggunakan pengaturan jaringan 3G Cepat. Jika Anda melihat dengan cermat apa yang terjadi pada utas utama, Anda dapat memahami bahwa permintaan untuk memuat file CSS terjadi pada awal penguraian HTML (sekitar 1,7 detik setelah halaman mulai memuat).


Kotak kecil di bawah blok parsing HTML mewakili permintaan untuk file CSS.

Selama periode waktu berikutnya, yaitu sekitar satu detik, utas utama tidak aktif. Di sini Anda dapat melihat pulau aktivitas kecil. Ini adalah pemicu peristiwa yang mengindikasikan penyelesaian pemuatan gaya, itu adalah pengiriman oleh mekanisme preloading sumber daya permintaan lainnya. Tetapi browser benar-benar berhenti mem-parsing HTML.


Jika Anda melihat gambaran besar, ternyata setelah dimulainya pemuatan CSS, aliran utama tidak aktif selama lebih dari 1,1 detik.

Jadi, 2,8 detik telah berlalu, gaya dimuat, browser memprosesnya. Hanya kemudian kita melihat pemrosesan skrip bawaan, dan setelah itu browser akhirnya kembali ke penguraian HTML.


CSS tiba dalam waktu sekitar 2,8 detik, setelah itu kita melihat bahwa browser melanjutkan penguraian HTML

Firefox adalah pengecualian yang bagus


Perilaku di atas umum untuk Chrome, Edge, dan Safari. Firefox adalah pengecualian yang bagus untuk daftar browser populer.

Semua peramban lain menangguhkan penguraian HTML, tetapi menggunakan pengurai proaktif (alat bahan preloading) untuk melihat kode untuk tautan ke sumber daya eksternal dan untuk memenuhi permintaan memuat sumber daya ini. Firefox, bagaimanapun, melangkah lebih jauh dalam hal ini: Firefox secara spekulatif membangun pohon DOM, meskipun ia mengharapkan skrip untuk dieksekusi.

Kecuali skrip memanipulasi DOM, yang mengarah pada kebutuhan untuk membuang hasil penguraian spekulatif, pendekatan ini memungkinkan Firefox untuk mengambil keuntungan. Tentu saja, jika browser harus menjatuhkan pohon DOM yang dibangun secara spekulatif, itu berarti bahwa dia tidak melakukan apa pun yang berguna dengan membangun pohon ini.

Ini merupakan pendekatan yang menarik. Saya sangat ingin tahu seberapa efektif itu. Namun, sekarang, tidak ada informasi tentang ini di Firefox Performance Profiler. Di sana Anda tidak dapat mengetahui apakah parser spekulatif berfungsi, apakah perlu untuk mengulang pekerjaan yang dilakukan olehnya, dan jika masih perlu diulang, bagaimana hal ini akan mempengaruhi kinerja.

Saya berbicara dengan mereka yang bertanggung jawab atas alat pengembang Firefox, dan saya dapat mengatakan bahwa mereka memiliki ide menarik tentang cara menyajikan informasi ini di profiler di masa depan. Saya harap mereka berhasil.

Solusi untuk masalah tersebut


Dalam kasus klien, yang saya sebutkan di awal, langkah pertama dalam menyelesaikan masalah ini tampak sangat sederhana: singkirkan pola preload/polyfill. Memulai CSS yang tidak penting tidak ada gunanya. Di sini Anda perlu beralih menggunakan, alih-alih rel="preload", atribut media="print". Inilah yang direkomendasikan oleh para ahli dari Grup Filament. Pendekatan ini, di samping itu, memungkinkan Anda untuk sepenuhnya menghilangkan polyfill.

<link rel="stylesheet" href="/path/to/my.css" media="print" onload="this.media='all'">

Ini sudah menempatkan kami pada posisi yang lebih baik: sekarang prioritas jaringan jauh lebih baik disejajarkan dengan pentingnya unduhan. Dan kami juga menyingkirkan skrip bawaan.

Dalam hal ini, masih ada skrip bawaan lain yang terletak di header dokumen, di bawah garis yang memulai permintaan untuk memuat CSS. Jika Anda memindahkan skrip ini sehingga berada di depan baris memuat CSS, ini akan menghilangkan kunci parser. Jika Anda menganalisis halaman lagi menggunakan Alat Pengembang Chrome, perbedaannya akan sangat jelas.


Sebelum membuat perubahan pada kode halaman, parser HTML berhenti pada baris 1939, setelah menemui skrip bawaan, dan tetap di sini selama sekitar satu detik. Setelah optimisasi, ia bisa sampai ke baris 5281.

Sebelumnya, parser berhenti di baris 1939 dan sedang menunggu CSS untuk memuat, tetapi sekarang mencapai baris 5281. Di sana, di akhir halaman, ada skrip bawaan yang menghentikan parser lagi.

Ini adalah solusi cepat untuk masalah ini. Ini bukan opsi yang mewakili solusi akhir untuk masalah tersebut. Mengubah urutan elemen dan menghilangkan polapreload/polyfillhanyalah langkah pertama. Anda dapat memecahkan masalah ini dengan menanamkan kode CSS penting dalam sebuah halaman, daripada memuatnya dari file eksternal. Polapreload/polyfillDirancang untuk digunakan selain CSS inline. Ini memungkinkan kami untuk sepenuhnya mengabaikan masalah yang terkait dengan skrip dan memastikan bahwa browser, setelah permintaan pertama, memiliki semua gaya yang diperlukan untuk merender halaman.

Tetapi untuk saat ini, harus dicatat bahwa kita dapat mencapai peningkatan kinerja yang baik dengan membuat perubahan yang sangat kecil pada proyek mengenai cara gaya dimuat dan urutan elemen dalam DOM.

Ringkasan


  • Jika Anda menggunakan loadCSSpola preload/polyfill, pergi ke pola memuat gaya print.
  • Jika Anda memiliki gaya eksternal yang dimuat dengan cara biasa (yaitu, menggunakan tautan reguler ke file gaya ini), pindahkan semua skrip bawaan yang dapat dipindahkan di atas tautan untuk memuat gaya.
  • Cantumkan gaya kritis di halaman untuk memastikan permulaan render yang paling cepat.

Pembaca yang budiman! Pernahkah Anda mengalami masalah memperlambat rendering halaman karena CSS?

PS
RUVDS mengucapkan selamat kepada semua profesional TI pada 8 Maret!
Tahun ini, kami memutuskan untuk tidak memberi tulip dan tidak memilih kado geek. Kami mengambil jalan yang berbeda dan menciptakan IT adalah halaman wanita untuk menunjukkan keberadaan spesialis wanita di IT.


All Articles