3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

javaScriptでブラウザバックに対応したモーダルウィンドウを設置する

Last updated at Posted at 2021-10-29

モーダルウィンドウの仕様

  • 現在、表示しているページをブラウザバックで離れる時にモーダルウィンドウを表示する
  • モーダルウィンドウを表示した後は、モーダルウィンドウ内の「閉じる」をクリックすればブラウザバックの機能が実行され、モーダルウィンドウの背景を触ると元の画面(レイヤー下)に戻る。

サンプルページ

モーダルウィンドウ表示ページを一回クリックして、ブラウザバックすると、モーダルウィンドウが表示される。
https://kaibara.github.io/js-modal/

構造全体はこちら

モーダルウィンドウ実装の注意点

この記事のような仕様だと、モーダルウィンドウの表示によってユーザーが取りたい行動を阻むことになる。
実装するサイトやページによってはSEOの順位が下がる可能性があるため、モーダルウィンドウの仕様だけでなく、サイトやページの仕様についてもよく検討しておく。

モーダルウィンドウで表示する内容(htmlとcss)

html及びcss【jQuery・CSS】意外と簡単!モーダルウィンドウをプラグインなしで作る | WEBDESIGNDAY の内容を参考に作成。

modal.html
<div class="modal js-modal">
    <div class="modal__bg js-modal-close"></div>
    <div class="modal__content">
        <p>モーダルウィンドウテンプレート</p>
        <a class="js-modal-close" href="">閉じる</a>
    </div>
</div>
style.css
.modal{
    display: none;
    height: 100vh;
    position: fixed;
    top: 0;
    width: 100%;
}
.modal__bg{
    background: rgba(0,0,0,0.8);
    height: 100vh;
    position: absolute;
    width: 100%;
}
.modal__content{
    background: #fff;
    left: 50%;
    padding: 40px;
    position: absolute;
    top: 50%;
    transform: translate(-50%,-50%);
    width: 60%;
}

cssは今回の本題ではないため説明は省く。
解説が見たければ参考記事へ。

モーダルウィンドウを表示する(javaScript)

コード全体像

モーダルウィンドウの表示、非表示に関しては【jQuery・CSS】意外と簡単!モーダルウィンドウをプラグインなしで作る | WEBDESIGNDAYを参考に作成。

modai.js
$(function(){

    // どのようにページが読み込まれたかのフラグ
    var backFlg = window.performance.navigation.type;

    // ブラウザバック以外で読み込まれたらのif
    if(backFlg < 1){
        // 履歴に現在のURLを追加保存する
        history.pushState(null,null,location.href);
    }

    //モーダルウィンドウの表示
    $(window).on('popstate', function(event) {
        $(".js-modal").fadeIn();

        // モーダルウィンドウ内閉じるリンクのリンク先変更
        var mLink = document.getElementsByClassName("js-modal-close")
        mLink[1].setAttribute("onClick", "history.back();return false;");

    });

    // モーダルウィンドウの解除
  $('.js-modal-close').on('click',function(){
        $(".js-modal").fadeOut();
        return false;
  });

});

解説

ブラウザバックのチェック

ブラウザバック時にモーダルウィンドウを表示するには、ユーザによるブラウザバックの操作をjavaScriptが検知できるようにする必要がある。
だが、javaScriptではブラウザバックを検知できない。
それなら、ブラウザバックと共に変更されるものを検知すれば良い。

ということで、ブラウザバックと共に変更される物の中で一番わかりやすいであろう、履歴の変更でユーザーのブラウザバックを検知する。
javaScriptでは**popstateイベント**で履歴の変更を検知できる。
ブラウザの「戻る」ボタンをJavascriptで検知するイベント代替案 | Yuta Ihara.com

modal.js
// 履歴に現在のURLを追加保存する
history.pushState(null,null,location.href);

**history.pushState(null,null,location.href);**で履歴に現在のURLを追加する。
pushStateをしないと、popstateで検知できないので欠かさずに記入。

ブラウザバックのボタンを右クリックしてみると、現在のページが2つ重なっている(履歴のと現在表示中ので2つ)のがわかる。
image.png

