Mecha versi 2.6.4 sudah dirilis!

Foto oleh Kon Karampelas

Pramuat Video YouTube dengan CSS dan JavaScript

Dengan cara mendapatkan gambar sampul video YouTube untuk dijadikan sebagai elemen video tiruan, agar video yang asli dapat dimuat hanya ketika dibutuhkan saja.

Tabel Konten
  1. Membuat Video Tiruan secara Otomatis 
  2. Mengeklik untuk Memuat Video yang Asli 
  3. Kesimpulan 
    1. CSS 
    2. JavaScript 

Menampilkan video YouTube di laman web melalui kode semat akan memuat keseluruhan data pratinjau video. Meskipun tidak semua isi video akan dimuat juga pada saat itu, tapi ketika pengguna menekan tombol pemutar video sekali saja, maka data video akan secara terus-menerus dimuat di latar belakang sampai selesai. Untuk menghentikan proses memuat video di latar belakang hanya bisa dilakukan dengan cara memuat ulang laman web, atau dengan menutup jendela peramban secara keseluruhan.

Struktur kode semat YouTube standar di tahun 2020 sekurang-kurangnya tampak seperti ini. Kode semat ini adalah kode HTML yang akan kalian dapatkan ketika kalian mengeklik-kanan pada video yang sedang diputar untuk memilih “salin kode semat“:

<iframe src="https://www.youtube.com/embed/ufhPvXy2AUk"></iframe>

Untuk mencegah terjadinya proses pemuatan data video di latar belakang, Saya akan mengganti elemen bingkai tersebut menjadi elemen tautan seperti ini:

<a href="https://www.youtube.com/watch?v=ufhPvXy2AUk" target="_blank">
  <svg viewBox="0 0 24 24">
    <path d="M8,5.14V19.14L19,12.14L8,5.14Z"></path>
  </svg>
</a>

Kemudian Saya ubah tampilannya dengan CSS untuk membuatnya tampak seperti video. Saya tambahkan juga sebuah ikon pemutar video di tengah-tengah sebagai indikator bahwa tautan tersebut adalah sebuah video.

Berikut ini adalah kode CSS untuk mengubah tampilan tautan tersebut agar tampak seperti sebuah elemen video:

a {
  display: block;
  position: relative;
  box-sizing: content-box;
  height: 0;
  padding-bottom: 56.25%; /* 16:9 */
  background: #000 none no-repeat 50% 50%;
  background-size: 100% auto;
  color: inherit;
}

a svg {
  fill: #fff;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .25));
  width: 6em;
  height: 6em;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -3em;
  margin-left: -3em;
  opacity: .75;
}

a:focus svg,
a:hover svg {
  opacity: 1;
}

Nilai height Saya atur ke 0 sedangkan nilai padding-bottom Saya atur ke 56.25% untuk memperoleh rasio 16:9. Ini adalah standar dimensi video HD. Video-video lama yang dahulu direkam untuk ditayangkan pada monitor sinar katode mungkin akan memiliki rasio yang berbeda.

Referensi: Display Resolution
TipeRasioLebarTinggi
SD4:31024768
HD16:919201080

Pada CSS, untuk membuat tinggi elemen menyesuaikan rasio lebarnya, metode seperti ini sudah sangat umum digunakan. Rasio sebenarnya tidak begitu penting. Selama ukuran lebar dan tinggi elemen tersebut diketahui, maka untuk mendapatkan nilai padding-bottom bisa dihitung dengan rumus berikut ini:

a {
  --width: 1920px;
  --height: 1080px;
  display: block;
  height: 0;
  padding-bottom: calc((var(--height) / var(--width)) * 100%);
}

Kemudian kita juga perlu menentukan sampul video agar lebih menarik. Gunakan ID video untuk mendapatkan gambar sampul video.

Tautan video YouTube.
Cara mengubah tautan video menjadi gambar sampul video.

Selain default.jpg, beberapa variasi gambar dengan ukuran, klip, dan resolusi yang lain juga tersedia:

  • https://img.youtube.com/vi/ufhPvXy2AUk/default.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/mqdefault.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/hqdefault.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/sddefault.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/maxresdefault.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/0.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/1.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/2.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/3.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/mq1.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/mq2.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/mq3.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/hq1.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/hq2.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/hq3.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/sd1.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/sd2.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/sd3.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/maxres1.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/maxres2.jpg
  • https://img.youtube.com/vi/ufhPvXy2AUk/maxres3.jpg

