現役システムエンジニアの備忘録

技術スキルや用語などの記録を残していきます

Frame(フレーム・親子ウィンドウ)

postMessageの使い方|iframe・別ウィンドウ間の送受信【JavaScript入門】

投稿日:2026年5月11日 更新日:

本記事にはプロモーション(アフィリエイト広告)を含みます。

この記事で分かること

  • postMessageで別の画面へメッセージを送る仕組み
  • 送信先を限定するtargetOriginの指定方法
  • 送信元と受信データを確認する方法
  • iframeと別ウィンドウを使った送受信のコードと手順
  • メッセージが届かないときの確認点

この記事は、2026年10月時点のMDN Web Docs「Window.postMessage()」とHTML Standard「Web messaging」に基づいています。対象:Python 3.7以降で動かす例と、これらの仕様に対応するブラウザー。

別のページにデータを渡したいけれど、画面をまたいでどう送ればよいか分からない。そんなときに使える方法のひとつが、JavaScriptのpostMessageです。

補足:JavaScriptとは?
Webページに動きや処理を加えるためのプログラミング言語です。
補足:postMessageとは?
別のページや画面に、決めた内容を渡すための仕組みです。受け取った側は、その内容を確認してから必要な処理を行います。

この記事では、iframeと別ウィンドウを使った送受信を、ファイルの用意から順に紹介します。postMessageを使うだけで安全になるわけではありません。送信先を限定し、受信側でも送信元とデータの中身を確かめます。

補足:iframeとは?
自分のページの中に、別のページを表示するための枠です。外部サービスの画面などをページ内に表示するときに使われます。
補足:ウィンドウとは?
Webページを表示するブラウザーの画面を指します。タブで開いたページも、それぞれ別の画面として扱われます。

この記事のコード例では、Pythonの簡易サーバーを使います。ブラウザーでページを開き、ボタンを押して送受信する手順も説明します。

補足:Pythonとは?
さまざまな処理をプログラムで動かすための言語です。ここでは、作成したファイルをブラウザーで開けるようにする機能を使います。
補足:サーバーとは?
ページやデータを、別のアプリや人が使えるように渡すコンピューター上の仕組みです。この例では、自分のパソコンからページを表示します。
補足:ブラウザーとは?
Google ChromeやSafariなど、Webページを見るためのアプリです。

この記事は、JavaScriptのウィンドウ操作を学ぶ記事です。ページ内の枠だけでなく、別ウィンドウとのやり取りも扱います。JavaScriptの基礎を順番に学ぶ場合は、JavaScript 基礎ロードマップ|初心者が最短で学ぶためのガイドも参考にしてください。



postMessageは別のページにメッセージを渡す仕組み

postMessageを使うと、ページ内のiframeや、別に開いた画面へデータを渡せます。送ったデータは受信側の処理に届きますが、相手のページの文章やボタンを直接操作する機能ではありません。

通常、ブラウザーは、関係のないページ同士が互いの中身を自由に読めないよう制限しています。悪意のあるページが別のページの情報を勝手に読むのを防ぐためです。

postMessageは、この制限をなくすものではありません。相手のページの中身を自由に読むのではなく、受信側が登録した処理にメッセージを渡します。送信先の指定と受信側の確認が不十分なら、意図しない相手とのやり取りにつながる可能性があります。

送信先と受信側を確認する

送信側は送信先を指定する

送信側は、相手の画面にあるpostMessage()を呼び出します。関数に渡す情報を「引数」といい、第1引数には渡すデータ、第2引数には受け取りを許可する相手のoriginを指定します。

補足:関数とは?
ひとまとまりの処理に名前を付け、必要なときに呼び出して使うものです。
補足:引数とは?
関数に処理してもらうために渡す情報です。たとえば、あいさつ文を渡して表示してもらうとき、その文が引数に当たります。
補足:originとは?
ページの出どころを示す情報です。接続方式・サイト名・ポート番号を組み合わせて区別します。ページ全体の住所と同じとは限りません。
補足:ポート番号とは?
同じコンピューターの中で、どの通信口を使うかを区別する番号です。ページの出どころを確認するときにも使われます。

targetOriginは、第2引数で指定する「メッセージを受け取ってよい相手の出どころ」です。送信先の出どころと一致しない場合、そのメッセージは相手に渡りません。

補足:targetOriginとは?
メッセージの送り先として認めるページの出どころを指定する値です。送り先が決まっている場合は、具体的な値を指定します。

