「JavaScriptで別タブを開きたい」という場面でよく使われるのがwindow.open()です。基本的な書き方はシンプルですが、実際に使ってみると「新しいタブが開かない」「SafariやChromeで挙動が違う」「fetchの処理後だとポップアップブロックされる」といった問題に悩むことがあります。
また、window.open()は単にURLを開くだけの機能ではありません。_blankなどのターゲット指定、ウィンドウサイズの設定、開いたウィンドウの再利用・クローズ、window.openerを介した親ウィンドウとの関係など、実装前に知っておきたい仕様があります。セキュリティ面では、noopenerやnoreferrer、reverse tabnabbingへの対策も重要です。
この記事では、window.open()の基本から実際の開発で遭遇しやすい問題まで、具体的なコードを交えながら解説します。
window.open()とは?JavaScriptで別タブ・別ウィンドウを開く基本
window.open()は、JavaScriptから新しいタブやウィンドウを開くための標準メソッドです。URL・ターゲット名・ウィンドウの見た目を指定するだけで、任意のページを別コンテキストで表示できます。まずは基本構文と引数の仕様、そして似た機能である<a target="_blank">やwindow.locationとの使い分けを押さえておきましょう。ここを正しく理解しておくことで、後述するポップアップブロックやセキュリティのトラブルも未然に防げるようになります。

window.open()の役割と基本構文
window.open()は、指定したURLを新しい「ブラウジングコンテキスト(タブ・ウィンドウ・フレーム)」に読み込むためのメソッドです。実務では「別タブでリンクを開きたいが、<a>タグではなくJavaScript側で動的に制御したい」という場面で使われることがほとんどです。
基本構文は以下の通りです。
// 基本構文:window.open(url, target, windowFeatures)
window.open(); // 何も指定しない場合、空のタブが開く
window.open("https://example.com"); // URLのみ指定
window.open("https://example.com", "_blank"); // 新しいタブで開くwindow.open()を実行した瞬間にページがすぐ表示されると思われがちですが、実際にはURLの読み込みは非同期で行われ、window.open()が返した時点では新しいウィンドウの中身はabout:blank(空白ページ)のままです。その後、現在実行中のスクリプトが終了してから実際のURL読み込みが開始されます。この挙動を知らないと、「開いた直後に新しいウィンドウの中身を操作しようとしたら何も反映されない」という不具合の原因になるため、最初に押さえておくべきポイントです。
第1引数〜第3引数(URL・ターゲット名・features)の正しい指定順と仕様
window.open()の引数は「URL→ターゲット名→windowFeatures」の順で固定されており、途中を省略することはできても順番を入れ替えることはできません。それぞれの仕様は以下の通りです。
| 引数 | 名称 | 必須 | 説明 |
|---|---|---|---|
| 第1引数 | url | 省略可 | 読み込むリソースのURL。省略または空文字の場合は空白ページが開く |
| 第2引数 | target | 省略可 | 開き先のウィンドウ名。_blank・_self・_parent・_topという特殊キーワードも指定可能 |
| 第3引数 | windowFeatures | 省略可 | width=400,height=300のように,区切り・name=value形式で見た目を指定 |
// 第1引数:開くURL
// 第2引数:ターゲット名(_blankで常に新しいタブ/ウィンドウ)
// 第3引数:ウィンドウの見た目(幅・高さなど)を指定
const newWin = window.open(
"https://example.com",
"_blank",
"width=600,height=400"
);
// window.open()は新しいウィンドウへの参照(WindowProxyオブジェクト)を返す
// ポップアップブロック等で開けなかった場合はnullが返る点に注意
if (newWin === null) {
console.log("ウィンドウを開けませんでした(ポップアップブロックの可能性)");
}実務でよくある間違いが、「第2引数にwindowFeaturesの値を入れてしまう」というケースです。第2引数はあくまで「ウィンドウ名(target)」であり、width=600のような文字列を渡してもウィンドウのサイズには反映されません。サイズや位置を指定したい場合は、必ず第3引数に渡す必要があります。
aタグ(target=”_blank”)やwindow.locationとの使い分け基準とメリット
結論から言うと、静的なリンクであれば<a target="_blank">、JavaScriptによる動的な制御が必要な場合のみwindow.open()を使うのが基本方針です。同じタブ内でページを遷移させたいだけならwindow.locationを使います。3つの違いを整理すると以下の通りです。
| 方法 | 新しいタブ/ウィンドウ | JSからの動的制御 | 主な用途 |
|---|---|---|---|
<a href="..." target="_blank"> | ○ | △(クリックイベントが必要) | 静的なリンク(外部サイトへの遷移など) |
window.open() | ○ | ○ | 条件分岐後に開く、サイズ指定、ポップアップ制御 |
window.location.href = "..." | ×(同一タブ) | ○ | フォーム送信後のリダイレクトなど同一タブでの遷移 |
<!-- 静的なリンクなら、HTMLだけで完結する<a>タグがシンプルで推奨されます -->
<a href="https://example.com" target="_blank" rel="noopener noreferrer">
外部サイトを新しいタブで開く
</a>// 条件によって開くURLを変えたい場合など、動的な制御が必要な場面ではwindow.open()を使う
function openExternalLink(userType) {
const url = userType === "admin"
? "https://example.com/admin"
: "https://example.com/user";
window.open(url, "_blank", "noopener,noreferrer");
}案件で「会員種別によってリンク先を変えつつ、必ず別タブで開いてほしい」という要件が来たときは、<a>タグだけでは対応できないためwindow.open()を使うことになります。逆に、単に外部サイトへのリンクを設置するだけであれば、<a target="_blank">の方がSEOやアクセシビリティの観点からもシンプルで、余計なJavaScriptを書かずに済みます。「なぜwindow.open()が必要なのか」を実装前に一度立ち止まって考えることで、無駄なコードを減らすことができます。
ポップアップブロックの原因と回避する実装パターン
window.open()が動かない原因の多くは「ポップアップブロック」です。ブラウザは、ユーザーの意図しないタイミングで新しいウィンドウが開くことを防ぐため、一定のルールに従ってブロック処理を行っています。結論として、ユーザーのクリックなどの操作イベントの中で、かつ同期的にwindow.open()を呼び出すことがブロックを回避する最も確実な方法です。非同期処理を挟むとブロックされやすくなる仕組みと、実際に開けたかどうかを判定する方法まで解説します。

