Membuat Komponen Gambar yang efektif

Komponen gambar merangkum praktik terbaik performa dan menyediakan solusi siap pakai untuk mengoptimalkan gambar.

Leena Sohoni
Leena Sohoni
Kara Erickson
Kara Erickson
Alex Castle
Alex Castle

Gambar adalah sumber umum hambatan performa untuk aplikasi web dan area fokus utama untuk pengoptimalan. Gambar yang tidak dioptimalkan berkontribusi pada pembengkakan halaman dan menyumbang lebih dari 70% total ukuran halaman dalam byte pada persentil ke-90th Beberapa cara untuk mengoptimalkan gambar memerlukan "komponen gambar" cerdas dengan solusi performa yang disertakan sebagai default.

Tim Aurora bekerja sama dengan Next.js untuk membangun salah satu komponen tersebut. Tujuannya adalah membuat template gambar yang dioptimalkan yang dapat disesuaikan lebih lanjut oleh developer web. Komponen ini berfungsi sebagai model yang baik dan menetapkan standar untuk membangun komponen gambar di framework, sistem pengelolaan konten (CMS), dan stack teknologi lainnya. Kami telah berkolaborasi dalam komponen serupa untuk Nuxt.js, dan kami bekerja sama dengan Angular dalam pengoptimalan gambar di versi mendatang. Postingan ini membahas cara kami mendesain komponen Gambar Next.js dan pelajaran yang kami dapatkan selama proses tersebut.

Komponen gambar sebagai ekstensi gambar

Masalah dan peluang pengoptimalan gambar

Gambar tidak hanya memengaruhi performa, tetapi juga bisnis. Jumlah gambar di halaman adalah prediktor konversi terbesar kedua pengguna yang mengunjungi situs. Sesi saat pengguna melakukan konversi memiliki 38% lebih sedikit gambar dibandingkan sesi saat mereka tidak melakukan konversi. Lighthouse mencantumkan beberapa peluang untuk mengoptimalkan gambar dan meningkatkan data web sebagai bagian dari audit praktik terbaiknya. Berikut adalah beberapa area umum tempat gambar dapat memengaruhi core web vitals dan pengalaman pengguna.

Gambar yang tidak berukuran merusak CLS

Gambar yang ditayangkan tanpa ukuran yang ditentukan dapat menyebabkan ketidakstabilan tata letak dan berkontribusi pada Cumulative Layout Shift (CLS) yang tinggi. Menetapkan atribut width dan height pada elemen <img> dapat membantu mencegah pergeseran tata letak. Contoh:

<img src="flower.jpg" width="360" height="240">

Lebar dan tinggi harus ditetapkan sedemikian rupa sehingga rasio aspek gambar yang dirender mendekati rasio aspek alaminya. Perbedaan rasio aspek yang signifikan dapat menyebabkan gambar terlihat terdistorsi. Properti yang relatif baru yang memungkinkan Anda menentukan rasio aspek di CSS dapat membantu mengubah ukuran gambar secara responsif sekaligus mencegah CLS.

Gambar besar dapat memengaruhi LCP

Semakin besar ukuran file gambar, semakin lama waktu yang dibutuhkan untuk mendownloadnya. Gambar besar dapat berupa gambar "hero" untuk halaman atau elemen paling signifikan di area pandang yang bertanggung jawab untuk memicu Largest Contentful Paint (LCP). Gambar yang merupakan bagian dari konten penting dan membutuhkan waktu lama untuk didownload akan menunda LCP.

Dalam banyak kasus, developer dapat mengurangi ukuran gambar melalui kompresi yang lebih baik dan penggunaan gambar responsif. Atribut srcset dan sizes dari elemen <img> membantu menyediakan file gambar dengan ukuran yang berbeda. Browser kemudian dapat memilih yang tepat bergantung pada ukuran dan resolusi layar.

Kompresi gambar yang buruk dapat memengaruhi LCP

