Iframe terlihat mudah dipakai, sehingga batasnya sering baru terasa saat halaman berperilaku aneh: widget kosong, skrip gagal membaca dokumen sematan, atau halaman melambat. Semua gejala itu berpijak pada aturan yang sama — dokumen sematan tetap dokumen terpisah dengan aturan keamanannya sendiri. Chapter ini merangkum batasan utamanya — same-origin policy, penolakan dari pemilik situs lain, dan biaya kinerja — beserta mitigasinya.
Same-Origin Policy: Dokumen Tetap Terpisah #
Same-origin policy adalah aturan keamanan inti browser: sebuah dokumen hanya boleh membaca dan mengubah DOM dokumen lain bila keduanya ber-asal sama, dengan origin sebagai kombinasi protokol, domain, dan port. Dokumen di dalam iframe membawa origin sendiri, dihitung dari URL src-nya. Bila origin itu berbeda dari origin halaman induk, skrip halaman induk tidak dapat menjangkau DOM dokumen sematan, dan sebaliknya. Isolasi ini dirancang sengaja: tanpa aturan itu, halaman sembarang dapat membaca isi situs lain di tab sampingnya.
Sandbox pada chapter sebelumnya bekerja di garis yang sama: tanpa allow-same-origin, dokumen sematan memakai origin unik sehingga terisolasi total, bahkan dari server yang sama sekalipun. Komunikasi tetap mungkin lewat API khusus seperti postMessage yang menyerahkan pertukaran data kepada kode kedua pihak. Untuk keperluan course ini, poin pentingnya satu: menyematkan bukan berarti berbagi.
Situs Lain Dapat Menolak Di-embed #
Batas berikutnya datang dari pemilik situs yang disematkan. Server dapat menyertakan header yang memerintahkan browser menolak dokumennya di dalam frame: X-Frame-Options dengan nilai DENY (tolak semua origin) atau SAMEORIGIN (hanya origin yang sama), serta directive frame-ancestors pada CSP (Content Security Policy) yang aturannya lebih rinci. Bila perintah itu berlaku, browser menolak menampilkan dokumen tersebut; yang tersisa pesan penolakan atau area kosong. Inilah penjelasan bila sebuah sematan tampak kosong padahal URL-nya benar — situs sengaja menolak di-embed, umumnya untuk mencegah serangan clickjacking.
Contoh header respons dari server www.example.com:
X-Frame-Options: DENY
Versi CSP: hanya origin yang sama yang boleh menyematkan
Content-Security-Policy: frame-ancestors 'self'frame-ancestors menggantikan X-Frame-Options pada browser modern dan menerima daftar origin, misalnya frame-ancestors 'self' www.example.com. Sebagai penulis HTML, tidak ada atribut yang meniadakan header ini; satu-satunya jalan adalah memakai URL embed resmi yang disediakan situs tersebut. Platform yang membolehkan penyematan biasanya menyiapkan halaman khusus untuk itu, seperti URL pemutar video dan URL peta pada chapter-chapter sebelumnya.
Biaya Kinerja dan Cara Menekannya #
Setiap sematan menambah pemuatan: permintaan HTTP baru, dokumen yang diurai ulang, dan skrip yang berjalan di thread-nya sendiri. Event load halaman induk menunggu seluruh iframe tanpa lazy selesai, sehingga indikator pemuatan ikut memanjang. Mitigasinya telah kita pegang sepanjang section ini: sematan dibuat sedikit, ukuran dibuat tetap agar layout stabil, loading="lazy" untuk yang jauh dari layar, dan sandbox agar risikonya terkendali. Tabel berikut merangkum seluruh batas beserta jawabannya:
| Batas | Dampak | Mitigasi |
|---|---|---|
| Same-origin policy | skrip tidak menjangkau DOM lintas origin | rancang halaman agar tidak bergantung pada pembacaan dokumen sematan; komunikasi lewat API seperti postMessage |
Header anti-embed (X-Frame-Options, frame-ancestors) | dokumen menolak tampil; area kosong | pakai URL embed resmi dari penyedia konten; sediakan tautan cadangan |
| Biaya pemuatan dokumen penuh | halaman lambat; event load tertunda | batasi jumlah iframe, gunakan loading="lazy", tetapkan ukuran |
| Risiko kode pihak ketiga | skrip sematan berjalan di browser pengunjung | sandbox dengan token minimum |
Contoh Lengkap dalam Satu File #
File penutup section ini menyatukan mitigasi tadi pada satu halaman artikel: widget cuaca dengan lazy, sandbox minimal, dan tautan cadangan:
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Berita dan Cuaca</title>
</head>
<body>
<h1>Suara Warung — Edisi Pekan Ini</h1>
<article>
<h2>Kunjungan Budi ke kebun bibit</h2>
<p>Budi membagikan catatan kunjungannya ke kebun bibit di luar kota.</p>
</article>
<iframe src="www.example.com/widget/cuaca?kota=bandung" title="Prakiraan cuaca Bandung" width="360" height="200" loading="lazy" sandbox="allow-scripts"></iframe>
<p>Widget gagal tampil? <a href="www.example.com/cuaca/bandung">Buka halaman cuaca secara langsung</a>.</p>
</body>
</html>Output yang Dihasilkan:
Jendela browser menampilkan:
- Judul "Suara Warung — Edisi Pekan Ini"
- Artikel kunjungan Budi tampil lebih dulu
- Widget cuaca 360x200 di akhir halaman, dimuat saat pengunjung mendekat
- Tautan cadangan "Buka halaman cuaca secara langsung" di bawah widgetMari kita bedah baris-baris pentingnya:
- Baris 10-13 (
article): konten milik kita sendiri ditulis lebih dulu, sehingga artikel utama tidak menunggu widget. - Baris 14 (
loading="lazy"): widget berada di akhir halaman, sehingga pemuatannya ditunda sampai pengunjung mendekat. - Baris 14 (
sandbox="allow-scripts"): widget boleh menjalankan skripnya, tetapi tanpa origin asli, popup, formulir, dan navigasi halaman induk. - Baris 15 (tautan cadangan): bila pemilik widget menolak di-embed atau widget gagal, pengunjung tetap menjangkau datanya.
Dengan chapter ini section Embedded Content menutup tirainya: kita dapat menyematkan, menamai, membatasi, dan memahami batas yang tidak dapat ditawar. Section berikutnya, SVG dan Graphics, membawa kita ke arah yang berbeda — menggambar grafik vektor langsung dari markup HTML sendiri, bukan dari dokumen lain.
Referensi resmi untuk pendalaman:
- MDN Web Docs — Same-origin policy
- MDN Web Docs — Header X-Frame-Options
- MDN Web Docs — CSP: frame-ancestors
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
contoh-batasan.html
Unduh berkas<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Berita dan Cuaca</title>
</head>
<body>
<h1>Suara Warung — Edisi Pekan Ini</h1>
<article>
<h2>Kunjungan Budi ke kebun bibit</h2>
<p>Budi membagikan catatan kunjungannya ke kebun bibit di luar kota.</p>
</article>
<iframe src="www.example.com/widget/cuaca?kota=bandung" title="Prakiraan cuaca Bandung" width="360" height="200" loading="lazy" sandbox="allow-scripts"></iframe>
<p>Widget gagal tampil? <a href="www.example.com/cuaca/bandung">Buka halaman cuaca secara langsung</a>.</p>
</body>
</html>