なぜブロックされる?onclick等ユーザーアクション直下での必須実行ルール
現代のブラウザは、ユーザーの操作(クリックやタップ)に直接紐づいて実行されたコードだけを「ユーザーの意図した操作」とみなし、それ以外のタイミングで発生したwindow.open()をブロックする仕組みを持っています。これは、ページを開いた瞬間に大量の広告ポップアップが表示されるような迷惑行為を防ぐための仕様です。
// 良い例:onclickイベントハンドラの中で、同期的にwindow.open()を呼び出す
button.addEventListener("click", () => {
window.open("https://example.com", "_blank");
});// 悪い例:ページ読み込み時に自動で実行される(ユーザー操作を伴わない)
window.addEventListener("load", () => {
// これはほぼ全てのブラウザでブロックされる
window.open("https://example.com", "_blank");
});筆者が現場で最初に混乱したのは、「同じwindow.open()のコードなのに、書く場所によって動いたり動かなかったりする」という現象でした。原因はコードの中身ではなく、実行される「タイミング」がユーザー操作から離れているかどうかにありました。実装時は、必ず「このコードはクリックイベントの中で、遅延なく実行されているか」を意識するようにしてください。
fetchやsetTimeoutなど非同期処理完了後に確実にwindow.openを発火させる裏技
onclickの中に書いていても、fetchやsetTimeoutなどの非同期処理を挟んでその完了後(コールバックやthenの中、awaitの後)にwindow.open()を呼び出すと、多くのブラウザでブロック対象になります。これは、非同期処理の完了タイミングが「ユーザー操作から時間的に離れてしまう」ため、ブラウザ側がユーザー操作起因のイベントと判断できなくなるためです。
// 悪い例:fetch完了後にwindow.openを呼ぶと、ブロックされる可能性が高い
button.addEventListener("click", async () => {
const res = await fetch("/api/redirect-url");
const data = await res.json();
window.open(data.url, "_blank"); // ← awaitの後なのでブロックされやすい
});回避策としてよく使われるのが、「先に空のウィンドウを同期的に開いておき、非同期処理が終わったタイミングでlocationを書き換える」という実装パターンです。
// 良い例:クリック直後に同期的に空のウィンドウを開いておく
button.addEventListener("click", async () => {
// クリックイベント内で同期的にwindow.open()を呼ぶことで、ブロックを回避する
const newWin = window.open("", "_blank");
try {
const res = await fetch("/api/redirect-url");
const data = await res.json();
// 非同期処理の完了後、開いておいたウィンドウのlocationを書き換える
if (newWin) {
newWin.location.href = data.url;
}
} catch (error) {
// 通信に失敗した場合は、開いておいたウィンドウを閉じておく
if (newWin) newWin.close();
console.error("リダイレクト先の取得に失敗しました", error);
}
});この「先に空ウィンドウを開いておく」パターンは、API通信を挟んで遷移先を決定するような実務のケースで非常によく使われるため、ぜひ覚えておいてください。
戻り値(null/undefined)を利用したポップアップブロック発生の検知とエラー判定方法
window.open()は、ブラウザがブロックした場合や新しいウィンドウの生成に失敗した場合、戻り値としてnullを返します。この戻り値をチェックすることで、「ユーザーにポップアップブロックの解除を促す」といったフォールバック処理を実装できます。
// 戻り値をチェックしてポップアップブロックを検知する
const newWin = window.open("https://example.com", "_blank");
if (newWin === null || typeof newWin === "undefined") {
// ブロックされた場合の処理(ユーザーへの案内など)
alert("ポップアップがブロックされました。ブラウザの設定をご確認ください。");
} else {
// 正常に開けた場合はフォーカスを移しておくと親切
newWin.focus();
}なお、Cross-Origin-Opener-Policy(COOP)ヘッダーが設定されているページでは、新しいウィンドウが別のブラウジングコンテキストグループで開かれ、参照が切り離されてclosedプロパティがtrueになるケースもあります。単純なnull判定だけでなく、こうしたセキュリティヘッダー起因の挙動があることも頭の片隅に置いておくと、原因不明のトラブルに直面した際に落ち着いて調査できます。
ブラウザごとの挙動差異
Chromeは比較的緩やかにユーザー操作からの遅延を許容する一方、Safari(特にiOS Safari)はポップアップブロックの判定が厳しく、awaitを一つ挟んだだけでもブロックされることがあります。Android Chromeはデスクトップ版Chromeに近い挙動をしますが、端末やOSのバージョンによって差が出ることもあるため、本番環境ではiOS Safari実機での動作確認を必ず行うことをおすすめします。Firefoxもユーザー操作起因かどうかを厳格にチェックする傾向があり、ブラウザ間で「動いたり動かなかったり」する代表的な原因の一つです。
あわせて読みたい


