Mengotomatiskan kompresi dan encoding

Jadikan pembuatan sumber gambar berperforma tinggi sebagai bagian lancar dari proses pengembangan Anda.

Semua sintaksis dalam kursus ini—mulai dari encoding data gambar hingga markup padat informasi yang mendukung gambar responsif—adalah metode bagi mesin untuk berkomunikasi dengan mesin. Anda telah mengetahui beberapa cara yang dapat dilakukan browser klien untuk menyampaikan kebutuhannya ke server, dan server untuk merespons dengan cara yang sama. Markup gambar responsif (khususnya srcset dan sizes) berhasil mendeskripsikan informasi yang sangat banyak dalam jumlah karakter yang relatif sedikit. Baik atau buruk, keringkasan ini dibuat dari desain: membuat sintaksis ini tidak terlalu singkat, dan lebih mudah diurai oleh developer, dapat membuatnya lebih sulit untuk diurai oleh browser. Semakin banyak kompleksitas yang ditambahkan ke string, semakin banyak potensi error parser, atau perbedaan perilaku yang tidak disengaja dari satu browser ke browser lainnya.

Jendela encoding gambar otomatis.

Namun, karakteristik sama yang dapat membuat subjek ini merasa mengintimidasi juga dapat memberi Anda solusi: sintaksis yang mudah dibaca oleh mesin adalah sintaksis yang lebih mudah ditulis oleh mereka. Anda hampir pasti pernah menemukan banyak contoh encoding dan kompresi gambar otomatis sebagai pengguna web: gambar apa pun yang diupload ke web melalui platform media sosial, sistem pengelolaan konten (CMS), dan bahkan program email hampir selalu akan melewati sistem yang mengubah ukuran, mengenkode ulang, dan mengompresinya.

Demikian pula, baik melalui plugin, library eksternal, alat proses build mandiri, atau penggunaan skrip sisi klien yang bertanggung jawab, markup gambar responsif akan mudah digunakan untuk otomatisasi.

Itulah dua masalah utama seputar otomatisasi performa gambar: mengelola pembuatan gambar—encoding, kompresi, dan sumber alternatif yang akan Anda gunakan untuk mengisi atribut srcset—serta pembuatan markup yang ditampilkan kepada pengguna. Dalam modul ini, Anda akan mempelajari beberapa pendekatan umum untuk mengelola gambar sebagai bagian dari alur kerja modern, baik sebagai fase otomatis dalam proses pengembangan, melalui framework atau sistem pengelolaan konten yang mendukung situs Anda, maupun yang hampir sepenuhnya diabstraksi oleh jaringan penayangan konten khusus.

Mengotomatiskan kompresi dan encoding

Anda mungkin tidak memiliki waktu untuk menentukan encoding dan level kompresi yang ideal secara manual untuk setiap gambar yang ditujukan untuk digunakan pada suatu project—Anda juga tidak menginginkannya. Meskipun menjaga ukuran transfer gambar sekecil mungkin , menyesuaikan setelan kompresi dan menyimpan ulang sumber alternatif untuk setiap aset gambar yang ditujukan untuk situs produksi akan menjadi hambatan besar dalam pekerjaan sehari-hari Anda.

Seperti yang telah Anda pelajari saat membaca berbagai format gambar dan jenis kompresi, encoding yang paling efisien untuk gambar akan selalu ditentukan oleh kontennya, dan seperti yang telah Anda pelajari dalam Gambar Responsif, ukuran alternatif yang Anda perlukan untuk sumber gambar akan ditentukan oleh posisi gambar tersebut dalam tata letak halaman. Dalam alur kerja modern, Anda akan melakukan pengambilan keputusan ini secara holistik, bukan secara individual, dengan menentukan serangkaian default yang wajar untuk gambar, agar sesuai dengan konteks penggunaan gambar tersebut.

Saat memilih encoding untuk direktori gambar fotografi, AVIF adalah pemenang yang jelas untuk kualitas dan ukuran transfer, tetapi memiliki dukungan terbatas, WebP menyediakan penggantian modern yang dioptimalkan, dan JPEG adalah default yang paling andal. Ukuran alternatif yang perlu dihasilkan untuk gambar yang dimaksudkan untuk menempati sidebar di tata letak halaman akan sangat berbeda dengan gambar yang dimaksudkan untuk menempati seluruh area pandang browser pada titik henti sementara tertinggi. Setelan kompresi akan mengharuskan pengamatan terhadap artefak kompresi dan pemburaman di beberapa file yang dihasilkan, sehingga memberikan lebih sedikit ruang untuk mengukir setiap byte yang memungkinkan dari setiap gambar sebagai ganti alur kerja yang lebih fleksibel dan andal. Singkatnya, Anda akan mengikuti proses pengambilan keputusan yang sama seperti yang Anda pahami dari materi ini, cukup besar.

