2回目以降のwindow.openでの各ブラウザでのフォーカスについて

window.openとかリンクタグで、新規にタブ/ウィンドウを開くときに、フォーカスが新規タブ/ウィンドウに移動するのは、どのブラウザでも問題ない気がする(少なくとも自分が持ってるPC、スマホ環境では)。
ただ、既に開いているタブ/ウィンドウのtargetに対して、再度 window.openとかリンクタグで開いてみると、ブラウザによってはフォーカスが移動しなかったりする。

検証してみた環境は以下。

  • Windows 10Pro 20H2:Chrome 93、Firefox 92、IE11
  • Android 8.0:Chrome 93
  • iOS 14.7:Safari

検証

ウィンドウ/タブを開く方法は以下。

  1. リンクタグ(aタグ)でタブを開く
  2. window.openでタブを開く
  3. window.openでウィンドウを開く

検証コードは以下。

<body>
  <h1>画面A</h1>
  <a href="./test_windowopen2.html" target="hoge">1. リンクでタブを開く</a>
  <br />
  <button onclick="openTab()">2. window.openでタブを開く</button>
  <br />
  <button onclick="openWindow()">3. window.openでウィンドウを開く</button>

  <script>
    function openTab() {
      window.open('./test_windowopen2.html', 'hoge');
    }

    function openWindow() {
      window.open('./test_windowopen2.html', 'hoge', 'width=1024,height=800,resizable=yes,scrollbars=yes');
    }
  </script>
</body>

検証結果

上記の検証コードでの結果は以下。

  • どの方法でもフォーカスが移動する
    ⇒ Windows 10 Chrome/Firefox、Android Chrome
  • どの方法でもフォーカスが移動しない
    ⇒ Windows 10 IE11、iOS Safari

そこで、window.open後に、フォーカスを移動させるように修正して再度実験。

function openTab() {
  const w = window.open('./test_windowopen2.html', 'hoge');
  w.focus();
}

function openWindow() {
  const w = window.open('./test_windowopen2.html', 'hoge', 'width=1024,height=800,resizable=yes,scrollbars=yes');
  w.focus();
}

上記の検証コードでの結果は以下。

  • どの方法でもフォーカスが移動する
    ⇒ Windows 10 Chrome/Firefox、Android Chrome
  • window.openでウィンドウを開く場合だけフォーカスが移動する
    ⇒ Windows 10 IE11
  • どの方法でもフォーカスが移動しない
    ⇒ iOS Safari

ちなみに、iOS Chrome、iPad OS Safari/Chrome でも、フォーカスは移動しなかった。

iOS Safariの場合、どうフォーカスさせようか

IE11でフォーカスが移動しないとしても、IE自体2022年6月でサポート終了するので無視しても構わないが、iOS Safariで解決したい場合はどうするか。

いろいろ考えてみたものの、結局は一度閉じて開き直す、というのが一番簡単。

let winB;
function openTab() {
  if (winB) {
    winB.close();
  }
  winB = window.open('./test_windowopen2.html', 'hoge');
}

ただし、この場合、子画面の方は一旦閉じるので、子画面上で保持していたデータ等を継続して利用したいケースにおいて対応を考える必要がある。

以下のサンプルでは、フラグメント識別子(#以後の文字列)付きのURLで window.open しているが、この場合には2回目以降の window.open はサーバからページを再取得してリロードするわけではなく、フラグメント識別子だけが変更される(loadイベントではなく、hashchangeイベントが発生する)。
そのため、2回目以降の window.open でも子画面上で何らかのデータを保持していても消えることはない。

↓ 親画面(スクリプト部分だけ)

function openTabWithTimestamp() {
  window.open('./test_windowopen2.html#' + Date.now(), 'hoge');
}

↓ 子画面

<body>
  <h1>画面B</h1>
  <div>
    親画面からの呼出:
    <strong id="inittime"></strong>
  </div>
  <div>
    親画面からのリロード:
    <strong id="reloadtime"></strong>
  </div>
  <script>
    window.addEventListener('load', (e) => {
      if (location.hash) {
        const elem = document.getElementById('inittime');
        elem.innerText = (new Date(location.hash.substring(1) - 0)).toLocaleString();
      }
    });
    window.addEventListener('hashchange', (e) => {
      if (location.hash) {
        const elem = document.getElementById('reloadtime');
        elem.innerText = (new Date(location.hash.substring(1) - 0)).toLocaleString();
      }
    });
  </script>
</body>

上記のケースにおいて、2回目以降の window.open でフォーカスを移すために、一度閉じて開き直すという操作をしたら、子画面上で保持していたデータは消えてしまう。

というわけで、上記のようなケースの場合を考えていくと、postmessageで連携させたり、localstorageに一時保存させたり、、と面倒くさいなーと。。

まあ、スマホで手動でタブをあっちこっち移動させて操作させるということは、あまり考えられない(そういう画面遷移設計にしない)ので、あまり考える必要もないかをも思うが。

以上です。