Setelah itu gunakan tautan gambar tersebut sebagai latar belakang elemen video tiruan:

<a href="https://www.youtube.com/watch?v=ufhPvXy2AUk" style="background-image: url(https://img.youtube.com/vi/ufhPvXy2AUk/1.jpg);" target="_blank"> … </a>

Sampai di sini, elemen video tiruan sebenarnya sudah bisa bekerja. Ketika video tersebut diklik, maka jendela baru akan terbuka untuk memuat laman video YouTube:

Lihat Demo

Tapi karena tujuan kita adalah untuk membuat video menjadi tersemat, rasanya tidak lengkap kalau video tiruan tersebut tidak bisa memuat video yang asli di tempat yang sama.

Terdapat dua tantangan di sini.

Tantangan pertama ada pada masalah teknis. Yaitu mengenai bagaimana cara kita menggunakan JavaScript untuk mengubah elemen video tiruan tersebut menjadi elemen bingkai seperti pada kode semat yang asli. Tantangan yang ke dua ada pada klien. Menyuruh klien untuk menyusun kode HTML video tiruan tersebut secara manual setiap kali ingin menyematkan video YouTube ke dalam artikel itu tidak mungkin. Tidak semua klien tahu tentang cara menulis kode HTML.

Klien biasanya menggunakan aplikasi WYSIWYG untuk menulis artikel. Dalam aplikasi tersebut biasanya juga sudah terdapat semacam fitur untuk mengubah tautan video yang ditempelkan menjadi elemen video YouTube tersemat secara otomatis. Meskipun dalam kasus ini fitur tersebut tidak dikehendaki, tapi setidaknya kita sepakat bahwa menyuruh klien untuk menyematkan tautan video seperti tampak pada gambar di bawah ini tidaklah sulit:

Menyunting artikel dengan CKEditor 5.
Tautan video YouTube sebagai paragraf baru.

Membuat Video Tiruan secara Otomatis 

Sebuah mekanisme untuk mengubah tautan-tautan video menjadi elemen video sangat diperlukan di sini, karena tidak semua klien tahu tentang bagaimana cara menyusun kode HTML. Bahkan kita sendiri yang sudah terbiasa melakukan itu setiap hari saja masih sering merasa malas untuk membuatnya secara manual.

Untuk membuat video tiruan secara otomatis melalui tautan video, pertama-tama kita perlu menentukan kriteria tautan seperti apa yang ideal untuk diubah menjadi video tiruan secara otomatis:

  1. Tautan harus mengarah ke laman video YouTube dan mengandung ID video di dalamnya.
  2. Tautan harus berdiri sendiri di dalam paragraf, tanpa ada elemen dan teks lain di sekelilingnya.

Dengan JavaScript, kita bisa menyeleksi tautan-tautan yang ada sesuai dengan kriteria di atas menggunakan selektor berikut ini:

let links = document.querySelectorAll('p > a:only-child');

Kemudian kita buat selektor tersebut menjadi lebih spesifik lagi seperti ini agar dapat menyeleksi tautan-tautan yang hanya mengandung teks “youtube.com” di dalamnya:

let links = document.querySelectorAll('p > a[href*="youtube.com"]:only-child');

Sebagai catatan, selektor :only-child pada CSS tidak peduli dengan teks. Sebuah elemen tautan yang berdiri sendiri di dalam paragraf, meskipun di sekitarnya terdapat teks, akan tetap dianggap sebagai satu-satunya anak elemen dari paragraf tersebut. Untuk itu kita perlu mengecek kerabat-kerabat di sekitar elemen tautan tersebut. Jika tidak terdapat kerabat atau terdapat beberapa kerabat namun hanya berupa karakter spasi, maka kita anggap elemen tautan tersebut sebagai elemen yang berdiri sendiri:

links = [...links].filter(link => {
    let next = link.nextSibling,
        previous = link.previousSibling;
    // Abaikan karakter spasi di sekitar elemen tautan
    if (next && 3 === next.nodeType && "" === next.nodeValue.trim()) {
        next = false;
    }
    if (previous && 3 === previous.nodeType && "" === previous.nodeValue.trim()) {
        previous = false;
    }
    return !next && !previous;
});