Format gambar modern seperti AVIF atau WebP dapat memberikan kompresi yang lebih baik daripada format JPEG dan PNG yang umum digunakan. Kompresi yang lebih baik dapat mengurangi ukuran file sebesar 25% hingga 50% dalam beberapa kasus untuk kualitas gambar yang sama. Pengurangan ini menghasilkan download yang lebih cepat dengan konsumsi data yang lebih sedikit. Aplikasi harus menayangkan format gambar modern ke browser yang mendukung format ini.

Memuat gambar yang tidak perlu akan memperburuk LCP

Gambar di bawah paruh atas atau tidak di area tampilan tidak ditampilkan kepada pengguna saat halaman dimuat. Permintaan ini dapat ditunda agar tidak berkontribusi pada LCP dan menundanya. Pemuatan lambat dapat digunakan untuk memuat gambar tersebut nanti saat pengguna men-scroll ke arahnya.

Tantangan pengoptimalan

Tim dapat mengevaluasi biaya performa akibat masalah yang tercantum sebelumnya dan menerapkan solusi praktik terbaik untuk mengatasinya. Namun, hal ini sering kali tidak terjadi dalam praktiknya, dan gambar yang tidak efisien terus memperlambat web. Kemungkinan alasannya adalah:

  • Prioritas: Developer web biasanya cenderung berfokus pada pengoptimalan kode, JavaScript, dan data. Oleh karena itu, mereka mungkin tidak menyadari masalah pada gambar atau cara mengoptimalkannya. Gambar yang dibuat oleh desainer atau diupload oleh pengguna mungkin tidak berada di urutan prioritas yang tinggi.
  • Solusi siap pakai: Meskipun developer memahami nuansa pengoptimalan gambar, tidak adanya solusi siap pakai all-in-one untuk framework atau stack teknologi mereka dapat menjadi penghalang.
  • Gambar dinamis: Selain gambar statis yang merupakan bagian dari aplikasi, gambar dinamis diupload oleh pengguna atau diambil dari database atau CMS eksternal. Mungkin sulit untuk menentukan ukuran gambar tersebut jika sumber gambar bersifat dinamis.
  • Kelebihan markup: Solusi untuk menyertakan ukuran gambar atau srcset untuk ukuran yang berbeda memerlukan markup tambahan untuk setiap gambar, yang bisa merepotkan. Atribut srcset diperkenalkan pada tahun 2014, tetapi saat ini hanya digunakan oleh 26,5% situs. Saat menggunakan srcset, developer harus membuat gambar dalam berbagai ukuran. Alat seperti just-gimme-an-img dapat membantu, tetapi harus digunakan secara manual untuk setiap gambar.
  • Dukungan browser: Format gambar modern seperti AVIF dan WebP membuat file gambar yang lebih kecil, tetapi memerlukan penanganan khusus di browser yang tidak mendukungnya. Developer harus menggunakan strategi seperti negosiasi konten atau elemen <picture> agar gambar ditayangkan ke semua browser.
  • Komplikasi pemuatan lambat: Ada beberapa teknik dan library yang tersedia untuk menerapkan pemuatan lambat untuk gambar di bawah area yang terlihat. Memilih yang terbaik bisa menjadi tantangan. Developer juga mungkin tidak mengetahui jarak terbaik dari "fold" untuk memuat gambar yang ditangguhkan. Ukuran area tampilan yang berbeda di perangkat dapat semakin mempersulit hal ini.
  • Perubahan lanskap: Saat browser mulai mendukung fitur HTML atau CSS baru untuk meningkatkan performa, developer mungkin kesulitan mengevaluasi setiap fitur tersebut. Misalnya, Chrome memperkenalkan fitur Prioritas Pengambilan sebagai Uji Coba Origin. Atribut ini dapat digunakan untuk meningkatkan prioritas gambar tertentu di halaman. Secara keseluruhan, developer akan merasa lebih mudah jika peningkatan tersebut dievaluasi dan diterapkan di tingkat komponen.

Komponen gambar sebagai solusi

