Membuat Komponen Gambar yang efektif

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

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

Gambar merupakan sumber umum bottleneck performa untuk aplikasi web dan area fokus utama untuk pengoptimalan. Gambar yang tidak dioptimalkan berkontribusi pada penggelembungan halaman dan saat ini menyumbang lebih dari 70% total berat halaman dalam byte pada persentil ke-90. Berbagai cara untuk mengoptimalkan gambar memerlukan "komponen gambar" cerdas dengan solusi performa yang diintegrasikan sebagai default.

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

Komponen gambar sebagai ekstensi gambar

Masalah dan peluang pengoptimalan gambar

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

Gambar yang tidak berukuran mengganggu CLS

Gambar yang ditayangkan tanpa menentukan ukurannya dapat menyebabkan ketidakstabilan tata letak dan berkontribusi pada Pergeseran Tata Letak Kumulatif (CLS) yang tinggi. Menyetel 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 disetel sedemikian rupa sehingga rasio aspek gambar yang dirender mendekati rasio aspek naturalnya. Perbedaan rasio aspek yang signifikan dapat menyebabkan gambar tampak terdistorsi. Properti yang relatif baru dan memungkinkan Anda menentukan rasio aspek di CSS dapat membantu mengukur gambar secara responsif sekaligus mencegah CLS.

Gambar besar dapat merusak LCP

Semakin besar ukuran file gambar, semakin lama waktu yang dibutuhkan untuk mendownload. Gambar besar dapat berupa gambar "utama" untuk halaman atau elemen paling signifikan di area pandang yang berperan 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 elemen <img> membantu menyediakan file gambar dengan ukuran yang berbeda. Selanjutnya browser dapat memilih yang tepat bergantung pada ukuran dan resolusi layar.

Kompresi gambar yang buruk dapat merusak LCP

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

Memuat gambar yang tidak diperlukan dapat merusak LCP

Gambar di paruh bawah atau tidak di area pandang tidak ditampilkan kepada pengguna saat halaman dimuat. Proses ini dapat ditangguhkan sehingga tidak berkontribusi pada LCP dan menundanya. Pemuatan lambat dapat digunakan untuk memuat gambar tersebut nanti saat pengguna men-scroll ke gambar tersebut.

Tantangan pengoptimalan

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

  • Prioritas: Developer web biasanya cenderung berfokus pada kode, JavaScript, dan pengoptimalan data. Dengan demikian, mereka mungkin tidak mengetahui adanya masalah dengan gambar atau cara mengoptimalkannya. Gambar yang dibuat oleh desainer atau yang diupload oleh pengguna mungkin tidak termasuk dalam daftar prioritas.
  • Solusi siap pakai: Meskipun developer mengetahui perbedaan pengoptimalan gambar, tidak adanya solusi siap pakai untuk framework atau tech-stack dapat menjadi penghalang.
  • Gambar dinamis: Selain gambar statis yang merupakan bagian dari aplikasi, gambar dinamis diupload oleh pengguna atau bersumber dari database eksternal atau CMS. Menentukan ukuran gambar semacam itu mungkin akan sulit jika sumber gambarnya dinamis.
  • Kelebihan markup: Solusi untuk menyertakan ukuran gambar atau srcset untuk ukuran yang berbeda memerlukan markup tambahan untuk setiap gambar, dan hal ini dapat merepotkan. Atribut srcset diperkenalkan pada tahun 2014, tetapi hanya digunakan oleh 26,5% situs saat ini. 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.
  • Detail pemuatan lambat: Ada beberapa teknik dan library yang tersedia untuk menerapkan pemuatan lambat untuk gambar paruh bawah. Memilih yang terbaik terkadang sulit dilakukan. Developer mungkin juga tidak mengetahui jarak terbaik dari "lipatan" untuk memuat gambar yang ditangguhkan. Ukuran area pandang yang berbeda pada perangkat dapat semakin mempersulit hal ini.
  • Mengubah lanskap: Karena browser mulai mendukung fitur HTML atau CSS baru untuk meningkatkan performa, developer mungkin akan kesulitan untuk mengevaluasi setiap fitur tersebut. Misalnya, Chrome memperkenalkan fitur Prioritas Pengambilan sebagai Uji Coba Origin. Fungsi 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 image sebagai solusi

Peluang yang tersedia untuk mengoptimalkan gambar dan tantangan dalam mengimplementasikannya satu per satu untuk setiap aplikasi mengantarkan kami pada ide tentang komponen gambar. Komponen gambar dapat mencakup 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 menggunakan framework Next.js untuk mendesain dan implement komponen Image mereka. 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 beragam fitur dan prinsip. API ini juga menyertakan opsi yang memungkinkan developer menyesuaikannya untuk berbagai persyaratan gambar.

