以前、プラグインなしでローディング画像を表示する方法を紹介しました。この方法では、ローディング画像と同時にオーバーレイを表示するだけでなく、ページ読み込み時の スクロール操作 などを無効にすることも目的でした。ところが、その動作がスマートフォンやタブレット、PCなどのデバイスによってスクロールが出来たり出来なかったりと不安定でした。そこで、この問題を解決する方法を紹介したいと思います。
はじめに
PCの場合は、マウスやキーボードで基本的にはスクロールを行います。
場合によっては、タッチパネル機能を持つディスプレイを接続して操作することもあるでしょう。
以前紹介した方法では、PCのタッチパネルではスクロールの操作はオーバーレイによって無効化されました。
しかし、マウスのホイールやキーボードのカーソルキーによるスクロールの操作は無効化されませんでした。
スマートフォンやタブレットの場合は、マウスやキーボードなどの外部入力が付属していないため、タッチパネルで基本的にはスクロールを行います。
Bluetoothを用いることで、PCと同様にマウスやキーボードを接続して操作することもあるでしょう。
ところが、以前紹介した方法では、マウスのホイールやキーボードのカーソルキーによるスクロールの操作どころか、タッチパネルの操作すら無効化されませんでした。
表.オーバーレイによるスクロール操作の有効/無効
タッチパネル | マウスホイール | カーソルキー | |
PC | 無効 | 有効 | 有効 |
スマートフォン | 有効 | 有効 | 有効 |
タブレット | 有効 | 有効 | 有効 |
上の表のように、オーバーレイによるスクロール操作の無効化は、PC(Let’ note CF-MX4)のタッチパネルのみで、スマートフォンやタブレットでは出来ませんでした。
ページ読み込み時などでタッチパネルやマウスのホイール、キーボードのカーソルの操作を一時的に無効化するには、オーバーレイだけでは不十分です。
これらの操作を一時的に無効にするには、JavaScriptで制御する必要があります。
photo by キイロイトリさん
スクロール操作 の無効化
タッチパネルやマウスのホイール、キーボードの スクロール操作 をJavaScriptで一時的に無効化する場合、以下のサイトを参考にしました。
// left: 37, up: 38, right: 39, down: 40, // spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36 var keys = {37: 1, 38: 1, 39: 1, 40: 1}; function preventDefault(e) { e = e || window.event; if (e.preventDefault) e.preventDefault(); e.returnValue = false; } function preventDefaultForScrollKeys(e) { if (keys[e.keyCode]) { preventDefault(e); return false; } } function disableScroll() { if (window.addEventListener) // older FF window.addEventListener('DOMMouseScroll', preventDefault, false); window.onwheel = preventDefault; // modern standard window.onmousewheel = document.onmousewheel = preventDefault; // older browsers, IE window.ontouchmove = preventDefault; // mobile document.onkeydown = preventDefaultForScrollKeys; } function enableScroll() { if (window.removeEventListener) window.removeEventListener('DOMMouseScroll', preventDefault, false); window.onmousewheel = document.onmousewheel = null; window.onwheel = null; window.ontouchmove = null; document.onkeydown = null; }
残念ながら、私のような初心者では上記のコードを全て理解できないので、具体的にどういう処理をしているかは説明できません。
どうやら、スクロールに関連するマウスやキーボード、タッチパッドの操作をキャンセルすることでスクロールを無効化しているようです。
上記のコードでは、スクロールを無効にしたい場合は関数disableScrollを呼び出し、逆に有効にしたい場合は関数enableScrollを呼び出します。
そこで問題になるのは、関数disableScrollや関数enableScrollをいつ呼び出すかです。
例えば、先述したJavaScriptを外部ファイル化し、HTMLのheader内で下記のように呼び出す場合、幾つかの処理が終了されてからでないと実行されません。
<script> $(function(){ disableScroll(); }); </script>
このため、ページの表示と同時に、スクロールの操作が無効化されることはありませんでした。
また、スクロール操作を有効化するため、HTMLのfooter内で下記のように関数enableScrollを呼び出すとページの読み込みが完全に終わる前にスクロール操作が有効化されてしまいました。
<script> $(function(){ enableScroll(); }); </script>
結果的には、HTMLでheader部分が読み込み始めるとスクロール操作が無効化され、footer部分まで読み込み終わるとスクロール操作が有効化されるので、スクロール操作の無効化時間は一瞬です。
JavaScriptやjQueryで関数を呼び出すタイミングを変えるように下記サイトを参考に上記のJavaScriptコードを修正したのですが、私の能力では上手く出来ませんでした。
ローディング画像表示と同時にスクロール操作の無効化
ローディング画像の表示と同時にスクロール操作を無効にする場合、以前紹介したjQueryを編集すれば実現可能であることが分かりました。
<script type="text/javascript"> $('head').append( // append()内の引数を</head>の手前に追加する '<style type="text/css">#container { display: none; } #fade, #loader { display: block; }</style>' // contanerを表示、loaderを非表示 ); jQuery.event.add(window,"load",function() { // 全ての読み込み完了後に呼ばれる関数 var pageH = $("#container").height(); // containerの高さを取得して、pageHに代入する $("#fade").css("height", pageH).delay(900).fadeOut(800); // pageHで取得したcontainerの高さをfadeの高さに設定、900ms表示後、800ms掛けてフェイドアウト $("#loader").delay(600).fadeOut(300); // 600ms表示後、300ms掛けてフェイドアウト $("#container").css("display", "block"); // containerを表示する }); </script>
上記のコードをloader.jsとして外部から読み込み、その際にマウスやキーボード、タッチパネルによるスクロール操作を無効化するようにします。
マウスやキーボード、タッチパネルを無効化
このため、マウスやキーボード、タッチパネルを無効化するための以下の処理を最初に記述します。
// left: 37, up: 38, right: 39, down: 40, // spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36 var keys = {37: 1, 38: 1, 39: 1, 40: 1}; function preventDefault(e) { e = e || window.event; if (e.preventDefault) e.preventDefault(); e.returnValue = false; } function preventDefaultForScrollKeys(e) { if (keys[e.keyCode]) { preventDefault(e); return false; } } if (window.addEventListener) // older FF window.addEventListener('DOMMouseScroll', preventDefault, false); window.onwheel = preventDefault; // modern standard window.onmousewheel = document.onmousewheel = preventDefault; // older browsers, IE window.ontouchmove = preventDefault; // mobile document.onkeydown = preventDefaultForScrollKeys;
マウスやキーボード、タッチパネルを有効化
次に、jQuery.event.addは画像を全て読み込んでから処理を実行するので、この中に実行したい処理を記入します。
jQuery.event.add(window, "load", function() { // ここに実行したい処理を書く。 });
今回の場合は、画像がすべて表示された後、表示したローディング画像とオーバーレイをフェードアウトするので、その後にマウスやキーボード、タッチパネルによるスクロール操作を有効化するようにします。
if (window.removeEventListener) window.removeEventListener('DOMMouseScroll', preventDefault, false); window.onmousewheel = document.onmousewheel = null; window.onwheel = null; window.ontouchmove = null; document.onkeydown = null;
自分のサイトに合わせた編集
自分のサイトに合わせた編集と言っても、プラグインなしでローディング画像を表示する方法で紹介した自分のサイトのclassやidの編集です。
loader.jsが問題なく動いていれば、スクロール操作の有効・無効を追加するだけなので、特に問題は発生しないと思います。
//left: 37, up: 38, right: 39, down: 40, //spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36 var keys = {37: 1, 38: 1, 39: 1, 40: 1}; function preventDefault(e) { e = e || window.event; if (e.preventDefault) e.preventDefault(); e.returnValue = false; } function preventDefaultForScrollKeys(e) { if (keys[e.keyCode]) { preventDefault(e); return false; } } // スクロール操作の無効化 if (window.addEventListener) // older FF window.addEventListener('DOMMouseScroll', preventDefault, false); window.onwheel = preventDefault; // modern standard window.onmousewheel = document.onmousewheel = preventDefault; // older browsers, IE window.ontouchmove = preventDefault; // mobile document.onkeydown = preventDefaultForScrollKeys; $('head').append( '<style type="text/css">#container-fluid { display: none; } #fade, #loader { display: block; }</style>' ); jQuery.event.add(window,"load",function() { // 全ての読み込み完了後に呼ばれる関数 var pageH = $(".container-fluid").height(); $("#fade").css("height", pageH).delay(900).fadeOut(800); $("#loader").delay(600).fadeOut(300); // スクロール操作の有効化 if (window.removeEventListener) window.removeEventListener('DOMMouseScroll', preventDefault, false); window.onmousewheel = document.onmousewheel = null; window.onwheel = null; window.ontouchmove = null; document.onkeydown = null; });
最後に
以前、プラグインなしでローディング画像を表示する方法を行ったときは、オーバーレイによってマウスやタッチパネルによるリンク先のクリックやタップを無効化することが出来るようになりました。
これによって、ページ読み込み中のタップやクリックの誤操作を防ぐことが出来るようになりました。
しかし、この方法では、一部のタッチパネルを除いて、スクロールの操作を無効化することが出来ませんでした。
スクロールの操作が無効化されていないと、ローディング画像が表示されている間はページの内容が表示されないので、この間にスクロールをすると意図しない部分からページが表示されることになります。
この場合、スクロールした位置によっては、サイト訪問者は再度ページの最初の方までスクロールしないといけないという問題が生じます。
この問題を解決するために、キーボードやマウス、タッチパネルの操作をJavaScriptによって無効化する方法が挙げられます。
Javascriptには、キーボードやマウス、タッチパネルの操作を検出するための以下のイベントハンドラがあります。
- .onkeydown(キーを押した際に発生する、JavaScriptのkeydownとkeypressの違い)
- .onwheel(要素のコンテンツをユーザーがスクロールした際に発生する)
- .onmousewheel(マウス ホイールを回転、ホイールの次のノッチを検出した際に発生する)
- .ontouchmove(タッチスクリーンをタッチして平行移動した際に発生する)
上記のイベントハンドラで操作を検出した際に、検出した値を全てfalseに置き換えることで操作を無効化することを参考サイトを基に試みました。
この結果、今まで出来なかったスクロール操作の無効化が可能になりました。
この副産物として、今まではGoogle Adsenseの広告の一つをページのトップに載せていたので、スクロールを無効化する前はその広告の表示回数が他の広告に比べて半分以下でした。
しかし、ページ読み込み中のスクロールを無効化することで、ページ読み込み終了と同時にページトップが表示されるため、以前よりも他の広告と表示回数が同じか若干少ないというぐらいになり、広告表示回数が増えました。
また、以前は、オーバーレイを半透明にして広告が表示された状態でスクロールを無効化していました。
この場合、訪問者に対して一定時間、強制的に広告を表示することになり、これが規約違反に当たるようでしばらく広告が表示されなくなりました。
このことから、スクロールが無効化されている時、Adsenseの広告が表示される場合は注意が必要です。
一番良いのはオーバーレイを半透明ではなく、不透明にする事だと思います。
ページ読み込み時のローディング画像と不透明のオーバーレイを表示し、その間のスクロール操作を無効にすると、以下のようなメリットがあることが分かりました。
- ページ読み込み中であることを明示することで、訪問者にページ読み込みが完了するまで待機を促すことが出来る。
- ページ読み込み中のクリックやタップ、スクロールの誤操作を防ぐ。
- ページ読み込みが完了するまで操作ができないため、ページ内の広告も全て読み込まれ、広告の表示回数が上がる。
- ページ読み込み完了後、常にページのトップが表示されるため、ページのトップに配置した広告が見逃される回数が減る。
ひょっとしたらページ読み込み中のローディング画像やオーバーレイの表示、その間のデバイスの操作を制限できるプラグインがあるかもしれませんが、プラグインが増えるとサイトの表示速度が遅くなる可能性があります。
このため、今回のような方法を試してみるのも良いかもしれません。
コメント