Kita mungkin juga perlu mengecek pola tautan yang ada, untuk memastikan bahwa tautan tersebut mengandung ID video. Berikut ini adalah beberapa format tautan video YouTube yang paling umum digunakan dan disalin-tempel oleh pengguna:

  • https://youtu.be/ufhPvXy2AUk
  • https://www.youtube.com/embed/ufhPvXy2AUk
  • https://www.youtube.com/watch?v=ufhPvXy2AUk
function isYouTubeLink(url) { /* … */ }

links = [...links].filter(link => {
    // …
    return isYouTubeLink(link.href) && !next && !previous;
});

Tapi itu bisa dikembangkan nanti. Sekarang kita fokus ke pembuatan elemen video tiruannya saja dulu.

Setelah menyeleksi elemen-elemen tautan yang ada sesuai dengan kriteria, sekarang kita buat sebuah fungsi untuk mendapatkan ID video dari tautan. Fungsi ini berlaku untuk format tautan yang ke tiga saja. Untuk bisa mendapatkan ID video dari format-format tautan yang lain perlu dilakukan pengembangan lebih lanjut:

function getYouTubeID(url) {
    return (url.split(/[?&]v=/)[1] || "").split('&')[0];
}

Kemudian kita iterasikan semua elemen tautan yang ada. Tambahkan kelas lazy-youtube-video pada masing-masing elemen, dan atur latar gambar pada elemen tersebut sebagai tautan gambar yang berhasil dibentuk dari ID video yang didapatkan:

links.forEach(link => {
    let id = getYouTubeID(link.href);
    if (id) {
        link.classList.add('lazy-youtube-video');
        link.innerHTML = '<svg viewBox="0 0 24 24"><path d="M8,5.14V19.14L19,12.14L8,5.14Z"></path></svg>';
        link.style.backgroundImage = 'url(https://img.youtube.com/vi/' + id + '/default.jpg)';
    }
});

Selektor CSS sebelumnya juga perlu diubah untuk menyesuaikan, agar target menjadi lebih spesifik:

.lazy-youtube-video { /* … */ }
.lazy-youtube-video svg { /* … */ }
.lazy-youtube-video:focus svg,
.lazy-youtube-video:hover svg { /* … */ }

Mengeklik untuk Memuat Video yang Asli 

Muat video yang asli ketika pengguna mengeklik elemen video tiruan tersebut. Di sini Saya menggunakan elemen <ins> sebagai wadah untuk elemen <iframe> yang akan memuat video yang asli nantinya. Saya membuat elemen tersebut di luar fungsi agar tidak terjadi duplikat, sehingga elemen video yang asli dapat dimuat secara bergantian, bukan secara bersamaan:

const video = document.createElement('ins');

video.classList.add('lazy-youtube-video');

Kemudian kita buat sebuah fungsi untuk menyisipkan elemen video di atas untuk menggantikan elemen-elemen video tiruan yang ada. Tambahkan juga kueri ?autoplay=1 pada sumber bingkai untuk memainkan video secara otomatis ketika berhasil dimuat, agar pengguna tidak perlu mengeklik tombol pemutar video sebanyak dua kali (klik yang pertama untuk memuat video yang asli, klik yang ke dua untuk memutar video yang asli):

function insertYouTubeVideo(event) {
    video.innerHTML = '<iframe src="https://www.youtube.com/embed/' + getYouTubeID(this.href) + '?autoplay=1"></iframe>';
    // Sisipkan elemen video yang asli sebelum elemen video tiruan
    this.parentNode.insertBefore(video, this);
    event.preventDefault();
}
/* Sembunyikan elemen video tiruan yang hadir setelah elemen video yang asli */
ins.lazy-youtube-video + a.lazy-youtube-video {
  display: none;
}

Eksekusi fungsi tersebut ketika pengguna mengeklik elemen video tiruan:

links.forEach(link => {
    // …
    link.addEventListener('click', insertYouTubeVideo);
});

Kesimpulan 

Kesimpulan dari kode-kode yang telah Saya jelaskan di atas adalah seperti ini:

CSS 

.lazy-youtube-video {
  display: block;
  position: relative;
  box-sizing: content-box;
  height: 0;
  padding-bottom: 56.25%; /* 16:9 */
  background: #000 none no-repeat 50% 50%;
  background-size: 100% auto;
  color: inherit;
}