Perlindungan dari pergeseran tata letak

Seperti yang telah dibahas sebelumnya, gambar yang tidak berukuran menyebabkan pergeseran tata letak dan berkontribusi pada CLS. Saat menggunakan komponen Image Next.js, developer harus memberikan ukuran gambar menggunakan atribut width dan height untuk mencegah pergeseran tata letak. Jika ukurannya tidak diketahui, developer harus menentukan layout=fill untuk menayangkan gambar tidak berukuran yang berada di dalam container berukuran tersebut. 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 Image tanpa ukuran, desain memastikan bahwa mereka akan meluangkan waktu untuk mempertimbangkan ukuran gambar dan mencegah pergeseran tata letak.

Memfasilitasi responsivitas

Agar gambar menjadi responsif di seluruh perangkat, developer harus menetapkan atribut srcset dan sizes di elemen <img>. Kami ingin mengurangi upaya ini dengan komponen Image. 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 memberikan solusi tiga bagian:

  1. Properti deviceSizes: Properti ini dapat digunakan untuk mengonfigurasi titik henti sementara satu kali berdasarkan perangkat yang umum digunakan pada basis pengguna aplikasi. Nilai default untuk titik henti sementara disertakan di 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: 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 untuk ditayangkan berdasarkan ukuran perangkat yang meminta halaman dan menyetel srcset dan sizes pada gambar dengan tepat.

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

Layar laptop Layar ponsel
Tata Letak = Intrinsik: Diperkecil agar sesuai dengan lebar penampung pada area pandang yang lebih kecil. Tidak meningkatkan ukuran di luar ukuran intrinsik gambar pada area pandang yang lebih besar. Lebar penampung sebesar 100%
Gambar pegunungan ditampilkan sebagaimana adanya Gambar pegunungan yang diperkecil
Tata Letak = Diperbaiki: Gambar tidak responsif. Lebar dan tinggi tetap serupa dengan elemen ``, terlepas dari perangkat tempatnya dirender.
Gambar pegunungan ditampilkan sebagaimana adanya Gambar pegunungan yang ditampilkan tidak sesuai dengan layar
Tata Letak = Responsif: Perkecil atau tingkatkan skala bergantung pada lebar penampung di area pandang yang berbeda, dengan tetap mempertahankan rasio aspek.
Gambar pegunungan yang ditingkatkan skalanya agar sesuai dengan layar Gambar pegunungan yang diperkecil agar sesuai dengan layar
Tata Letak = Isi: Lebar dan tinggi direntangkan untuk mengisi penampung induk. (Induk `
` lebar ditetapkan menjadi 300*500 dalam contoh ini)
Gambar pegunungan dirender agar sesuai dengan ukuran 300*500 Gambar pegunungan 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 baik sebagai default. Saat menggunakan elemen <img>, ada beberapa opsi native untuk pemuatan lambat, tetapi semuanya memiliki kelemahan yang membuatnya sulit digunakan. Developer mungkin menggunakan salah satu pendekatan pemuatan lambat berikut:

  • Tentukan atribut loading: Atribut ini mudah diterapkan, tetapi saat ini tidak didukung di beberapa browser.
  • Gunakan Intersection Observer API: Membuat solusi pemuatan lambat kustom memerlukan upaya serta desain dan implementasi yang cermat. Developer mungkin tidak selalu punya waktu untuk hal ini.
  • Impor library pihak ketiga ke pemuatan gambar dengan lambat: Mungkin diperlukan upaya tambahan untuk mengevaluasi dan mengintegrasikan library pihak ketiga yang sesuai untuk pemuatan lambat.

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

Pramuat gambar penting

Sering kali, elemen LCP berupa gambar, dan gambar yang besar dapat menunda LCP. Sebaiknya pramuat gambar penting agar browser dapat menemukan gambar tersebut lebih cepat. Saat menggunakan elemen <img>, petunjuk pramuat dapat disertakan di head HTML sebagai berikut.

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

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

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

Menambahkan atribut priority akan menyederhanakan markup dan lebih mudah digunakan. Developer komponen gambar juga dapat mempelajari opsi untuk menerapkan heuristik guna mengotomatiskan pramuat untuk gambar paruh atas di halaman yang memenuhi kriteria tertentu.

Dorong 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 loader. Contoh berikut menunjukkan bahwa loader mengizinkan konfigurasi CDN di 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 menghasilkan 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 gambar yang dihosting sendiri

Mungkin ada situasi di mana 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 mirip CDN. Pengoptimal menggunakan Sharp untuk transformasi gambar produksi jika diinstal di server. Library ini adalah pilihan tepat bagi siapa saja yang ingin membangun pipeline pengoptimalan gambarnya sendiri.

