【JavaScript】外部からiframe内のスクロール位置を操作する方法

埋め込んだiframeの中身を、外側のページからスクロールさせたいことがあります。やり方はiframeが同一オリジンか、クロスオリジン(別ドメイン)かで大きく変わります。

同一オリジンなら直接スクロールできますが、クロスオリジンはセキュリティ制限で直接操作できず、postMessage を使います。この記事では両方のケースを解説します。

この記事の結論:同一オリジンなら iframe.contentWindow.scrollTo(0, y) で直接スクロールできます。クロスオリジンは直接操作できないため、postMessage でiframe側に依頼します。どちらもiframeの読み込み完了(load)後に実行します。
スポンサーリンク

同一オリジンのiframeをスクロールする(scrollTo)

iframeが同じドメイン(同一オリジン)なら、iframe.contentWindow から中身のウィンドウにアクセスし、scrollTo() でスクロールできます。古い scrollTop プロパティより scrollTo() が簡潔で確実です。

HTML
<iframe id="myIframe" src="/page.html"></iframe>
JavaScript:iframe内をスクロール
const iframe = document.getElementById("myIframe");

// 縦100pxの位置へスクロール
iframe.contentWindow.scrollTo(0, 100);

// スムーズにスクロールするなら
iframe.contentWindow.scrollTo({ top: 100, behavior: "smooth" });

scrollTo やスムーズスクロールの詳細は特定の位置までスクロールさせる方法で解説しています。なおiframe自体の遅延読み込み(loading="lazy")はLazyload(遅延読み込み)完全ガイドも参考になります。

読み込み完了を待ってから実行する(onload)

iframeの中身がまだ読み込まれていないうちにスクロールしても効きません。load イベントで読み込み完了を待ってから実行します。ボタンクリックなど、十分に読み込まれた後の操作なら不要です。

JavaScript:load後にスクロール
const iframe = document.getElementById("myIframe");

iframe.addEventListener("load", () => {
  iframe.contentWindow.scrollTo(0, 100); // 読み込み完了後に実行
});

クロスオリジンは直接操作できない(postMessage)

iframeが別ドメイン(クロスオリジン)の場合、ブラウザのセキュリティ制限で contentWindow.document直接アクセスできません。代わりに postMessage でiframe側に「スクロールして」と依頼し、iframe側のスクリプトが自分でスクロールします。

前提:iframe側を自分で管理している必要があります:この方法は、iframeで読み込むページに自分でスクリプトを仕込める場合のみ可能です。管理外の第三者サイトのスクロールを外から操作することはできません(セキュリティ上の仕様)。
JavaScript:親ページ(依頼を送る)
const iframe = document.getElementById("myIframe");

// iframe側へ「100pxスクロールして」と依頼(第2引数で送信先originを限定)
iframe.contentWindow.postMessage(
  { type: "scroll", top: 100 },
  "https://child.example.com"
);
JavaScript:iframe側のページ(受け取って実行)
window.addEventListener("message", (event) => {
  // 発信元を必ず確認(セキュリティ)
  if (event.origin !== "https://parent.example.com") return;

  if (event.data.type === "scroll") {
    window.scrollTo({ top: event.data.top, behavior: "smooth" });
  }
});

postMessage による親子間の通信はポップアップウィンドウを開く方法(postMessageの章)でも解説しています。受信側で event.origin を必ず確認して、不正なメッセージを弾くのが鉄則です。

同一オリジンかどうかを確認する

同一オリジンかどうかは、contentWindow.document へのアクセスをtry-catch で試すと判別できます。クロスオリジンだと例外になります。

JavaScript:同一オリジンか判定
function canAccess(iframe) {
  try {
    // クロスオリジンだとここでエラーになる
    return !!iframe.contentWindow.document;
  } catch {
    return false; // クロスオリジン → 直接操作は不可
  }
}

同一オリジンなら scrollTo で直接、クロスオリジンなら postMessage で、と使い分けます

よくある質問(FAQ)

Q親フレームからiframe内のスクロールを操作するには?
A同一オリジンのiframeなら iframe.contentWindow.scrollTo(0, y) でスクロール位置を変更できます。クロスオリジンではセキュリティポリシーにより直接操作できないため、postMessage を使います。
Qクロスオリジンのiframeはなぜ直接操作できないのですか?
Aブラウザの同一オリジンポリシーにより、別ドメインのiframeの中身(DOMやスクロール)には直接アクセスできない仕組みになっているためです。iframe側にスクリプトを仕込める場合のみ、postMessage 経由で操作できます。
Qiframeの高さをコンテンツに合わせて自動調整するには?
A同一オリジンなら iframe.contentDocument.body.scrollHeight で高さを取得し、iframe.style.height に設定します。クロスオリジンには postMessage で高さを通知する仕組みが必要です。
QpostMessageを使うときの注意点は?
A受信側で event.origin を必ず確認し、想定した送信元以外のメッセージを弾いてください。送信側も第2引数で送信先のoriginを限定します。これを怠るとXSSなどのリスクがあります。

まとめ

iframe内のスクロール操作は、同一オリジンなら iframe.contentWindow.scrollTo(0, y) で直接行えます。古い scrollTop より scrollTo が簡潔で、スムーズスクロールも指定できます。

クロスオリジン(別ドメイン)は直接操作できないため、postMessage でiframe側に依頼し、iframe側のスクリプトが自分でスクロールします。いずれも読み込み完了(load)後に実行し、postMessage では event.origin の確認を忘れないようにしましょう。