開いた子ウィンドウの操作:再利用・閉じる処理・window.postMessage連携
window.open()で開いたウィンドウ(子ウィンドウ)は、開きっぱなしにするだけでなく、閉じる・再利用する・親ウィンドウとデータをやり取りするといった制御が実務では頻繁に求められます。結論として、子ウィンドウの制御は「戻り値のWindowProxyオブジェクトを変数に保持しておく」ことがすべての基本になります。この参照さえ持っておけば、閉じる・状態確認・通信のいずれも実現できます。

window.close()で画面を閉じる方法とclosedプロパティでの開閉状態チェック
子ウィンドウを閉じたい場合は、window.open()の戻り値に対してclose()メソッドを呼び出します。また、そのウィンドウが既に閉じられているかどうかはclosedプロパティで判定できます。
// 子ウィンドウを開く際に、戻り値を変数に保持しておく
let childWindow = window.open("https://example.com", "_blank");
// 任意のタイミングで子ウィンドウを閉じる
function closeChildWindow() {
if (childWindow && !childWindow.closed) {
childWindow.close();
}
}
// 子ウィンドウが閉じられているかどうかをチェックする
function checkChildWindowStatus() {
if (childWindow === null) {
console.log("そもそもウィンドウを開けていません");
} else if (childWindow.closed) {
console.log("子ウィンドウは既に閉じられています");
} else {
console.log("子ウィンドウは開いたままです");
}
}実務で起こりやすい失敗が、「子ウィンドウの参照をローカル変数として関数内に閉じ込めてしまい、別の関数からclose()を呼べなくなる」というケースです。子ウィンドウを後から操作する必要がある場合は、必ずモジュールスコープやコンポーネントのstateなど、複数の処理から参照できる場所にWindowProxyを保持しておくようにしましょう。なお、ユーザーが子ウィンドウのタブを手動で閉じた場合でもclosedプロパティは自動的にtrueに更新されるため、定期的にポーリングして状態を監視するといった実装も可能です。
同じウィンドウ名を指定して既存タブを新規立ち上げせずに再利用・フォーカスする技
window.open()の第2引数(ターゲット名)に同じ文字列を指定すると、既にそのウィンドウ名で開かれているタブ・ウィンドウが存在する場合は新規作成されず、既存のものが再利用されます。これを利用すると「同じボタンを何度クリックしても、タブが増殖しない」実装が可能になります。
// 同じウィンドウ名("previewWindow")を指定することで、既存のタブを再利用する
function openPreview(url) {
// 2回目以降のクリックでは、新しいタブが増えずに既存タブのURLが更新される
const win = window.open(url, "previewWindow");
if (win) {
// 既存タブが背面に隠れている場合に備えて、前面にフォーカスを移す
win.focus();
}
}注意点として、この「再利用」はウィンドウ名が一致している場合のみ機能します。第2引数を毎回_blankにしていると、クリックのたびに新しいタブが際限なく増えていくため、「プレビュー用のタブは1つに固定したい」といった要件では、_blankではなく固定の文字列(例:previewWindow)を指定するのがポイントです。また、URLが変わっても同じウィンドウ名であれば同じタブ内でページが遷移するだけなので、都度focus()を呼んでユーザーの目線を新しい内容に誘導する配慮も忘れないようにしましょう。
クロスドメイン環境で安全に親子通信を行うwindow.postMessageの実装方法
親ウィンドウと子ウィンドウが同一オリジン(同じドメイン)であればwindow.openerや戻り値のオブジェクトから直接プロパティにアクセスできますが、異なるドメイン間(クロスオリジン)では、ブラウザの同一オリジンポリシーにより直接アクセスできません。この制約を安全に回避するための標準的な手段がwindow.postMessage()です。
// 【親ウィンドウ側】子ウィンドウを開き、メッセージを受け取る準備をする
const childWindow = window.open("https://child.example.com", "_blank");
// 子ウィンドウからのメッセージを受信するリスナーを登録
window.addEventListener("message", (event) => {
// 送信元オリジンを必ず検証する(セキュリティ上、最重要のチェック)
if (event.origin !== "https://child.example.com") {
return; // 想定外のオリジンからのメッセージは無視する
}
console.log("子ウィンドウから受信:", event.data);
});// 【子ウィンドウ側】親ウィンドウ(opener)へメッセージを送信する
if (window.opener) {
// 第2引数には、送信先として許可するオリジンを明示的に指定する
window.opener.postMessage(
{ type: "FORM_SUBMITTED", payload: { id: 123 } },
"https://parent.example.com"
);
}postMessageを実装する際に最も見落とされがちなのが、受信側でのevent.originの検証です。この検証を省略すると、悪意のある第三者のページから偽装したメッセージを受け取ってしまい、意図しない処理が実行されるリスクがあります。第2引数(送信先オリジン)を"*"(ワイルドカード)に設定すれば動作はしますが、これは「誰にでもメッセージを送ってよい」という意味になり本番環境では推奨されません。開発時は動作確認のために"*"を使うことがあっても、リリース前には必ず具体的なオリジンを指定するように修正してください。この一手間が、後述するセキュリティ対策(noopener・noreferrer)とあわせて、安全な別ウィンドウ実装の土台になります。
コストパフォーマンスに優れた高性能なレンタルサーバー
【Hostinger】セキュリティ対策:noopener・noreferrer の正しい指定方法
window.open()やtarget="_blank"で開いた別タブは、便利な反面、正しくセキュリティ対策をしないと「タブジャッキング(reverse tabnabbing)」と呼ばれる攻撃の入り口になり得ます。結論として、外部サイトへのリンクを別タブで開く際は、必ずnoopenerとnoreferrerをセットで指定することが、コードレビューでも指摘されないための最低限のルールです。ここでは攻撃の仕組みから、HTML・JavaScript両方での正しい実装方法まで解説します。

