埋め込んだiframeの中身を、外側のページからスクロールさせたいことがあります。やり方はiframeが同一オリジンか、クロスオリジン(別ドメイン)かで大きく変わります。
同一オリジンなら直接スクロールできますが、クロスオリジンはセキュリティ制限で直接操作できず、postMessage を使います。この記事では両方のケースを解説します。
iframe.contentWindow.scrollTo(0, y) で直接スクロールできます。クロスオリジンは直接操作できないため、postMessage でiframe側に依頼します。どちらもiframeの読み込み完了(load)後に実行します。同一オリジンのiframeをスクロールする(scrollTo)
iframeが同じドメイン(同一オリジン)なら、iframe.contentWindow から中身のウィンドウにアクセスし、scrollTo() でスクロールできます。古い scrollTop プロパティより scrollTo() が簡潔で確実です。
<iframe id="myIframe" src="/page.html"></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 イベントで読み込み完了を待ってから実行します。ボタンクリックなど、十分に読み込まれた後の操作なら不要です。
const iframe = document.getElementById("myIframe");
iframe.addEventListener("load", () => {
iframe.contentWindow.scrollTo(0, 100); // 読み込み完了後に実行
});
クロスオリジンは直接操作できない(postMessage)
iframeが別ドメイン(クロスオリジン)の場合、ブラウザのセキュリティ制限で contentWindow.document に直接アクセスできません。代わりに postMessage でiframe側に「スクロールして」と依頼し、iframe側のスクリプトが自分でスクロールします。
const iframe = document.getElementById("myIframe");
// iframe側へ「100pxスクロールして」と依頼(第2引数で送信先originを限定)
iframe.contentWindow.postMessage(
{ type: "scroll", top: 100 },
"https://child.example.com"
);
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 で試すと判別できます。クロスオリジンだと例外になります。
function canAccess(iframe) {
try {
// クロスオリジンだとここでエラーになる
return !!iframe.contentWindow.document;
} catch {
return false; // クロスオリジン → 直接操作は不可
}
}
同一オリジンなら scrollTo で直接、クロスオリジンなら postMessage で、と使い分けます。
よくある質問(FAQ)
iframe.contentWindow.scrollTo(0, y) でスクロール位置を変更できます。クロスオリジンではセキュリティポリシーにより直接操作できないため、postMessage を使います。postMessage 経由で操作できます。iframe.contentDocument.body.scrollHeight で高さを取得し、iframe.style.height に設定します。クロスオリジンには postMessage で高さを通知する仕組みが必要です。event.origin を必ず確認し、想定した送信元以外のメッセージを弾いてください。送信側も第2引数で送信先のoriginを限定します。これを怠るとXSSなどのリスクがあります。まとめ
iframe内のスクロール操作は、同一オリジンなら iframe.contentWindow.scrollTo(0, y) で直接行えます。古い scrollTop より scrollTo が簡潔で、スムーズスクロールも指定できます。
クロスオリジン(別ドメイン)は直接操作できないため、postMessage でiframe側に依頼し、iframe側のスクリプトが自分でスクロールします。いずれも読み込み完了(load)後に実行し、postMessage では event.origin の確認を忘れないようにしましょう。