次のコードは、指定した相手に、あいさつのデータを送る例です。

targetWindow.postMessage(
  { type: "greeting", text: "こんにちは" },
  "https://example.com"
);

この例では、targetWindowが示す画面にメッセージを送ります。送信先のページの出どころがhttps://example.comと一致する場合に限り、メッセージが渡されます。

注意:*を送信先に指定すると、出どころを限定せずに送信します。送り先が分かっている場合は、*ではなく具体的な値を指定してください。

受信側は送信元とデータを確認する

受信側は、メッセージを受け取ったときに動く処理を登録します。届いた内容をそのまま信頼せず、送信元とデータの形・内容を確認してから使います。

次のコードでは、想定した相手から届いたか、データが期待した形かを確認してから使います。

window.addEventListener("message", (event) => {
  if (event.origin !== "https://example.com") return;

  const data = event.data;
  if (data === null || typeof data !== "object") return;
  if (data.type !== "greeting" || typeof data.text !== "string") return;

  // 確認した内容を使う
});

event.originは送信元の出どころ、event.dataは届いたデータです。受信側は、送信元が想定した相手かを調べ、データが期待した形かを確かめています。

補足:event.originとは?
届いたメッセージを送ったページの出どころを示す値です。受信側が、想定した相手から届いたかを確認するときに使います。
補足:event.dataとは?
届いたメッセージの中身です。送信側が渡した文字や、ひとまとめにした情報が入ります。
注意:送信元の出どころを確認するだけでは、データの中身まで安全とは限りません。使うデータの種類や値も、受信側で確かめてください。



iframeを使って送受信する一式の例

親ページに表示したiframeとの間で、ボタンを使ってメッセージを往復させます。親ページと中のページは異なるポート番号で開くため、出どころの確認も行います。

親ページと中のページの関係、メッセージの流れは次のとおりです。

親ページとiframeの間で、postMessageを使って双方向にメッセージを送り、受信側が送信元とデータを確認する流れを示した図です。

ファイルを用意する

まず、次の手順でファイルを準備します。親ページと中のページのコードは、指定した場所にそのまま保存してください。

  1. 作業用の場所にparentとchildというフォルダーを作ります。
  2. 親ページ用にparent/index.htmlを作り、下のコードを保存します。
  3. 中のページ用にchild/index.htmlを作り、続くコードを保存します。

フォルダーとファイルは次の構成です。

parent/
  index.html
child/
  index.html

親ページのparent/index.htmlに保存するコードです。

<!doctype html>
<html lang="ja">
<meta charset="utf-8">
<title>親ページ</title>
<h1>親ページ</h1>
<button id="send-to-child">中のページへ送る</button>
<p id="parent-result">ここに受信内容が表示されます。</p>
<iframe id="child-frame" title="中のページ"
  src="http://localhost:8001/index.html"></iframe>

<script>
const CHILD_ORIGIN = "http://localhost:8001";
const frame = document.getElementById("child-frame");
const result = document.getElementById("parent-result");

document.getElementById("send-to-child").addEventListener("click", () => {
  frame.contentWindow.postMessage(
    { type: "greeting", text: "親ページから届きました" },
    CHILD_ORIGIN
  );
});

window.addEventListener("message", (event) => {
  if (event.origin !== CHILD_ORIGIN) return;
  if (event.source !== frame.contentWindow) return;

  const data = event.data;
  if (data === null || typeof data !== "object") return;
  if (data.type !== "greeting" || typeof data.text !== "string") return;

  result.textContent = "受信:" + data.text;
});
</script>
</html>

document.getElementById()は、指定した名前の場所をページ内から探す書き方です。コードでは、ボタンや表示欄、iframeを見つけています。

補足:document.getElementById()とは?
ページ内で指定した名前が付いた場所を探す書き方です。この例では、ボタンや表示欄、iframeを見つけています。

中のページのchild/index.htmlに保存するコードです。

<!doctype html>
<html lang="ja">
<meta charset="utf-8">
<title>中のページ</title>
<h2>iframeの中のページ</h2>
<button id="send-to-parent">親ページへ送る</button>
<p id="child-result">ここに受信内容が表示されます。</p>

<script>
const PARENT_ORIGIN = "http://localhost:8000";
const result = document.getElementById("child-result");

document.getElementById("send-to-parent").addEventListener("click", () => {
  window.parent.postMessage(
    { type: "greeting", text: "中のページから届きました" },
    PARENT_ORIGIN
  );
});