Terkait pemrosesan gambar itu sendiri, ada banyak library pemrosesan gambar open source yang menyediakan metode mengonversi, memodifikasi, dan mengedit gambar dalam batch, yang saling bersaing dalam kecepatan, efisiensi, dan keandalan. Library pemrosesan ini akan memungkinkan Anda menerapkan setelan encoding dan kompresi ke seluruh direktori gambar sekaligus, tanpa perlu membuka software pengeditan gambar, dan dengan cara yang mempertahankan sumber gambar asli jika setelan tersebut perlu disesuaikan dengan cepat. Aplikasi tersebut dimaksudkan untuk berjalan dalam berbagai konteks, mulai dari lingkungan pengembangan lokal Anda hingga server web itu sendiri. Misalnya, ImageMin untuk Node.js yang berfokus pada kompresi dapat diperluas agar sesuai dengan aplikasi tertentu melalui array plugin, sementara ImageMagick lintas platform dan Sharp berbasis Node.js dilengkapi dengan sejumlah fitur yang luar biasa.

Library pemrosesan gambar ini memungkinkan developer mem-build alat khusus untuk mengoptimalkan gambar dengan lancar sebagai bagian dari proses pengembangan standar Anda—memastikan project Anda akan selalu mereferensikan sumber gambar yang siap produksi dengan overhead sesedikit mungkin.

Alur kerja dan alat pengembangan lokal

Task runner dan pemaket seperti Grunt, Gulp, atau Webpack dapat digunakan untuk mengoptimalkan aset gambar bersama dengan tugas umum terkait performa lainnya, seperti minifikasi CSS dan JavaScript. Sebagai ilustrasi, mari kita ambil kasus penggunaan yang relatif sederhana: direktori dalam project Anda berisi selusin gambar fotografi, yang dimaksudkan untuk digunakan pada situs yang ditampilkan kepada publik.

Pertama, Anda harus memastikan encoding yang konsisten dan efisien untuk gambar ini. Seperti yang telah Anda pelajari dalam modul sebelumnya, WebP adalah default yang efisien untuk gambar fotografi dalam hal kualitas dan ukuran file. WebP didukung dengan baik, tetapi tidak didukung secara universal, jadi Anda juga ingin menyertakan fallback dalam bentuk JPEG progresif. Kemudian, untuk menggunakan atribut srcset untuk pengiriman aset yang efisien, Anda harus membuat beberapa ukuran alternatif untuk setiap encoding.

Meskipun ini akan menjadi pekerjaan berulang dan memakan waktu jika dilakukan dengan software pengeditan gambar, runner tugas seperti Gulp dirancang untuk mengotomatiskan pengulangan semacam ini. Plugin gulp-responsive, yang memanfaatkan Sharp, adalah salah satu opsi dari banyak opsi yang semuanya mengikuti pola serupa: mengumpulkan semua file di direktori sumber, mengenkode ulang, dan mengompresinya berdasarkan singkatan "kualitas" standar yang sama seperti yang Anda pelajari di Format dan Kompresi Gambar. File yang dihasilkan kemudian dihasilkan ke jalur yang Anda tentukan, yang siap direferensikan dalam atribut src dari elemen img yang dilihat pengguna, tanpa mengubah file asli.

const { src, dest } = require('gulp');
const respimg = require('gulp-responsive');

exports.webp = function() {
  return src('./src-img/*')
    .pipe(respimg({
      '*': [{
        quality: 70,
        format: ['webp', 'jpeg'],
        progressive: true
      }]
  }))
  .pipe(dest('./img/'));
}

Dengan proses seperti ini, tidak ada salahnya akan terjadi pada lingkungan produksi jika seseorang dalam project tidak sengaja menambahkan foto yang dienkode sebagai PNG truecolor besar ke direktori yang berisi sumber gambar asli—terlepas dari encoding gambar aslinya, tugas ini akan menghasilkan WebP yang efisien dan penggantian progressive JPEG yang andal, serta pada tingkat kompresi yang dapat disesuaikan dengan mudah sambil berjalan. Tentu saja, proses ini juga memastikan bahwa file gambar asli Anda akan dipertahankan di dalam lingkungan pengembangan project. Artinya, setelan ini dapat disesuaikan kapan saja dengan hanya output otomatis yang ditimpa.