Mendukung pemuatan progresif

Pemuatan progresif adalah teknik yang digunakan untuk mempertahankan minat pengguna dengan menampilkan gambar placeholder yang biasanya memiliki kualitas jauh lebih rendah sedangkan gambar sebenarnya dimuat. Meningkatkan kinerja yang dirasakan dan pengalaman pengguna yang lebih baik. Hal ini dapat digunakan bersama dengan pemuatan lambat untuk gambar paruh bawah atau untuk gambar paruh atas.

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

Dampak

Dengan menerapkan semua pengoptimalan di atas, kami telah meraih keberhasilan dengan komponen Image Next.js dalam produksi dan juga bekerja dengan tech stack lainnya pada komponen gambar yang serupa.

Saat Leboncoin memigrasikan frontend JavaScript lamanya ke Next.js, mereka juga mengupgrade pipeline gambarnya untuk menggunakan komponen Image Next.js. Pada halaman yang dimigrasikan dari <img> ke gambar berikutnya/gambar, LCP turun dari 2,4 detik menjadi 1,7 detik. Total byte gambar yang didownload untuk halaman tersebut berubah 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 memperoleh manfaat dari 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 pelajari yang dapat membantu.

Katup pengaman dapat menyebabkan lebih banyak bahaya daripada baik

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

Pisahkan gesekan yang berguna dari gangguan yang tidak ada gunanya

Persyaratan untuk mengubah ukuran gambar adalah contoh "friksi yang berguna". Membatasi penggunaan komponen, tetapi memberikan manfaat performa yang besar sebagai imbalannya. Pengguna akan dengan mudah menerima batasan tersebut jika mereka memiliki gambaran yang jelas tentang potensi manfaat performa. Oleh karena itu, ada baiknya untuk 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 mencari ukuran gambar yang disimpan secara lokal terasa mengganggu. Kami menambahkan impor gambar statis, yang menyederhanakan proses ini dengan mengambil dimensi untuk gambar lokal secara otomatis pada waktu build menggunakan plugin Babel.

Menyeimbangkan antara fitur praktis dan pengoptimalan performa

Jika komponen image Anda tidak melakukan apa pun selain menimbulkan "friksi yang berguna" pada penggunanya, developer akan cenderung tidak ingin menggunakannya. Kami mendapati bahwa meskipun fitur performa seperti ukuran gambar dan pembuatan nilai srcset otomatis adalah yang paling penting. Fitur praktis yang ditampilkan kepada developer seperti pemuatan lambat otomatis dan placeholder buram bawaan juga mendorong minat terhadap komponen Image Next.js.

Menetapkan roadmap bagi fitur untuk mendorong adopsi

Membuat solusi yang berfungsi sempurna untuk segala situasi adalah hal yang sangat sulit. Mungkin tergoda untuk merancang sesuatu yang bekerja dengan baik untuk 75% orang dan kemudian memberi tahu 25% yang lain bahwa "dalam kasus ini, komponen ini bukan untuk Anda."

Dalam praktiknya, strategi ini ternyata bertentangan dengan tujuan Anda sebagai desainer komponen. Anda ingin developer mengadopsi komponen Anda agar mendapatkan manfaat dari performanya. Hal ini sulit dilakukan jika ada sejumlah pengguna yang tidak dapat bermigrasi dan merasa tidak terlibat dalam percakapan. Mereka cenderung mengungkapkan kekecewaan, yang mengarah ke persepsi negatif yang memengaruhi penggunaan aplikasi.

Sebaiknya Anda memiliki roadmap untuk komponen Anda yang mencakup semua kasus penggunaan yang wajar dalam jangka panjang. Hal ini juga membantu untuk memperjelas dalam dokumentasi tentang apa yang tidak didukung dan mengapa untuk menetapkan ekspektasi tentang masalah yang dimaksudkan untuk dipecahkan.

Kesimpulan

Penggunaan dan pengoptimalan gambar merupakan hal yang rumit. Developer harus bisa menyeimbangkan antara performa dan kualitas gambar, sekaligus memastikan pengalaman pengguna yang bagus. Oleh karena itu, pengoptimalan gambar merupakan upaya yang hemat biaya dan berdampak tinggi.

Alih-alih membuat setiap aplikasi melakukan semuanya dari awal, kami membuat template praktik terbaik yang dapat digunakan developer, framework, dan tech-stack lainnya sebagai referensi untuk implementasi mereka sendiri. Pengalaman ini tentu akan bermanfaat karena kami mendukung framework lain, pada komponen image mereka.

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