window.addEventListener("message", (event) => {
  if (event.origin !== PARENT_ORIGIN) return;
  if (event.source !== window.parent) return;

  const data = event.data;
  if (data === null || typeof data !== "object") return;
  if (data.type !== "greeting" || typeof data.text !== "string") return;

  result.textContent = "受信:" + data.text;
});
</script>
</html>

2つのページを開く

この例では、ページを開くための簡易サーバーとしてPythonを使います。Python 3.7以降と、コマンドを入力する画面を2つ用意します。対応するブラウザーで例を開いてください。

  1. 1つ目のコマンド入力画面を開き、作業用の場所から親ページ用のサーバーを起動します。Windowsではpy、macOSやLinuxではpython3を使います。
# Windows
py -m http.server 8000 --directory parent

# macOS / Linux
python3 -m http.server 8000 --directory parent
  1. 2つ目のコマンド入力画面を開き、同じ作業用の場所から中のページ用のサーバーを起動します。
# Windows
py -m http.server 8001 --directory child

# macOS / Linux
python3 -m http.server 8001 --directory child
  1. ブラウザーでhttp://localhost:8000/index.htmlを開き、親ページと中のページが表示されることを確認します。
  2. 親ページの「中のページへ送る」を押します。中のページの表示欄に「受信:親ページから届きました」と表示されます。
  3. 中のページの「親ページへ送る」を押します。親ページの表示欄に「受信:中のページから届きました」と表示されます。
補足:HTTPとは?
Webページをやり取りするときに使われる通信の決まりです。この例は自分のパソコン内で試すためのもので、実際のサービスに使う設定例ではありません。
補足:localhostとは?
自分のパソコン自身を指す名前です。ここでは、外部のWebサイトではなく、自分のパソコンでページを開きます。

コードで確認していること

  • 送り先の出どころを、CHILD_ORIGINまたはPARENT_ORIGINで具体的に指定しています。
  • 受信側は、event.originで送信元を確かめています。
  • 親ページは、event.sourceがページ内のiframeかどうかも確かめています。
  • 受信データが想定した種類で、typeとtextを持つことを確かめてから表示します。
補足:event.sourceとは?
メッセージを送った画面を指す値です。この例では、送信元がページ内のiframeかどうかを確認します。
注意:この例のlocalhostとポート番号は、手元で試すための設定です。実際のページで使うときは、送信元と送信先の出どころを実際の設定に合わせて変更してください。

別ウィンドウ間でも考え方は同じ

別ウィンドウでも、送信側が相手の画面を指定し、受信側が送信元とデータを確認する点は同じです。次の例では、親ページから新しいウィンドウを開き、親から子、子から親の両方向にメッセージを送ります。

この例では、親ページをポート番号8000、中のページをポート番号8001で開きます。前の例で起動した2つのサーバーを使い、親ページ用と中のページ用のフォルダーに、それぞれファイルを追加します。

別ウィンドウ用のファイルを作る

  1. 作業用の場所にあるparentフォルダーに、親ページ用のpopup.htmlを作ります。
  2. childフォルダーに、別ウィンドウ用のpopup.htmlを作ります。このフォルダーは、8001番のサーバーが公開する場所です。

親ページ用のparent/popup.htmlに保存するコードです。

<!doctype html>
<html lang="ja">
<meta charset="utf-8">
<title>別ウィンドウ送受信の親ページ</title>
<h1>親ページ</h1>
<button id="open-popup">別ウィンドウを開く</button>
<button id="send-to-popup" disabled>別ウィンドウへ送る</button>
<p id="parent-result">別ウィンドウの準備ができると、ここに表示されます。</p>

<script>
const POPUP_ORIGIN = "http://localhost:8001";
let popupWindow = null;
let popupReady = false;

const result = document.getElementById("parent-result");
const sendButton = document.getElementById("send-to-popup");

document.getElementById("open-popup").addEventListener("click", () => {
  popupWindow = window.open(
    "http://localhost:8001/popup.html",
    "postMessagePopup",
    "width=600,height=400"
  );

  if (popupWindow === null) {
    result.textContent = "別ウィンドウを開けませんでした。ブラウザーの設定を確認してください。";
  }
});

