JavaScriptの window.open() を使うと、別のブラウザウィンドウ(またはタブ)をプログラムから開くことができます。ヘルプページ・利用規約・OAuth認証画面など、現在のページを離れずに別コンテンツを表示したい場面で活用されます。
ただし、現代のブラウザはポップアップブロッカーを搭載しており、使い方を誤るとブロックされてしまいます。この記事では基本的な使い方から、ブロック対策・ウィンドウ間通信・モーダルとの使い分けまで体系的に解説します。
window.open() の基本構文
window.open(url, target, features) の3つの引数で挙動を制御します。
// 基本形
window.open('https://example.com');
// 第2引数:ウィンドウ名(_blank=新規, _self=現タブ, _parent, _top, または任意の名前)
window.open('https://example.com', '_blank');
// 第3引数:ウィンドウの外観を指定する文字列(スペースなし・カンマ区切り)
window.open(
'https://example.com',
'myPopup',
'width=800,height=600,left=100,top=100'
);
// 戻り値:開いたウィンドウへの参照(ブロックされた場合は null)
const popup = window.open('https://example.com', '_blank');
if (popup === null) {
console.log('ポップアップがブロックされました');
}
| 引数 | 内容 | 省略時の動作 |
|---|---|---|
| url | 開く URL(空文字列 "" で空白ページ) |
空白ページ(about:blank) |
| target | ウィンドウ名または _blank・_self |
_blank(新規) |
| features | サイズ・位置などの設定文字列 | ブラウザのデフォルト |
ウィンドウのサイズ・位置を指定する(features)
第3引数の features 文字列で、ウィンドウのサイズと表示位置を制御できます。
| オプション | 説明 | 例 |
|---|---|---|
width |
ウィンドウの幅(px) | width=800 |
height |
ウィンドウの高さ(px) | height=600 |
left |
画面左端からの距離(px) | left=200 |
top |
画面上端からの距離(px) | top=100 |
noopener |
opener プロパティを無効化(セキュリティ強化) | noopener |
noreferrer |
Referer ヘッダーを送らない | noreferrer |
/**
* 画面中央にポップアップを表示する
* @param {string} url
* @param {number} w - 幅(px)
* @param {number} h - 高さ(px)
*/
function openCentered(url, w = 800, h = 600) {
const left = Math.round(window.screenX + (window.outerWidth - w) / 2);
const top = Math.round(window.screenY + (window.outerHeight - h) / 2);
return window.open(
url,
'_blank',
`width=${w},height=${h},left=${left},top=${top},noopener,noreferrer`
);
}
// 使い方
openCentered('https://example.com/help', 900, 650);
toolbar=no・menubar=no・scrollbars=yes などのオプションがありましたが、現代のブラウザはセキュリティ上の理由からこれらのほとんどを無視します。制御できるのは実質的に width・height・left・top のみと考えてください。ポップアップブロッカーの仕組みと対策
現代のブラウザは、ユーザー操作(クリックなど)を起点としない window.open() の呼び出しをブロックします。
| 呼び出しパターン | ブロックされるか |
|---|---|
| クリックイベントハンドラ内で即時呼び出し | ◎ ブロックされない |
| ページ読み込み時(DOMContentLoaded など)に自動呼び出し | ✕ ブロックされる |
| クリック後に setTimeout で遅延呼び出し | ✕ ブロックされる(タイミングによる) |
| クリック後に await(非同期)してから呼び出し | ✕ ブロックされる |
await fetch(...) の後に window.open() を呼ぶと、ブラウザはユーザー操作の「信頼コンテキスト」が切れたと判断してブロックします。非同期処理が必要な場合は、先に window.open("") で空ウィンドウを開いておき、後から popup.location.href = url で URL を設定するのが正しいパターンです。document.getElementById('openBtn').addEventListener('click', () => {
// クリックハンドラ内で即時呼び出し → ブロックされない
window.open('https://example.com', '_blank', 'noopener,noreferrer');
});
document.getElementById('authBtn').addEventListener('click', async () => {
// ① クリック直後に空ウィンドウを先に開いておく
const popup = window.open('', '_blank', 'width=500,height=700');
try {
// ② 非同期で認証URLを取得
const res = await fetch('/api/auth/url');
const { authUrl } = await res.json();
// ③ 取得したURLをポップアップに設定
popup.location.href = authUrl;
} catch (err) {
// 失敗したらポップアップを閉じる
popup.close();
alert('認証URLの取得に失敗しました');
}
});
ポップアップブロックの検出とフォールバック
ブロックされた場合 window.open() は null を返します。これを検出して通常リンクへのフォールバックを用意すると、ユーザビリティが向上します。
function openPopupWithFallback(url, options = 'width=800,height=600,noopener,noreferrer') {
const popup = window.open(url, '_blank', options);
if (popup === null || popup.closed) {
// ブロックされた → 通常のタブで開くようユーザーに案内
const openLink = document.createElement('a');
openLink.href = url;
openLink.target = '_blank';
openLink.rel = 'noopener noreferrer';
openLink.textContent = 'こちらをクリックして開いてください';
const msg = document.getElementById('popupMsg');
if (msg) {
msg.innerHTML = '';
msg.append('ポップアップがブロックされました。', openLink);
msg.hidden = false;
}
}
return popup;
}
開いたウィンドウを制御する(opener・closed・focus)
window.open() の戻り値はウィンドウへの参照です。これを使って、ポップアップの状態確認・フォーカス・クローズを制御できます。
let popup = null;
document.getElementById('openBtn').addEventListener('click', () => {
// すでに開いていて閉じられていなければ再利用
if (popup && !popup.closed) {
popup.focus(); // 既存のウィンドウを前面に
return;
}
popup = window.open(
'/help',
'helpWindow',
'width=900,height=700,noopener'
);
});
document.getElementById('closeBtn').addEventListener('click', () => {
if (popup && !popup.closed) {
popup.close();
popup = null;
}
});
// ポップアップが閉じられたかどうかを定期確認
const checkInterval = setInterval(() => {
if (popup && popup.closed) {
console.log('ポップアップが閉じられました');
popup = null;
clearInterval(checkInterval);
}
}, 500);
noopener を指定すると、開いた先のページから window.opener で元ページを参照できなくなります。これにより悪意あるページが window.opener.location を書き換えるタブナビゲーション攻撃(reverse tabnapping)を防げます。外部サイトを開く場合は必ず noopener,noreferrer を指定してください。postMessage でポップアップと安全に通信する
同じオリジンであれば popup.document に直接アクセスできますが、より安全でオリジン間でも使えるのが postMessage です。OAuth 認証の結果を親ウィンドウに返すケースなどで活用されます。
// 親ウィンドウ:postMessage のリスナーを設定
window.addEventListener('message', (e) => {
// ① 送信元オリジンを必ず検証する(セキュリティ上必須)
if (e.origin !== 'https://your-domain.com') return;
// ② データを処理
const { type, payload } = e.data;
if (type === 'AUTH_SUCCESS') {
console.log('認証成功:', payload.token);
// ポップアップを閉じて処理を続ける
if (popup && !popup.closed) popup.close();
}
});
// ポップアップウィンドウ側のスクリプト
// 認証成功後などに親ウィンドウへメッセージを送信
function notifyParent(token) {
if (!window.opener || window.opener.closed) return;
window.opener.postMessage(
{ type: 'AUTH_SUCCESS', payload: { token } },
'https://your-domain.com' // ターゲットオリジンを明示(必須)
);
// 送信後に自分自身を閉じる
window.close();
}
message イベントのハンドラで e.origin を検証しないと、悪意あるサイトから偽のメッセージを送られるリスクがあります。必ず e.origin !== "https://your-domain.com" の検証を最初に行ってください。また送信側でもターゲットオリジンを "*"(ワイルドカード)にせず、具体的なオリジンを指定してください。window.open とモーダルダイアログの使い分け
| window.open(新規ウィンドウ) | モーダルダイアログ | |
|---|---|---|
| 親ページの操作 | 可能(独立したウィンドウ) | 不可(背景がブロックされる) |
| URL の変化 | 別ウィンドウに独立したURL | 変化しない |
| ポップアップブロック | ユーザー操作起点でないとブロック | ブロックなし(DOM操作のため) |
| 適した用途 | 外部サービス・OAuth・ヘルプページ | 確認ダイアログ・画像拡大・フォーム |
| モバイル対応 | タブとして開く(UXが分断されやすい) | 同一ページ内でUXが完結 |
window.open() は外部サービス連携(OAuth・決済ページ)など、独立したセッションが必要なケースに限定して使うのが現代のベストプラクティスです。よくある質問
popup.resizeTo(幅, 高さ) または popup.resizeBy(差分幅, 差分高さ) で変更できます。ただし noopener を指定した場合は popup への参照が null になるため使えません。また、ブラウザによっては自分で開いたウィンドウ以外のリサイズを制限しています。popup.document.write() や popup.document.body.innerHTML で書き込めます。別オリジンの場合は Same-Origin Policy によりアクセスが制限されます。オリジン間でデータをやり取りするには postMessage を使ってください。<a target="_blank"> はユーザーがクリックしたときに開くため、ポップアップブロッカーに引っかかりません。window.open() はプログラムから呼び出せる分、ポップアップブロッカーの制約を受けます。セキュリティ面では両方とも rel="noopener noreferrer"(aタグ)または noopener,noreferrer(window.open)を指定してください。.closed プロパティを setInterval で定期的に確認するのが一般的です。ただしこれはポーリングのため100%リアルタイムではありません。より確実にするには、ポップアップ側で閉じる前に window.opener.postMessage で通知する設計が推奨されます。まとめ
JavaScript のポップアップウィンドウ実装のポイントをまとめます。
window.open(url, target, features)で別ウィンドウ・タブを開ける- ポップアップブロッカーを回避するにはクリックイベントハンドラ内で即時呼び出す
- 非同期処理後に開きたい場合は「空ウィンドウを先に開いて後から URL を設定」する
- 外部URLを開く際は必ず
noopener,noreferrerを指定してセキュリティを確保する - ウィンドウ間通信は
postMessage+ オリジン検証で安全に行う - モーダルで代替できる場面ではモーダルを優先する(UX・セキュリティ両面で有利)
ページ内のモーダルダイアログ実装は【JavaScript】Micromodal.jsで簡単にモーダルを実装する方法、既存要素の移動・制御については【JavaScript】既存の要素を移動させる方法もあわせてご覧ください。