モーダルウィンドウの仕様
- 現在、表示しているページをブラウザバックで離れる時にモーダルウィンドウを表示する
- モーダルウィンドウを表示した後は、モーダルウィンドウ内の「閉じる」をクリックすればブラウザバックの機能が実行され、モーダルウィンドウの背景を触ると元の画面(レイヤー下)に戻る。
サンプルページ
モーダルウィンドウ表示ページを一回クリックして、ブラウザバックすると、モーダルウィンドウが表示される。
https://kaibara.github.io/js-modal/
構造全体はこちら
モーダルウィンドウ実装の注意点
この記事のような仕様だと、モーダルウィンドウの表示によってユーザーが取りたい行動を阻むことになる。
実装するサイトやページによってはSEOの順位が下がる可能性があるため、モーダルウィンドウの仕様だけでなく、サイトやページの仕様についてもよく検討しておく。
モーダルウィンドウで表示する内容(htmlとcss)
html
及びcss
は【jQuery・CSS】意外と簡単!モーダルウィンドウをプラグインなしで作る | WEBDESIGNDAY の内容を参考に作成。
<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>
.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を参考に作成。
$(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
// 履歴に現在のURLを追加保存する
history.pushState(null,null,location.href);
**history.pushState(null,null,location.href);
**で履歴に現在のURLを追加する。
pushState
をしないと、popstate
で検知できないので欠かさずに記入。
ブラウザバックのボタンを右クリックしてみると、現在のページが2つ重なっている(履歴のと現在表示中ので2つ)のがわかる。
ここで追加することで、ブラウザバックを押しても、遷移元のページに戻らずにモーダルウィンドウを表示できる
例) 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文の解説をしていく。
// どのようにページが読み込まれたかのフラグ
var backFlg = window.performance.navigation.type;
window.performance.navigation.type
は、このページがどのように読み込まれたかの値を返す。
他のページからのリンクやブックマークからなら0
,再読み込みなら1
,ブラウザバックなどの履歴なら2
,それ以外なら255
の値を返す。
PerformanceNavigation.type - Web API | MDN
// ブラウザバック以外で読み込まれたらのif
if(backFlg < 1){
// 履歴に現在のURLを追加保存する
history.pushState(null,null,location.href);
}
このif文ではブラウザバック以外、他のページからのリンクや再読み込みでこのページが読み込まれたら、history.pusyState();
で履歴を追加するようにしている。
何故このようなif文が必要なのか。
それは、アクセスのされ方でブラウザバックの回数に変化が生じるからだ。
window.performance.navigation.type
で0
が返されるなら、遷移元の上にhistory.pusyState();
で履歴が追加されるため、履歴を見ると表示中の物もを含めて、現在のページが2つある状態になる。
この状態でブラウザバックすれば、同じページのまま履歴だけが変わったのでpopstate
が検知し、$(window).on('popstate', function(event) {}
の中身が実行される。
なら、window.performance.navigation.type
が1
か2
を返す状態で、history.pusyState();
が実行されたらどうなるか。
答えは、表示中のページを含めて履歴にそのページが3つ重なる。
この画像の状態だと、遷移元ページ
に戻るのにブラウザバック → モーダルウィンドウ表示
の流れを2回繰り返す必要が生まれてしまう。
backFlg
とそれを使用したif文によって、history.pusyState();
を制御し、どのようなアクセス方法であってもブラウザバックの回数に変化が生じないようにしている。
JavaScript - ブラウザバック を検知したい|teratail
モーダルウィンドウの表示
現在の履歴を追加できたら、addEventListener
でpopstate
が呼び出されるのを検知して、呼び出された時の機能を追加する。
$(".js-modal").fadeIn();
ここは読んだそのまま。該当要素をフェードインさせる。
// モーダル内閉じるリンクのリンク先変更
var mLink = document.getElementsByClassName("js-modal-link")
mLink[1].setAttribute("onClick", "history.back();return false;");
「閉じる」リンクのclass
を読み取って、閉じるリンクにブラウザバックと同じ機能(履歴のひとつ前のに戻る)を追加する。
setAttribute
でのonClick
の上書きはhtmlファイル側に書いても問題はないけど、モーダルウィンドウの表示に関するjavaScriptの動きはまとめておきたかったのでこちらに記入。
モーダルウィンドウを閉じる
// モーダルウィンドウの解除
$('.js-modal-close').on('click',function(){
$(".js-modal").fadeOut();
return false;
});
指定した要素がクリックされたら、fadeIn()
同様、fadeOut()
で該当要素をフェードアウトさせていく。
js-modal-close
には、aタグ要素も含まれるので、return false;
でリンク先に移動しないようにしておく
余談
一回ページをクリックしないとブラウザバックを押してもモーダルウィンドウが表示されないのはなんで…?