Peluang yang tersedia untuk mengoptimalkan gambar dan tantangan dalam menerapkannya satu per satu untuk setiap aplikasi mengarahkan kami pada ide komponen gambar. Komponen gambar dapat merangkum dan menerapkan praktik terbaik. Dengan mengganti elemen <img> dengan komponen gambar, developer dapat mengatasi masalah performa gambar mereka dengan lebih baik.

Selama setahun terakhir, kami telah bekerja dengan framework Next.js untuk mendesain dan menerapkan komponen Gambar mereka. Komponen ini dapat digunakan sebagai pengganti langsung untuk elemen <img> yang ada di aplikasi Next.js sebagai berikut.

// Before with <img> element:
function Logo() {
  return <img src="/logo.jpg" alt="logo" height="200" width="100" />
}

// After with image component:
import Image from 'next/image'

function Logo() {
  return <Image src="/logo.jpg" alt="logo" height="200" width="100" />
}

Komponen ini mencoba mengatasi masalah terkait gambar secara umum melalui serangkaian fitur dan prinsip yang kaya. Selain itu, ada opsi yang memungkinkan developer menyesuaikannya untuk berbagai persyaratan gambar.

Perlindungan dari pergeseran tata letak

Seperti yang dibahas sebelumnya, gambar yang tidak berukuran menyebabkan pergeseran tata letak dan berkontribusi pada CLS. Saat menggunakan komponen Gambar Next.js, developer harus memberikan ukuran gambar menggunakan atribut width dan height untuk mencegah perubahan tata letak. Jika ukurannya tidak diketahui, developer harus menentukan layout=fill untuk menayangkan gambar yang tidak berukuran dan berada di dalam penampung berukuran. Atau, Anda dapat menggunakan impor gambar statis untuk mengambil ukuran gambar sebenarnya di hard drive pada waktu build dan menyertakannya dalam gambar.

// Image component with width and height specified
<Image src="/logo.jpg" alt="logo" height="200" width="100" />

// Image component with layout specified
<Image src="/hero.jpg" layout="fill" objectFit="cover" alt="hero" />

// Image component with image import
import Image from 'next/image'
import logo from './logo.png'

function Logo() {
  return <Image src={logo} alt="logo" />
}

Karena developer tidak dapat menggunakan komponen Gambar tanpa ukuran, desain ini memastikan bahwa mereka akan meluangkan waktu untuk mempertimbangkan ukuran gambar dan mencegah pergeseran tata letak.

Memfasilitasi daya respons

Agar gambar responsif di berbagai perangkat, developer harus menetapkan atribut srcset dan sizes dalam elemen <img>. Kami ingin mengurangi upaya ini dengan komponen Gambar. Kami mendesain komponen Next.js Image untuk menetapkan nilai atribut hanya sekali per aplikasi. Kami menerapkannya ke semua instance komponen Gambar berdasarkan mode tata letak. Kami menemukan solusi tiga bagian:

  1. Properti deviceSizes: Properti ini dapat digunakan untuk mengonfigurasi titik henti sementara satu kali berdasarkan perangkat yang umum untuk basis pengguna aplikasi. Nilai default untuk titik henti sementara disertakan dalam file konfigurasi.
  2. Properti imageSizes: Ini juga merupakan properti yang dapat dikonfigurasi yang digunakan untuk mendapatkan ukuran gambar yang sesuai dengan titik henti sementara ukuran perangkat.
  3. Atribut layout di setiap gambar: Atribut ini digunakan untuk menunjukkan cara menggunakan properti deviceSizes dan imageSizes untuk setiap gambar. Nilai yang didukung untuk mode tata letak adalah fixed, fill, intrinsic, dan responsive

Saat gambar diminta dengan mode tata letak responsif atau isi, Next.js mengidentifikasi gambar yang akan ditayangkan berdasarkan ukuran perangkat yang meminta halaman dan menetapkan srcset dan sizes dalam gambar dengan tepat.

Perbandingan berikut menunjukkan cara mode tata letak dapat digunakan untuk mengontrol ukuran gambar di layar yang berbeda. Kami telah menggunakan gambar demo yang dibagikan dalam dokumentasi Next.js, yang dilihat di ponsel dan laptop standar.