タブジャッキング・reverse tabnabbing 攻撃の仕組みと危険性
target="_blank"やwindow.open()で新しいタブを開いた場合、デフォルトの挙動によっては、開かれた側(子ウィンドウ)のページからwindow.openerというプロパティを通じて、開いた元のページ(親ウィンドウ)を操作できてしまうことがあります。
具体的な攻撃のイメージは以下の通りです。
- 悪意のあるサイトが、一見無害なリンクを設置する
- ユーザーがそのリンクをクリックし、新しいタブで悪意のあるサイトが開く
- 新しく開いたタブ(悪意のあるサイト)が、
window.opener.locationを書き換え、元のタブ(親ウィンドウ)を偽のログインページに差し替える - ユーザーは元のタブに戻った際、URLバーは正規のサイトのままなのに、表示されている中身だけが偽のログインページになっていることに気づかず、IDやパスワードを入力してしまう
この攻撃が厄介なのは、ユーザーが見ているタブのURLは変わらないため、フィッシングサイトだと気づきにくい点にあります。「新しいタブを開いただけなのに、元のタブが乗っ取られる」という直感に反する挙動のため、対策を知らないと防ぎようがありません。
rel=”noopener noreferrer” を付与するHTMLとJavaScriptの両方の実装
このリスクへの対策はシンプルで、開かれた側のページからwindow.openerにアクセスできないようにすることです。HTMLの<a>タグではrel属性にnoopenerとnoreferrerを指定します。
<!-- HTML側の対策:target="_blank"を使う場合は必ずrel属性を併記する -->
<a href="https://external-site.example.com" target="_blank" rel="noopener noreferrer">
外部サイトへのリンク
</a>- noopener: 新しく開いたページから
window.openerをnullにし、親ウィンドウへの参照を断ち切る - noreferrer: 上記に加えて、リンク元のURL情報(リファラー)が遷移先に送信されないようにする
JavaScriptのwindow.open()で同様の対策を行う場合は、第3引数(windowFeatures)にnoopenerとnoreferrerを指定します。
// JavaScript側の対策:第3引数にnoopener,noreferrerを指定する
window.open(
"https://external-site.example.com",
"_blank",
"noopener,noreferrer"
);なお、モダンブラウザ(Chrome、Firefox、Safariの最新版)では、target="_blank"を指定した<a>タグにrel="noopener"を明示的に書かなくても、デフォルトでnoopener相当の挙動になるよう仕様が変更されています。しかし、この挙動はブラウザのバージョンに依存するため、古いブラウザとの互換性やコードレビューでの明確さを考慮すると、明示的にrel="noopener noreferrer"を記述しておくことを強く推奨します。「デフォルトで安全だから書かなくていい」と判断してしまうと、対応ブラウザの範囲が変わった際に思わぬ脆弱性を生む可能性があるためです。
window.opener を使った親ウィンドウ操作のリスクと noopener 無効化の対策
前述の通り、window.openerは本来、親子ウィンドウ間で正当な連携を行うための機能です。しかし、この参照が悪用されると前述のタブジャッキングにつながるため、信頼できない外部サイトへのリンクには常にnoopenerを付与し、window.openerへのアクセス自体を遮断することが基本方針になります。
// 自社の管理画面など、信頼できる同一オリジンの子ウィンドウとの連携では
// window.openerを使った直接操作が有効なケースもある
if (window.opener && !window.opener.closed) {
// 親ウィンドウ側の関数を呼び出して、処理結果を伝える(同一オリジンの場合のみ)
window.opener.postMessage({ status: "completed" }, window.location.origin);
}一方で、外部の信頼できないサイトへのリンクに対して誤ってnoopenerを付け忘れると、window.openerが有効なまま残ってしまいます。コードレビューチェックリストとしては、「target="_blank"またはwindow.open()を新規に書いたら、必ずnoopenerとnoreferrerがセットになっているかを確認する」というルールを徹底することをおすすめします。これは今回紹介したセキュリティ対策の中でも、最も見落とされやすく、かつ最も基本的な確認項目です。
実践的な活用シーン別の実装例
ここまで基本仕様・ポップアップブロック対策・セキュリティ対策を解説してきました。ここからは、実務で実際によく遭遇する4つのシーン(PDFプレビュー、TypeScript、jQuery、バナー広告)について、それぞれの実装パターンを具体的なコードとともに紹介します。結論として、基本の書き方は共通しているものの、シーンごとに「型」「ライブラリの流儀」「広告出稿先の仕様」といった個別の注意点があるため、案件に合わせて該当箇所を参照してください。