Untuk menghasilkan beberapa file, Anda meneruskan beberapa objek konfigurasi—semuanya sama, terlepas dari penambahan kunci width dan nilai dalam piksel:

const { src, dest } = require('gulp');
const respimg = require('gulp-responsive');

exports.default = function() {
  return src('./src-img/*')
    .pipe(respimg({
    '*': [{
            width: 1000,
            format: ['jpeg', 'webp'],
            progressive: true,
            rename: { suffix: '-1000' }
            },
            {
            width: 800,
            format: ['jpeg', 'webp'],
            progressive: true,
            rename: { suffix: '-800' }
            },
            {
            width: 400,
            format: ['jpeg', 'webp'],
            progressive: true,
            rename: { suffix: '-400' },
        }]
        })
    )
    .pipe(dest('./img/'));
}

Dalam kasus contoh di atas, gambar asli (monarch.png) lebih dari 3,3 MB. File terbesar yang dihasilkan oleh tugas ini (monarch-1000.jpeg) berukuran sekitar 150 KB. Ukuran terkecil, monarch-400.web, hanya berukuran 32 KB.

[10:30:54] Starting 'default'...
[10:30:54] gulp-responsive: monarch.png -> monarch-400.jpeg
[10:30:54] gulp-responsive: monarch.png -> monarch-800.jpeg
[10:30:54] gulp-responsive: monarch.png -> monarch-1000.jpeg
[10:30:54] gulp-responsive: monarch.png -> monarch-400.webp
[10:30:54] gulp-responsive: monarch.png -> monarch-800.webp
[10:30:54] gulp-responsive: monarch.png -> monarch-1000.webp
[10:30:54] gulp-responsive: Created 6 images (matched 1 of 1 image)
[10:30:54] Finished 'default' after 374 ms

Tentu saja, Anda perlu memeriksa hasilnya dengan cermat untuk menemukan artefak kompresi yang terlihat, atau mungkin meningkatkan kompresi untuk penghematan tambahan. Karena tugas ini tidak merusak, setelan ini dapat diubah dengan mudah.

Dengan begitu, Anda mendapatkan proses yang tidak hanya efisien, tetapi juga tangguh—sebagai alat yang dapat dengan lancar menerapkan pengetahuan Anda tentang aset gambar berperforma tinggi ke seluruh project, tanpa intervensi manual apa pun.

Penerapan markup gambar responsif

Mengisi atribut srcset biasanya akan menjadi proses manual yang mudah, karena atribut tersebut benar-benar hanya mengambil informasi tentang konfigurasi yang telah Anda lakukan saat membuat sumber. Pada tugas di atas, kita telah menetapkan nama file dan informasi lebar yang akan diikuti oleh atribut:

srcset="filename-1000.jpg 1000w, filename-800.jpg 800w, filename-400.jpg 400w"

Ingat bahwa konten atribut srcset bersifat deskriptif, bukan preskriptif. Tidak ada salahnya membebani atribut srcset, selama rasio aspek setiap sumber konsisten. Atribut srcset dapat berisi URI dan lebar setiap potongan alternatif yang dihasilkan oleh server tanpa menyebabkan permintaan yang tidak perlu, dan semakin banyak sumber kandidat yang kami sediakan untuk gambar yang dirender, semakin efisien browser akan dapat menyesuaikan permintaan.

Seperti yang telah Anda pelajari di Gambar Responsif, Anda dapat menggunakan elemen <picture> untuk menangani pola penggantian WebP atau JPEG dengan lancar. Dalam hal ini, Anda akan menggunakan atribut type bersama dengan srcset.

<picture>
  <source type="image/webp" srcset="filename-1000.webp 1000w, filename-800.webp 800w, filename-400.webp 400w">
  <img srcset="filename-1000.jpg 1000w, filename-800.jpg 800w, filename-400.jpg 400w" sizes="…" alt="…">
</picture>

Seperti yang telah Anda pelajari, browser yang mendukung WebP akan mengenali konten atribut type, dan memilih atribut srcset elemen <source> tersebut sebagai daftar kandidat gambar. Browser yang tidak mengenali image/webp sebagai jenis media yang valid akan mengabaikan <source> ini, dan sebagai gantinya menggunakan atribut srcset elemen <img> dalam.

Ada satu pertimbangan lagi dalam hal dukungan browser: browser tanpa dukungan untuk markup gambar responsif tetap akan memerlukan penggantian, atau kami dapat berisiko gambar rusak, terutama dalam konteks penjelajahan lama. Karena <picture>, <source>, dan srcset semuanya diabaikan dalam browser ini, kita akan menentukan sumber default di atribut src <img> bagian dalam.