Layar laptop Layar ponsel
Tata Letak = Intrinsic: Diperkecil agar sesuai dengan lebar penampung pada area tampilan yang lebih kecil. Tidak menskalakan lebih besar dari ukuran intrinsik gambar pada area pandang yang lebih besar. Lebar penampung 100%
Gambar pegunungan ditampilkan apa adanya Gambar pegunungan diperkecil
Tata Letak = Tetap: Gambar tidak responsif. Lebar dan tinggi ditetapkan seperti elemen `` terlepas dari perangkat tempat elemen tersebut dirender.
Gambar pegunungan ditampilkan apa adanya Gambar pegunungan yang ditampilkan apa adanya tidak sesuai dengan layar
Tata Letak = Responsif: Perkecil skala atau peningkatan skala bergantung pada lebar penampung di berbagai area tampilan, dengan mempertahankan rasio aspek.
Gambar pegunungan yang diperbesar agar pas dengan layar Gambar pegunungan diperkecil agar pas dengan layar
Tata Letak = Isi: Lebar dan tinggi diregangkan untuk mengisi penampung induk. (Lebar <div> induk ditetapkan ke 300*500 dalam contoh ini)
Gambar pegunungan yang dirender agar sesuai dengan ukuran 300*500 Gambar pegunungan yang dirender agar sesuai dengan ukuran 300*500
Gambar yang dirender untuk tata letak yang berbeda

Menyediakan pemuatan lambat bawaan

Komponen Gambar menyediakan solusi pemuatan lambat bawaan yang berperforma tinggi sebagai default. Saat menggunakan elemen <img>, ada beberapa opsi untuk pemuatan lambat, tetapi semuanya memiliki kekurangan yang membuatnya sulit digunakan. Developer dapat menerapkan salah satu pendekatan pemuatan lambat berikut:

  • Tentukan atribut loading: Atribut ini didukung di semua browser modern.
  • Gunakan Intersection Observer API: Membangun solusi pemuatan lambat kustom memerlukan upaya serta desain dan penerapan yang matang. Developer mungkin tidak selalu memiliki waktu untuk melakukan hal ini.
  • Mengimpor library pihak ketiga untuk memuat gambar secara lambat: Upaya tambahan mungkin diperlukan untuk mengevaluasi dan mengintegrasikan library pihak ketiga yang sesuai untuk pemuatan lambat.

Di komponen Next.js Image, pemuatan ditetapkan ke "lazy" secara default. Pemuatan lambat diimplementasikan menggunakan Intersection Observer, yang tersedia di sebagian besar browser modern. Developer tidak perlu melakukan tindakan tambahan apa pun untuk mengaktifkannya, tetapi mereka dapat menonaktifkannya jika diperlukan.

Pramuat gambar penting

Sering kali, elemen LCP adalah gambar, dan gambar besar dapat menunda LCP. Sebaiknya muat terlebih dahulu gambar penting agar browser dapat menemukan gambar tersebut lebih cepat. Saat menggunakan elemen <img>, petunjuk pra-muat dapat disertakan di head HTML sebagai berikut.

<link rel="preload" as="image" href="important.png">

Komponen gambar yang didesain dengan baik harus menawarkan cara untuk menyesuaikan urutan pemuatan gambar, terlepas dari framework yang digunakan. Dalam kasus komponen Gambar Next.js, developer dapat menunjukkan gambar yang merupakan kandidat yang baik untuk pramuat menggunakan atribut priority dari komponen gambar.

<Image src="/hero.jpg" alt="hero" height="400" width="200" priority />

Menambahkan atribut priority menyederhanakan markup dan lebih nyaman digunakan. Developer komponen gambar juga dapat mempelajari opsi untuk menerapkan heuristik guna mengotomatiskan pra-pemuatan untuk gambar di atas layar pada halaman yang memenuhi kriteria tertentu.

Mendorong hosting gambar berperforma tinggi