PDF・画像・Blob URLを別タブでプレビュー表示する方法
サーバーから返却されたPDFファイルや画像を、ダウンロードさせずにその場でプレビュー表示したいというニーズは非常に多くあります。静的なURLであればそのままwindow.open()に渡すだけですが、APIレスポンスとして受け取ったバイナリデータ(Blob)を表示したい場合は、URL.createObjectURL()を使ってBlob URLを生成します。
// 静的なPDFファイルのURLを別タブでプレビュー表示する場合
window.open("https://example.com/files/document.pdf", "_blank", "noopener,noreferrer");// APIから取得したPDFのBlobデータを別タブでプレビュー表示する場合
async function previewPdfFromApi() {
const response = await fetch("/api/generate-pdf");
const blob = await response.blob();
// BlobデータからブラウザでアクセスできるURL(Blob URL)を生成する
const blobUrl = URL.createObjectURL(blob);
// 生成したBlob URLを新しいタブで開く
const newWin = window.open(blobUrl, "_blank", "noopener,noreferrer");
if (newWin) {
// メモリリークを防ぐため、一定時間後にBlob URLを解放する
newWin.addEventListener("load", () => {
setTimeout(() => URL.revokeObjectURL(blobUrl), 60000);
});
}
}ここでよく見落とされがちなのが、URL.revokeObjectURL()によるメモリ解放です。Blob URLは発行したままにしておくとブラウザのメモリを占有し続けるため、プレビュー用タブでの表示が完了したと想定できるタイミングで解放する処理を入れておくと、長時間利用されるアプリケーションでのメモリリークを防げます。なお、前述の非同期処理とポップアップブロックの関係上、fetch完了後にwindow.open()を呼ぶ今回のコードはブロックされる可能性があるため、実際の実装では先に空ウィンドウを開いておく手法と組み合わせることをおすすめします。
TypeScriptでwindow.open()を使う際のWindowProxy型エラー対処法
TypeScriptでwindow.open()を使うと、戻り値の型はWindow | nullとして推論されます。この型を正しく扱わずにnewWin.focus()のようにアクセスすると、「オブジェクトは ‘null’ である可能性があります」といった型エラーが発生します。
// 戻り値の型は Window | null として推論される
const newWin: Window | null = window.open("https://example.com", "_blank");
// null チェックを行わずにアクセスするとコンパイルエラーになる
// newWin.focus(); // Error: Object is possibly 'null'.
// 正しくは、null チェック(オプショナルチェイニング)を行ってからアクセスする
newWin?.focus();
// 早期リターンで明示的にガードする書き方も可読性が高くおすすめ
function openAndFocus(url: string): void {
const win = window.open(url, "_blank", "noopener,noreferrer");
if (!win) {
console.warn("ウィンドウを開けませんでした");
return;
}
win.focus();
}TypeScriptのエラーは一見面倒に感じますが、「ポップアップブロックによってnullが返ってくる可能性」をコンパイル時に強制的に意識させてくれる、実は親切な仕組みです。as Windowのような型アサーションで無理やりnullの可能性を握りつぶすのではなく、オプショナルチェイニング(?.)や早期リターンで正しくガードすることで、本番環境でのランタイムエラーを未然に防げます。
jQuery環境でwindow.open()をイベントハンドラと組み合わせる書き方
レガシーな案件では、jQueryのイベントハンドラの中でwindow.open()を呼び出す場面もまだ存在します。基本的な考え方はネイティブJavaScriptと変わらず、clickイベントハンドラの中で同期的に呼び出すことがポイントです。
// jQueryのclickイベントハンドラ内でwindow.open()を呼び出す
$("#openButton").on("click", function (event) {
event.preventDefault(); // aタグ等のデフォルト動作をキャンセルする場合
const url = $(this).data("url"); // data-url属性からリンク先を取得
const newWin = window.open(url, "_blank", "noopener,noreferrer");
if (!newWin) {
alert("ポップアップがブロックされました");
}
});jQuery自体にはwindow.open()をラップする専用APIは用意されていないため、上記のようにイベントハンドラの中でネイティブのwindow.open()をそのまま呼び出す形で問題ありません。注意点は、$.ajax()のコールバック(非同期処理)の中でwindow.open()を呼ぶと、前述の通りブロックされやすくなることです。jQueryを使っている案件は歴史が長く、$.ajaxの成功コールバック内にwindow.open()が書かれているレガシーコードも少なくないため、改修時にはブロックされていないか実機で確認することをおすすめします。
バナー広告制作におけるwindow.clicktagを使った遷移処理の実装
Web広告(特にディスプレイ広告・バナー広告)の制作では、広告配信プラットフォーム側が遷移先URLを動的に注入する仕組みとしてclicktagという変数がよく使われます。window.clicktagをそのままwindow.open()に渡すのが基本パターンです。
// グローバル変数clicktagは、広告配信プラットフォーム側から動的に注入される
// (配信先によっては window.clickTag のように大文字小文字が異なる場合があるので要注意)
var clickTag = clickTag || "https://example.com/lp/";
document.getElementById("bannerLink").addEventListener("click", function () {
// clicktagで指定されたURLを新しいタブで開く
window.open(clickTag, "_blank", "noopener,noreferrer");
});バナー広告制作で特に注意すべき点は、配信プラットフォーム(Google広告、Yahoo!広告など)ごとにclicktagの変数名の記法(clickTagかclickTAGか等)や実装ルールが微妙に異なることです。入稿前には必ず配信先プラットフォームの最新の入稿規定を確認し、指定された変数名・実装方法に厳密に従うようにしてください。ここでの実装ミスは、審査落ちや正しくクリック計測が行われない原因に直結します。