ここで追加することで、ブラウザバックを押しても、遷移元のページに戻らずにモーダルウィンドウを表示できる

例) A(遷移元) → B(現在のページ)

history.pushState(); がない時
A(遷移元) → B(現在のページ)

Bからブラウザバック → A(遷移元)

history.pushState(); がある時
A(遷移元) → B(現在のページ) → B'(history.pushState();で追加した履歴)

B'からブラウザバック → B(現在のページ)

JavaScriptでURLを操作するメモ - Qiita
Webブラウザの [前へ][次へ] ボタンがクリックされ履歴のページが表示されるイベントを検出する - popStateの利用 : JavaScript | iPentec

どのようにアクセスされたかのチェック

先に「ブラウザバックでどのようにモーダルウィンドウを表示するか」について話したが、その前にあるbackFlgフラグとhistory.pusyState();を囲むif文の解説をしていく。

modal.js
// どのようにページが読み込まれたかのフラグ
var backFlg = window.performance.navigation.type;

window.performance.navigation.typeは、このページがどのように読み込まれたかの値を返す。
他のページからのリンクやブックマークからなら0,再読み込みなら1,ブラウザバックなどの履歴なら2,それ以外なら255の値を返す。
PerformanceNavigation.type - Web API | MDN

modal.js
// ブラウザバック以外で読み込まれたらのif
if(backFlg < 1){
    // 履歴に現在のURLを追加保存する
    history.pushState(null,null,location.href);
}

このif文ではブラウザバック以外、他のページからのリンクや再読み込みでこのページが読み込まれたら、history.pusyState();で履歴を追加するようにしている。
何故このようなif文が必要なのか。

それは、アクセスのされ方でブラウザバックの回数に変化が生じるからだ。
window.performance.navigation.type0が返されるなら、遷移元の上にhistory.pusyState();で履歴が追加されるため、履歴を見ると表示中の物もを含めて、現在のページが2つある状態になる。
image.png
この状態でブラウザバックすれば、同じページのまま履歴だけが変わったのでpopstateが検知し、$(window).on('popstate', function(event) {}の中身が実行される。

なら、window.performance.navigation.type12を返す状態で、history.pusyState();が実行されたらどうなるか。
答えは、表示中のページを含めて履歴にそのページが3つ重なる。
image.png

この画像の状態だと、遷移元ページに戻るのにブラウザバック → モーダルウィンドウ表示の流れを2回繰り返す必要が生まれてしまう。

backFlgとそれを使用したif文によって、history.pusyState();を制御し、どのようなアクセス方法であってもブラウザバックの回数に変化が生じないようにしている。

JavaScript - ブラウザバック を検知したい|teratail

モーダルウィンドウの表示

現在の履歴を追加できたら、addEventListenerpopstateが呼び出されるのを検知して、呼び出された時の機能を追加する。

modal.js
$(".js-modal").fadeIn();

ここは読んだそのまま。該当要素をフェードインさせる。

modal.js
// モーダル内閉じるリンクのリンク先変更
var mLink = document.getElementsByClassName("js-modal-link")
mLink[1].setAttribute("onClick", "history.back();return false;");

「閉じる」リンクのclassを読み取って、閉じるリンクにブラウザバックと同じ機能(履歴のひとつ前のに戻る)を追加する。
setAttributeでのonClickの上書きはhtmlファイル側に書いても問題はないけど、モーダルウィンドウの表示に関するjavaScriptの動きはまとめておきたかったのでこちらに記入。

モーダルウィンドウを閉じる

modal.js
// モーダルウィンドウの解除
$('.js-modal-close').on('click',function(){
  $(".js-modal").fadeOut();
    return false;
});

指定した要素がクリックされたら、fadeIn()同様、fadeOut()で該当要素をフェードアウトさせていく。
js-modal-closeには、aタグ要素も含まれるので、return false;でリンク先に移動しないようにしておく

余談

一回ページをクリックしないとブラウザバックを押してもモーダルウィンドウが表示されないのはなんで…?

参考文献

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?