Karena penskalaan gambar ke bawah secara visual lancar, dan encoding JPEG didukung secara universal, JPEG terbesar merupakan pilihan yang masuk akal.

<picture>
  <source type="image/webp" srcset="filename-1000.webp 1000w, filename-800.webp 800w, filename-400.webp 400w">
  <img src="filename-1000.jpg" srcset="filename-1000.jpg 1000w, filename-800.jpg 800w, filename-400.jpg 400w" sizes="…" alt="…">
</picture>

sizes bisa sedikit lebih sulit untuk ditangani. Seperti yang telah Anda pelajari, sizes bersifat kontekstual. Anda tidak dapat mengisi atribut tanpa mengetahui jumlah ruang yang seharusnya ditempati oleh gambar dalam tata letak yang dirender. Untuk permintaan yang paling efisien, atribut sizes yang akurat harus ada di markup pada saat permintaan tersebut dibuat oleh pengguna akhir, jauh sebelum gaya yang mengatur tata letak halaman diminta. Menghapus sizes sepenuhnya tidak hanya merupakan pelanggaran spesifikasi HTML, tetapi juga menghasilkan perilaku default yang setara dengan sizes="100vw"—memberi tahu browser bahwa gambar ini hanya dibatasi oleh area pandang itu sendiri, sehingga menghasilkan sumber kandidat terbesar yang dapat dipilih.

Seperti halnya dengan tugas pengembangan web yang sangat membebani, sejumlah alat telah dibuat untuk memisahkan proses atribut sizes penulisan tangan. respImageLint adalah cuplikan kode yang sangat penting yang dimaksudkan untuk memeriksa akurasi atribut sizes dan memberikan saran untuk peningkatan. Pratinjau berjalan sebagai bookmarklet—alat yang Anda jalankan di browser, selagi diarahkan ke halaman yang dirender sepenuhnya yang berisi elemen gambar. Dalam konteks ketika browser memiliki pemahaman penuh tentang tata letak halaman, browser juga akan memiliki pemahaman yang hampir sempurna tentang ruang yang seharusnya ditempati oleh gambar dalam tata letak tersebut pada setiap ukuran area pandang yang memungkinkan.

Laporan gambar responsif yang menampilkan ketidakcocokan ukuran/lebar.

Alat untuk analisis lint atribut sizes tentu saja berguna, tetapi memiliki nilai yang lebih tinggi sebagai alat untuk membuatnya secara grosir. Seperti yang Anda ketahui, sintaksis srcset dan sizes dimaksudkan untuk mengoptimalkan permintaan aset gambar dengan cara yang lancar secara visual. Meskipun bukan sesuatu yang harus digunakan dalam produksi, nilai placeholder sizes default dari 100vw sangat wajar saat mengerjakan tata letak halaman di lingkungan pengembangan lokal Anda. Setelah gaya tata letak diterapkan, menjalankan respImageLint akan memberi Anda atribut sizes yang disesuaikan dan dapat Anda salin dan tempel ke markup, dengan tingkat detail yang jauh lebih besar daripada yang ditulis secara manual:

Laporan gambar responsif dengan dimensi yang disarankan.

Meskipun permintaan gambar yang dimulai oleh markup yang dirender server terjadi terlalu cepat bagi JavaScript untuk membuat atribut sizes sisi klien, alasan yang sama tidak berlaku jika permintaan tersebut dimulai dari sisi klien. Project Lazysizes, misalnya, memungkinkan Anda sepenuhnya menunda permintaan gambar hingga tata letak ditetapkan, sehingga JavaScript dapat menghasilkan nilai sizes untuk kami—kenyamanan yang sangat besar bagi Anda, dan jaminan permintaan yang paling efisien bagi pengguna Anda. Namun, perlu diingat bahwa pendekatan ini berarti mengorbankan keandalan markup yang dirender server dan pengoptimalan kecepatan yang ada di browser, dan memulai permintaan ini hanya setelah halaman dirender akan berdampak negatif sangat besar terhadap skor LCP Anda.

Tentu saja, jika Anda sudah bergantung pada framework rendering sisi klien seperti React atau Vue, itu adalah utang yang akan Anda timbulkan—dan dalam kasus tersebut, menggunakan Lazysizes berarti atribut sizes Anda dapat hampir sepenuhnya diabstraksi. Lebih baik lagi: karena sizes="auto" pada gambar yang dimuat lambat mendapatkan konsensus dan implementasi native, Lazysizes akan secara efektif menjadi polyfill untuk perilaku browser yang baru distandardisasi tersebut.