よくある質問(FAQ)
ここでは、記事本文では触れきれなかった細かい疑問や、実際に検索されることが多い関連キーワードをもとに、Q&A形式で回答します。
-
window.openを書いたのに効かない・動かないのはなぜですか?
-
最も多い原因は「ポップアップブロック」です。
onclickイベントハンドラの外(ページ読み込み時やsetTimeoutの中など)で実行していないか、fetchやasync/awaitなどの非同期処理の後に呼び出していないかを確認してください。また、window.open()の戻り値がnullになっていないかコンソールで確認することで、ブロックされているかどうかを切り分けられます。第2引数(ターゲット名)に誤ってwindowFeatures用の文字列を渡していないかも、あわせてチェックするポイントです。
-
window.openのポップアップブロックを解除する方法はありますか?
-
ユーザー側でブラウザの設定からポップアップブロックを解除することは可能ですが、Webサイト制作者側からユーザーに設定変更を強制することはできません。開発者側での対策としては、本文で紹介した「クリックイベント内で同期的に
window.open()を呼び出す」実装に修正することが最も確実な解決策です。どうしても非同期処理を挟む必要がある場合は、「先に空のウィンドウを開いておき、後からlocationを書き換える」パターンを使ってください。
-
window.openがスマホ(iPhone・Android)で開かない・別タブにならないのはなぜですか?
-
iOS SafariはPCのブラウザよりもポップアップブロックの判定が厳しく、非同期処理を挟んだ
window.open()はブロックされやすい傾向があります。また、LINEやInstagramなどのアプリ内ブラウザ(WebView)では、window.open()自体が無効化されていたり、新しいタブという概念がなく同一画面内で開かれたりする場合もあります。スマホ向けの実装では、実機での動作確認を必ず行い、アプリ内ブラウザで開かれる可能性がある場合は<a target="_blank">とあわせてフォールバック的な導線(コピー用のURL表示など)を用意しておくと安心です。
-
window.open()で開いたウィンドウのサイズや位置が指定通りにならないのはなぜですか?
-
widthやheight、left、topを指定しても、ユーザーの画面の作業領域からはみ出す指定をした場合、ブラウザ側で自動的に位置やサイズが補正され、画面外に一部でもはみ出さないように調整されます。また、Chromeの最新版ではpopupの指定がない状態でscrollbarsやtoolbarといったレガシーな機能名を指定しても、見た目の細かい制御には反映されず、単に「ポップアップとして開くかどうか」の判定にのみ影響する仕様になっています。UIを厳密に制御したい場合は、期待通りの挙動になっているか主要ブラウザ(Chrome・Safari・Firefox)でそれぞれ確認することをおすすめします。
-
window.opener(ウィンドウオープナー)とは何ですか?何に使うのですか?
-
window.openerは、window.open()によって開かれた子ウィンドウ側から、開いた元の親ウィンドウを参照するためのプロパティです。同一オリジンの管理画面同士でデータを連携したい場合などに使われますが、外部の信頼できないサイトへのリンクでこの参照が残っていると、本文で解説した「タブジャッキング」のリスクにつながります。外部サイトへのリンクには必ずnoopenerを指定し、window.openerへのアクセスを遮断しておくことが安全な実装の基本です。
-
noopenerを指定すると、window.openの戻り値やpostMessageによる通信に影響はありますか?
-
はい、大きな影響があります。noopenerを指定してwindow.open()を実行すると、セキュリティ上の理由から親ウィンドウと子ウィンドウの参照が完全に切断されます。
このため、子ウィンドウのwindow.openerがnullになるだけでなく、親ウィンドウ側で受け取るwindow.open()の戻り値も強制的にnullになります。戻り値がnullになるため、親ウィンドウから開いた子ウィンドウに対してpostMessage()でメッセージを送信したり、close()で画面を閉じたりすることはできなくなります。
もし、開いた別タブと通信を行ったり、親側からタブを閉じる制御が必要な場合は、対象が自社システムなどの信頼できるサイトであることを前提に、noopenerを指定せずに実装する必要があります。その上で、通信にはpostMessage()を使用し、必ずevent.originを検証して安全性を担保する設計にしてください。
-
window.open()とlocation.hrefやwindow.location.assign()はどう違いますか?
-
window.open()は新しいタブ・ウィンドウを生成して別のブラウジングコンテキストでページを開くのに対し、location.hrefやwindow.location.assign()は現在表示しているタブ自体のURLを書き換えて、同一タブ内でページ遷移させる点が根本的に異なります。フォーム送信後のリダイレクトのように「同じタブで次のページに進みたい」場合はwindow.locationを、「元のページを表示したまま別の情報を並行して見せたい」場合はwindow.open()を使う、という使い分けが基本になります。
まとめ
window.open()は、JavaScriptから新しいタブやウィンドウを開くために利用できる便利なAPIです。基本的な構文はシンプルですが、実際のWeb制作ではポップアップブロックや非同期処理、セキュリティなども考慮する必要があります。
特に重要なのは、単にwindow.open()を呼び出せばよいわけではなく、用途に応じて適切な方法を選ぶことです。単純にリンクを別タブで開くだけなら<a target="_blank">が適しているケースもあります。一方、JavaScriptによる条件分岐やウィンドウの制御が必要な場合はwindow.open()が役立ちます。
この記事の重要ポイントを整理すると、以下のとおりです。
window.open()は「別タブを開くためのコード」とだけ覚えるのではなく、ポップアップブロック・セキュリティ・ユーザー体験まで含めて使い分けることが大切です。基本的な仕組みを理解しておけば、WebサイトやWebアプリのさまざまな場面で、安全かつ適切に活用できるようになります。