CDN Gambar direkomendasikan untuk mengotomatiskan pengoptimalan gambar, dan juga mendukung format gambar modern seperti WebP dan AVIF. Komponen Gambar Next.js menggunakan CDN gambar secara default menggunakan arsitektur pemuat. Contoh berikut menunjukkan bahwa pemuat memungkinkan konfigurasi CDN dalam file konfigurasi Next.js.

module.exports = {
  images: {
    loader: 'imgix',
    path: 'https://ImgApp/imgix.net',
  },
}

Dengan konfigurasi ini, developer dapat menggunakan URL relatif di sumber gambar, dan framework akan menggabungkan URL relatif dengan jalur CDN untuk membuat URL absolut. CDN gambar populer seperti Imgix, Cloudinary, dan Akamai didukung. Arsitektur ini mendukung penggunaan penyedia cloud kustom dengan menerapkan fungsi loader kustom untuk aplikasi.

Mendukung image yang dihosting sendiri

Mungkin ada situasi saat situs tidak dapat menggunakan CDN gambar. Dalam kasus tersebut, komponen gambar harus mendukung gambar yang dihosting sendiri. Komponen Gambar Next.js menggunakan pengoptimal gambar sebagai server gambar bawaan yang menyediakan API seperti CDN. Pengoptimal menggunakan Sharp untuk transformasi gambar produksi jika diinstal di server. Library ini adalah pilihan yang tepat bagi siapa saja yang ingin membangun pipeline pengoptimalan gambar sendiri.

Mendukung pemuatan progresif

Pemuatan progresif adalah teknik yang digunakan untuk mempertahankan minat pengguna dengan menampilkan gambar placeholder yang biasanya berkualitas jauh lebih rendah saat gambar sebenarnya dimuat. Hal ini meningkatkan performa yang dirasakan dan meningkatkan pengalaman pengguna. Fitur ini dapat digunakan bersama dengan pemuatan lambat untuk gambar di bawah lipatan atau untuk gambar di atas lipatan.

Komponen Image Next.js mendukung pemuatan progresif untuk gambar melalui properti placeholder. Ini dapat digunakan sebagai LQIP (Placeholder gambar berkualitas rendah) untuk menampilkan gambar berkualitas rendah atau buram saat gambar sebenarnya dimuat.

Dampak

Dengan semua pengoptimalan ini, kami telah melihat keberhasilan dengan komponen Gambar Next.js dalam produksi dan juga bekerja dengan stack teknologi lain pada komponen gambar serupa.

Saat Leboncoin memigrasikan frontend JavaScript lama mereka ke Next.js, mereka juga mengupgrade pipeline gambar mereka untuk menggunakan komponen Next.js Image. Di halaman yang dimigrasikan dari <img> ke next/image, LCP turun dari 2,4 detik menjadi 1,7 detik. Total byte gambar yang didownload untuk halaman tersebut turun dari 663 kB menjadi 326 kB (dengan ~100 kB byte gambar yang dimuat lambat).

Pelajaran yang Diperoleh

Siapa pun yang membuat aplikasi Next.js dapat memanfaatkan penggunaan komponen Gambar Next.js untuk pengoptimalan. Namun, jika Anda ingin membuat abstraksi performa serupa untuk framework atau CMS lain, berikut beberapa pelajaran yang kami peroleh selama proses tersebut yang mungkin berguna.

Katup pengaman dapat menyebabkan lebih banyak kerugian daripada manfaat

Pada rilis awal komponen Next.js Image, kami menyediakan atribut unsized yang memungkinkan developer melewati persyaratan ukuran, dan menggunakan gambar dengan dimensi yang tidak ditentukan. Kami mengira ini akan diperlukan dalam kasus ketika tinggi atau lebar gambar tidak dapat diketahui sebelumnya. Namun, kami melihat pengguna merekomendasikan atribut unsized dalam masalah GitHub sebagai solusi menyeluruh untuk masalah terkait persyaratan ukuran, bahkan dalam kasus di mana mereka dapat menyelesaikan masalah dengan cara yang tidak memperburuk CLS. Selanjutnya, kami menghentikan penggunaan dan menghapus atribut unsized.

