以前リリースしたとあるサービスで、「一部の入力フォームを別ウィンドウをポップアップして入力させ、終わったらリンクをクリックして閉じる」という JavaScript の処理を入れていたのですが、なぜか2015年頃から Chrome で画面が固まってしまう不具合が発生しました。2014年の春にテストした時は問題なく動いていたのですが。
どうやらブラウザーのバージョンアップに伴い、正しく子ウィンドウを閉じるための方法が変化してしまったようです。今ならどう実装するべきなのかを、少し検証してみました。
再現方法
不具合は以下の流れで発生します。確認したブラウザは Chrome 39.0.2171.99m (Windows) です。
- 親ウィンドウにある
<a onClick="window.open()">
リンクを叩き、子ウィンドウをポップアップさせる。 - 子ウィンドウにある
<a onClick="window.open('about:blank','_self').close()">
リンクを叩く。 - 親・子ウィンドウ両方が固まってしまう。
ウィンドウを閉じるために window.close()
ではなく window.open('about:blank','_self').close()
と書いているのは、IE/FF/Chrome いずれのブラウザーでも綺麗に閉じるための有名な Hack だったからです。詳細は JavaScriptでWindow.closeする時のブラウザ別対応まとめ - TechNote がわかりやすいです。
検証
以下の2つの HTML を用意します。
<html lang="en">
<head>
<title>Parent</title>
</head>
<body>
<!-- 子ウインドウをポップアップする -->
<a href="#" onClick="window.open('popup_child.html', 'child', 'width=300,height=300');">Open popup window</a>
</body>
</html>
<html lang="en">
<head>
<title>Child</title>
</head>
<body>
<!-- 子ウインドウ(自分自身)を閉じる -->
<a href="#" onClick="window.open('about:blank', '_self').close()">Close (ハック版)</a>
<a href="#" onClick="window.close();">Close (単純版)</a>
</body>
</html>
検証手順は以下の通り。
- popup_parent.html にアクセスし、
Open popup window
リンクを叩く。 - 子ウィンドウが開くので、
Close (ハック版)
とClose (単純版)
の2つのリンクをそれぞれ叩き、正しく閉じられるかどうかを記録する。
検証結果は次のようになりました。「o」は閉じられた場合、「x」は閉じられなかった場合です。
ブラウザー | ハック版 | 単純版 |
---|---|---|
IE 10 | o | o |
Chrome 39.0.2171.99m | x | o |
FireFox 34.0.5 | o | o |
Safari 5.1.7 | o | o |
Chrome だけハック版がうまく動かないという結果になりました。
悪さをしているのは WebKit なのかと思い、一応 Safari でも実験しましたが、問題はありませんでした。よって、今のところは Chrome だけ処理を分けるようにすれば良さそうです。ただし、Safari の WebKit は若干バージョンが古い (Safari = WebKit/534.57.2, Chrome = Webkit/537.36) ので、今後のバージョンアップでどうなるかは不明です。
解決策
検証結果から、全て単純版の書き方にすれば解決するように見えますが、一応古いブラウザーとの互換性を考えて、Chrome だけ単純版に分岐するような JS にしました。
<a href="#" onClick="if (/Chrome/i.test(navigator.userAgent)) { window.close(); } else { window.open('about:blank', '_self').close(); }">閉じる</a>
これでどのブラウザーでも閉じられるようになりました。