window.addEventListener("message", (event) => {
  if (event.origin !== POPUP_ORIGIN) return;
  if (event.source !== popupWindow) return;

  const data = event.data;
  if (data === null || typeof data !== "object") return;

  if (data.type === "ready") {
    popupReady = true;
    sendButton.disabled = false;
    result.textContent = "別ウィンドウの準備ができました。";
    return;
  }

  if (data.type !== "greeting" || typeof data.text !== "string") return;
  result.textContent = "受信:" + data.text;
});

sendButton.addEventListener("click", () => {
  if (popupWindow === null || popupWindow.closed || !popupReady) return;

  popupWindow.postMessage(
    { type: "greeting", text: "親ページから届きました" },
    POPUP_ORIGIN
  );
});
</script>
</html>

別ウィンドウの準備が終わると、親ページのボタンが押せるようになります。送信前に準備完了の合図を受け取るため、ページの読み込みより先にメッセージを送る状態を避けられます。

別ウィンドウ用のchild/popup.htmlに保存するコードです。

<!doctype html>
<html lang="ja">
<meta charset="utf-8">
<title>別ウィンドウ</title>
<h1>別ウィンドウ</h1>
<button id="send-to-parent">親ページへ送る</button>
<p id="popup-result">ここに受信内容が表示されます。</p>

<script>
const PARENT_ORIGIN = "http://localhost:8000";
const result = document.getElementById("popup-result");

window.addEventListener("message", (event) => {
  if (event.origin !== PARENT_ORIGIN) return;
  if (event.source !== window.opener) return;

  const data = event.data;
  if (data === null || typeof data !== "object") return;
  if (data.type !== "greeting" || typeof data.text !== "string") return;

  result.textContent = "受信:" + data.text;
});

window.addEventListener("load", () => {
  if (window.opener === null) return;

  window.opener.postMessage(
    { type: "ready" },
    PARENT_ORIGIN
  );
});

document.getElementById("send-to-parent").addEventListener("click", () => {
  if (window.opener === null) return;

  window.opener.postMessage(
    { type: "greeting", text: "別ウィンドウから届きました" },
    PARENT_ORIGIN
  );
});
</script>
</html>

別ウィンドウ間で送受信する

  1. 親ページ用と中のページ用のサーバーを、それぞれ起動しておきます。すでに前の手順で起動している場合は、そのまま使えます。8000番のサーバーはparentフォルダーを、8001番のサーバーはchildフォルダーを公開します。
  2. ブラウザーでhttp://localhost:8000/popup.htmlを開きます。
  3. 「別ウィンドウを開く」を押します。別ウィンドウが開き、親ページに「別ウィンドウの準備ができました。」と表示されます。
  4. 親ページの「別ウィンドウへ送る」を押します。別ウィンドウに「受信:親ページから届きました」と表示されます。
  5. 別ウィンドウの「親ページへ送る」を押します。親ページに「受信:別ウィンドウから届きました」と表示されます。

実行結果:

親ページ:受信:別ウィンドウから届きました
別ウィンドウ:受信:親ページから届きました

別ウィンドウを開く処理では、受信側に送信元を確かめさせるだけでなく、開いた画面を示すpopupWindowが受信元であることも確認しています。別ウィンドウ側も、event.originとevent.sourceを使って、親ページからのメッセージかどうかを確認します。

注意:この例では、親ページとの連絡にwindow.openerを使います。別ウィンドウを開くときに元ページとの関係を切る設定を加えると、この方法で親ページを参照できなくなります。
補足:window.openerとは?
新しいウィンドウを開いた元のページを指す値です。この例では、別ウィンドウから親ページへメッセージを送るために使います。



メッセージが届かないときの確認点

  • 送信先の出どころが一致していない:送信側の第2引数と、受信側が確認する送信元の値に、接続方式・サイト名・ポート番号の違いがないか確認します。
  • 受信処理の登録前に送っている:受信側のページが読み込まれ、メッセージを受け取る処理が登録されてから送信します。別ウィンドウの例では、準備完了の合図が表示されてから送信します。
  • 受信元の確認で除外されている:event.originとevent.sourceの確認条件が、実際の送信元に合っているか見直します。
  • データの形が確認条件と違う:送信側のtypeやtextと、受信側で確かめている名前・値の種類を比べます。
  • ポップアップが止められている:別ウィンドウが開かない場合は、ブラウザーが新しい画面を止めていないか確認します。新しい画面を開く処理は、ボタンを押したときに実行します。
  • ページの開き方が想定と違う:ファイルを直接開かず、記事の手順どおりにサーバーを起動してページを開きます。
  • ポート番号が別の処理に使われている:サーバーの起動時にエラーが出た場合は、起動に使うポート番号を確認します。番号を変更した場合は、コード内の出どころも同じ番号にそろえます。

