こんにちは!のせっち@nosecchi01です!
クライアントさんの要望で「ブラウザバックでお客さんが離れてしまう前に、広告を出したい」という要望があるかもしれません。
そういう要望に応えるために、ブラウザバックでモーダルを出現させる方法をご紹介します。
機能としては以下です。
- ブラウザの戻るを押すと、モーダルが出現
- モーダルを閉じると戻るを実行
注意点:ブラウザバックの制御はGoogle Chromeではできない
これからご紹介する方法ですが、僕が確認した限りでは(2021年11月現在)Google Chromeでは再現不可能です。
理由は、こちらの記事が詳しいです。
記事で紹介されている元の英文記事では禁止する方向となっていますが、既に実装済みではないかと思います。(確定情報ではないです)
ユーザーの意図していない動作を返すのはユーザー体験としては良くないので、クライアントさんから実装を求められた場合、まずは理由を説明した上でお断りすることをおススメします。
現状ではChromeのみですが、他ブラウザが追随する可能性は十分にあります。
それでも、どうしても、実装が必要な場合は以下をどうぞ!
完成図を確認する
まずはcodepenをご確認ください。
See the Pen 戻るでモーダルを出現させる by Yuki Nose (@yukinouz1) on CodePen.
「前のページに戻る」ボタンを押すと、閉じるボタンが出現します。
モーダルといいつつ、ボタンしか出てきませんが、今回モーダルの見た目は本筋ではないので省略です
codepenでは再現しないですが、「閉じる」を押すと、ブラウザバックしてくれます。
codepenで戻るが再現しない理由は戻るページが存在しないためです。
「アバウトへ」は適当なリンクを付けています。通常のリンクタグではモーダルが出現しないことが確認できます。
一度閉じるを押した後は、「前のページに戻る」ボタンを押しても何も起きなくなります。
戻るのたびにモーダルが出ていたら一生外に出られないので、一度だけ実行するようにしています。
「戻るを押したらモーダルを出す」に必要な機能をおさらいしましょう!
- ブラウザバックしたら発火する(モーダルが出現する)
- モーダルを閉じたらブラウザバックする
- 他のaタグなどをクリックしてもモーダルは出てこない。
- モーダルを閉じたら、二度とモーダルは出てこない。
機能をわかっていただけたところで、中身を解説していきます!
解説
javascriptを中心に解説していきます。
まずは全体のコードです。
let modalState = false;
window.addEventListener("popstate", (e) => {
// aタグクリックや進むボタンでの遷移時にも呼ばれるので、モーダルが出てないかつstateがpushedの場合のみモーダルを出す
if (modalState || e.state !== "pushed")
return;
// fadeIn/fadeOutはjQueryを使う
$("#js-modal").fadeIn();
$(".js-modal-close").on("click", ()=> {
$("#js-modal").fadeOut();
modalState = true;
window.history.back();
})
});
const onload = () => {
window.history.replaceState("pushed", null, null); // 現在のページにstateを付加してpopstateイベントで判定する
const entries = performance.getEntriesByType("navigation");
if (entries.some((item) => item.type === "reload")) {
return;
} else {
window.history.pushState("pushed", null, null); // 戻るボタンを有効化させるためにヒストリを一つ追加する
}
};
window.addEventListener("load", ()=> {
onload();
});
ここからは更に分解して解説していきます。
let modalState = false;
modalStateはモーダルが開いたらtrueにします。(後ほど出てきます)モーダルが開いたかどうかを判定して、一度開いた(trueになった)ら二度と戻るでモーダルが出ないようにするためです。
window.addEventListener("popstate", (e) => {
// aタグクリックや進むボタンでの遷移時にも呼ばれるので、モーダルが出てないかつstateがpushedの場合のみモーダルを出す
if (modalState || e.state !== "pushed")
return;
});
popstateは戻るボタンを押したかどうかを判定します。
if (modalState) は先ほど解説した通りで、modalState === true
ならです。 e.state !== "pushed"
は後ほど解説しますが、後半のコードでヒストリを操作するので、state !== "pushed"
なら、となります。
どちらかの条件を満たす場合は、return;
で処理を抜けます。(モーダルは出さない)
$("#js-modal").fadeIn();
$(".js-modal-close").on("click", ()=> {
$("#js-modal").fadeOut();
modalState = true;
window.history.back();
})
fadeIn()
はfadeOut()
はjQueryが便利なのでjQueryを使っています。
戻るを押したら、#js-modal
をfadeInです。
.js-modal-close
で以下の処理を行います。
- モーダルを閉じる(fadeOut)
- modalState を trueにする
- 「戻る」を実行
ここをIDではなくClassにしている理由は、モーダルではよく背景クリックでも閉じるを実行したりするためで、同一class名が存在する前提でclassにしています。
modalState = true
modalStateをtrueにすることで、次に戻るを押してもモーダルが出現しないようにします。
window.history.back();
モーダルを閉じたら、ユーザーが本来意図した戻るを実行してあげます。
モーダルを閉じるだけで、ページに留めることもできますが、ユーザーは「戻る」を押したのに、モーダルが出てきている状態になっています。これは意図しない挙動なので、閉じるを押したら戻るを実行して本来の挙動に戻します。
次に進みます。
const onload = () => {
window.history.replaceState("pushed", null, null); // 現在のページにstateを付加してpopstateイベントで判定する
// 省略
};
history.replaceState(state, title[, url]);
で現在の履歴(ヒストリー)を置換することができます。
const entries = performance.getEntriesByType("navigation");
if (entries.some((item) => item.type === "reload")) {
return;
} else {
window.history.pushState("pushed", null, null); // 戻るボタンを有効化させるためにヒストリを一つ追加する
}
};
const entries = performance.getEntriesByType("navigation");
if (entries.some((item) => item.type === "reload")) { return; }
リロードを無視するために書いています。これを書かないとリロードの度にヒストリが増えてしまうので必ず書いておきましょう!
window.history.pushState("pushed", null, null);
でpushedをヒストリに追加しています。戻るボタンを右クリックすると、同一ページが追加されていて、ヒストリが追加されていることがわかります。
window.addEventListener("load", ()=> {
onload();
});
定義したonloadを実行しています。
解説は以上です!
お疲れ様でした!
まとめ
・javascriptを使って、戻るを実行した際に何かアクションを起こすことができる。
・Google Chromeでは再現しない。
・ユーザービリティ的によくないので、実装する際は本当に必要な機能なのかよくよく検討する。