.lazy-youtube-video iframe {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  border: 0;
}

.lazy-youtube-video svg {
  fill: #fff;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .25));
  width: 6em;
  height: 6em;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -3em;
  margin-left: -3em;
  opacity: .75;
}

.lazy-youtube-video:focus svg,
.lazy-youtube-video:hover svg {
  opacity: 1;
}

/* Sembunyikan elemen video tiruan yang hadir setelah elemen video yang asli */
ins.lazy-youtube-video + a.lazy-youtube-video {
  display: none;
}

JavaScript 

// Seleksi semua elemen tautan yang berdiri sendiri di dalam paragraf
// yang mengandung atribut `href` dengan nilai yang mengandung kata `youtube.com`
let links = document.querySelectorAll('p > a[href*="youtube.com"]:only-child');

// Pastikan juga bahwa tidak terdapat teks-teks lain di sekitar elemen tautan
// kecuali beberapa karakter spasi atau tidak sama sekali 
links = [...links].filter(link => {
    let next = link.nextSibling,
        previous = link.previousSibling;
    // Abaikan karakter spasi di sekitar elemen tautan
    if (next && 3 === next.nodeType && "" === next.nodeValue.trim()) {
        next = false;
    }
    if (previous && 3 === previous.nodeType && "" === previous.nodeValue.trim()) {
        previous = false;
    }
    return !next && !previous;
});

// Berlaku untuk format tautan `https://www.youtube.com/watch?v=***********`
function getYouTubeID(url) {
    return (url.split(/[?&]v=/)[1] || "").split('&')[0];
}

// Buat wadah untuk memuat video yang asli
const video = document.createElement('ins');

// Tambahkan kelas yang sama seperti kelas pada elemen video tiruan
video.classList.add('lazy-youtube-video');

function insertYouTubeVideo(event) {
    video.innerHTML = '<iframe src="https://www.youtube.com/embed/' + getYouTubeID(this.href) + '?autoplay=1"></iframe>';
    // Sisipkan elemen video yang asli sebelum elemen video tiruan
    this.parentNode.insertBefore(video, this);
    event.preventDefault();
}

links.forEach(link => {
    let id = getYouTubeID(link.href);
    if (id) {
        link.classList.add('lazy-youtube-video');
        link.innerHTML = '<svg viewBox="0 0 24 24"><path d="M8,5.14V19.14L19,12.14L8,5.14Z"></path></svg>';
        link.style.backgroundImage = 'url(https://img.youtube.com/vi/' + id + '/default.jpg)';
        link.addEventListener('click', insertYouTubeVideo);
    }
});

Fitur pramuat video YouTube di atas masih bisa dikembangkan lagi, terutama untuk bisa menerima format-format tautan alternatif video YouTube yang lain. Berbagai variasi ukuran gambar sampul video juga memungkinkan pengembang untuk memuat sampul video secara efisien dengan menyesuaikan lebar layar yang sedang digunakan oleh pengguna. Sebagai contoh, ketika pengguna menggunakan layar monitor berukuran besar, maka gambar sampul video yang akan dimuat adalah sddefault.jpg, sedangkan ketika pengguna menggunakan layar monitor berukuran kecil, maka gambar sampul yang akan dimuat adalah mqdefault.jpg:

Lihat Demo

5 Komentar

Beat M4A

Keren nih ilmu nya, jadi pengen nyoba.. Aku udh pakai yang sejenis sih.

Adhy Suryadi

Ke depannya akan lebih sederhana lagi setelah semua browser benar-benar mendukung lazy load loading="lazy" seperti pada browser dengan basik Chromium yang bekerja untuk image dan iframe ya mas.

Taufik Nurrohman

Iya, pakai itu juga bisa. Cuma dari segi estetika menurut Saya kurang menarik. Sangat jelas kalau video yang dimuat itu berasal dari YouTube. Kalau dulu, sebelum YouTube dibeli oleh Google (dan sebelum pembaruan Adobe Flash Player dihentikan), kita masih bisa mengatur tampilan video semat, seperti untuk mengatur garis batas dan warna-warna pada kontrol video. Kalau sekarang tidak bisa.

Komentar telah ditutup.