別のページ同士を扱うときの制限については、【JavaScript入門】フレームのセキュリティ制限とは?同一オリジンポリシーとiframeの制約を初心者向けに解説も参考になります。ページの読み込み完了を待つ方法は、【JavaScript入門】iframeの読み込み完了を検知する方法|onloadで安全にDOMへアクセスする手順を初心者向けに解説で確認できます。

postMessageを使う前に知っておきたい制約

  • postMessageは、データを渡す仕組みです。相手ページの中身を直接読み書きする機能ではありません。
  • メッセージが届いても、内容が正しいとは限りません。送信元・データの種類・値を受信側で確認してください。
  • 送信先を限定する設定と、受信側の確認は別の役割です。両方を適切に行います。
  • 実際のサービスでは、相手ページの仕様や公開されている接続方法も確認してください。相手側がメッセージの受信に対応していない場合、この例だけでは連携できません。

送信先や受信側の確認方法は、MDN Web DocsのpostMessage解説と、HTML Standardの「Web messaging」で確認できます。

補足:MDNとは?
Mozillaが公開している、Webページ作成に使う技術の解説資料です。
補足:MDN Web Docsとは?
Webページ作りに使う技術について、Mozillaが公開している解説資料です。
補足:HTML Standardとは?
Webページの表示や動きについて、共通の決まりをまとめた文書です。

JavaScriptの基礎から学びたい方へ PR

この記事の例を理解するために、JavaScriptの基本やページ操作、イベント処理から順に学びたい方は、書籍を使う方法もあります。

これからのJavaScriptの教科書

JavaScriptの基本文法に加え、ページ操作、フォーム操作、イベント、非同期処理などを扱う書籍です。記事で扱ったメッセージ送受信だけでなく、関連する基礎を順に学びたい人に向いています。

  • JavaScriptの基本から順に学びたい人
  • ページ操作やイベント処理などもあわせて学びたい人
  • コード例を試しながら学びたい人

注意点:全608ページのため、要点だけを短時間で確認したい人には分量が多く感じられる場合があります。対象仕様はECMAScript 2023です。

補足:ECMAScriptとは?
JavaScriptの書き方や動きについて決めた標準です。この書籍は、2023年版の標準までを扱うと案内されています。

postMessageに関するよくある質問

Q1

postMessageは、出どころが異なるページ間でも使えますか?

A

使えます。ただし、送信先を具体的に指定し、受信側でも送信元とデータの中身を確かめてください。

Q2

送信先には「*」を指定してもよいですか?

A

送り先が決まっている場合は、具体的な出どころを指定してください。「*」は送り先を限定しません。

Q3

受信側で送信元を確認すれば、安全に使えますか?

A

送信元の確認だけでは不十分です。データの種類や値も確認し、必要な内容だけを処理してください。

Q4

postMessageで、相手のページのボタンや文章を直接操作できますか?

A

できません。postMessageはページ間でデータを渡す仕組みです。受け取った側のページが、そのデータをどう扱うかを決めます。

Q5

別ウィンドウが開かないときは、何を確認すればよいですか?

A

ブラウザーが新しい画面を止めていないか確認してください。例のように、ボタンを押したときに新しい画面を開く処理を行います。

Q6

メッセージが届かないときは、何を確認すればよいですか?

A

送信先の出どころ、受信処理の登録タイミング、送信元の確認条件、データの形を確認します。ページの開き方とポート番号も見直してください。



まとめ

  • postMessageは、別のページへデータを渡す仕組みです。
  • 送り先が分かっている場合は、具体的なtargetOriginを指定します。
  • 受信側では、送信元とデータの種類・値を確認します。
  • iframeと別ウィンドウの両方で、相互にメッセージを送れます。
  • 別ウィンドウを開くときは、ボタン操作をきっかけに開き、準備完了後に送信します。

まずは親ページと中のページ、または別ウィンドウの例を順に試してください。実際のサービスで使うときは、送信先・送信元・データの確認条件を利用環境に合わせます。

このブログは Xserver 上の WordPress で運用しています。
表示速度が速く、安定しているのでブログ初心者にもおすすめです。

→ レンタルサーバー エックスサーバー

-Frame(フレーム・親子ウィンドウ)

執筆者: