基本設定
iframe要素には、コンテンツのURLを指定するsrc属性と、コンテンツの概要を示すtitle属性が必要です。title属性は、アクセシビリティの観点から必須とされます。
<iframe
  src="https://example.com"
  width="800"
  height="600"
  title="外部コンテンツの概要"
  loading="lazy"
  sandbox="allow-scripts"
  allow="geolocation 'none'">
</iframe>レスポンシブ対応
iframeのサイズをビューポートに応じて変更するには、CSSを使用します。アスペクト比を維持する場合、以下の手法が用いられます。
.iframe-container {
  position: relative;
  width: 100%;
  height: 0;
  padding-bottom: 56.25%; /* アスペクト比 16:9 */
}
.iframe-container iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}同一オリジンポリシー
同一オリジンポリシーは、ブラウザのセキュリティモデルの基本原則です。オリジン(プロトコル、ホスト、ポートの組み合わせ)が異なるリソース間のアクセスは、原則として制限されます。
同一オリジン間のアクセス
親ページとiframeが同一オリジンの場合、親ページのスクリプトはiframe内のDOMにアクセスできます。
const iframe = document.getElementById('myIframe');
const iframeDoc = iframe.contentDocument;
const heading = iframeDoc?.querySelector('h1');
if (heading) {
  heading.textContent = '親ページからの変更';
}異なるオリジン間の通信
オリジンが異なる場合、DOMへの直接アクセスはできません。通信にはpostMessage APIを使用します。
// 親から子への送信
const iframe = document.getElementById('myIframe');
iframe.contentWindow?.postMessage('データ', 'https://trusted-domain.com');
// 子での受信
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://trusted-domain.com') {
    return;
  }
  console.log(event.data);
});sandbox属性
sandbox属性は、iframe内のコンテンツが使用できる機能を制限します。属性値を空にすると、スクリプト実行、フォーム送信、ポップアップ表示などの機能がブロックされます。
| オプション | 説明 | 
|---|---|
| allow-scripts | JavaScriptの実行を許可する | 
| allow-forms | フォームの送信を許可する | 
| allow-popups | ポップアップの作成を許可する | 
| allow-same-origin | コンテンツを同一オリジンとして扱う | 
allow-scriptsとallow-same-originを同時に指定すると、埋め込みコンテンツはsandboxの制約を回避できるため、この組み合わせは使用しないでください。
セキュリティヘッダー
HTTPヘッダーによってもiframeの挙動は制御されます。
- X-Frame-Options: DENYまたはSAMEORIGINを指定し、ページがiframe内に表示されることを制御します。
- Content-Security-Policy (CSP): frame-srcディレクティブでiframeとして読み込めるソースを、frame-ancestorsディレクティブでページを埋め込める親ページを指定します。
遅延読み込み
loading="lazy"属性を指定すると、iframeがビューポートに近づくまで読み込みが遅延されます。
<iframe src="..." loading="lazy"></iframe>Intersection Observer APIを使えば、遅延読み込みを細かく制御できます。
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const iframe = entry.target;
      iframe.src = iframe.dataset.src;
      observer.unobserve(iframe);
    }
  });
});
document.querySelectorAll('iframe[data-src]').forEach(iframe => {
  observer.observe(iframe);
});推奨設定
以下は、セキュリティを考慮したiframeの推奨設定例です。
<iframe 
  src="適当なsrc"
  title="適当なタイトル"
  sandbox="allow-scripts allow-forms"
  allow="geolocation 'none'; microphone 'none'; camera 'none'"
  loading="lazy"
  referrerpolicy="strict-origin-when-cross-origin">
</iframe>