Memisahkan hambatan yang berguna dari gangguan yang tidak ada gunanya

Persyaratan untuk mengubah ukuran gambar adalah contoh "hambatan yang berguna". Hal ini membatasi penggunaan komponen, tetapi memberikan manfaat performa yang sangat besar sebagai gantinya. Pengguna akan dengan mudah menerima batasan jika mereka memiliki gambaran yang jelas tentang potensi manfaat performa. Oleh karena itu, ada baiknya menjelaskan kompromi ini dalam dokumentasi dan materi lain yang dipublikasikan tentang komponen tersebut.

Namun, Anda dapat menemukan solusi untuk hambatan tersebut tanpa mengorbankan performa. Misalnya, selama pengembangan komponen Next.js Image, kami menerima keluhan bahwa ukuran gambar yang disimpan secara lokal sulit dicari. Kami menambahkan impor gambar statis, yang menyederhanakan proses ini dengan otomatis mengambil dimensi untuk gambar lokal pada waktu build menggunakan plugin Babel.

Menyeimbangkan fitur kenyamanan dan pengoptimalan performa

Jika komponen gambar Anda tidak melakukan apa pun selain memaksakan "hambatan yang berguna" pada penggunanya, developer cenderung tidak ingin menggunakannya. Kami menemukan bahwa meskipun fitur performa seperti penskalaan gambar dan pembuatan nilai srcset otomatis adalah yang paling penting. Fitur kemudahan yang ditujukan untuk developer seperti pemuatan lambat otomatis dan placeholder buram bawaan juga mendorong minat pada komponen Gambar Next.js.

Menetapkan peta jalan untuk fitur guna mendorong adopsi

Membangun solusi yang berfungsi sempurna untuk semua situasi sangatlah sulit. Mungkin Anda tergoda untuk mendesain sesuatu yang berfungsi baik untuk 75% orang, lalu memberi tahu 25% orang lainnya bahwa "dalam kasus ini, komponen ini tidak cocok untuk Anda".

Dalam praktiknya, strategi ini ternyata bertentangan dengan tujuan Anda sebagai desainer komponen. Anda ingin developer mengadopsi komponen Anda untuk mendapatkan manfaat dari peningkatan performanya. Hal ini sulit dilakukan jika ada sekelompok pengguna yang tidak dapat bermigrasi dan merasa tidak dilibatkan dalam percakapan. Mereka cenderung mengungkapkan kekecewaan, sehingga menimbulkan persepsi negatif yang memengaruhi adopsi.

Sebaiknya Anda memiliki peta jalan untuk komponen yang mencakup semua kasus penggunaan yang wajar dalam jangka panjang. Selain itu, akan lebih baik jika dokumentasi menjelaskan secara eksplisit apa yang tidak didukung dan alasannya untuk menetapkan ekspektasi tentang masalah yang ingin dipecahkan oleh komponen.

Kesimpulan

Penggunaan dan pengoptimalan gambar itu rumit. Developer harus menemukan keseimbangan antara performa dan kualitas gambar sekaligus memastikan pengalaman pengguna yang luar biasa. Hal ini menjadikan pengoptimalan gambar sebagai upaya yang berbiaya tinggi dan berdampak besar.

Daripada setiap aplikasi harus mengulang-ulang proses yang sama, kami membuat template praktik terbaik yang dapat digunakan developer, framework, dan stack teknologi lainnya sebagai referensi untuk penerapan mereka sendiri. Pengalaman ini memang akan terbukti berharga saat kami mendukung framework lain, pada komponen gambar mereka.

Komponen Gambar Next.js telah berhasil meningkatkan hasil performa di aplikasi Next.js, sehingga meningkatkan pengalaman pengguna. Kami yakin bahwa ini adalah model yang bagus dan akan berfungsi dengan baik dalam ekosistem yang lebih luas, dan kami ingin mendengar dari developer yang ingin mengadopsi model ini dalam project mereka.