こんにちは、Webプログラマの篠田です。
多くのサイトで、レスポンシブ対応をされていると思います。
その際に、アコーディオンを利用したコンテンツの見せ方もよく見かけます。
そんな、レスポンシブ対応アコーディオン実装時の罠についてご紹介します。
スマホで「クリックイベント」が、うまく動かない罠
パソコン用Webサイトで、アコーディオンを実装する場合の下記のようにjQueryを記述します。
<script type="text/javascript">
$(function(){
$(document).on('click','セレクタ名',function(){
#アコーディオン処理
});
});
</script>
アコーディオンに関わらず、「クリックイベント」を利用して、何らかの処理を行うことが一般的です。
ですが、スマホで同様の処理を動かそうとすると、うまく動かなかったり、タップしてからアコーディオンが動くまでにタイムラグが発生して動作がぎこちなくなるという現象が発生します。
スマホは「タッチイベント」で動かす
スマホにもクリックイベントは有効ですが、クリックイベントよりも素早く動作するのが「タッチイベント」です。
「タッチイベント」は下記のように記述します。
<script type="text/javascript">
$(function(){
$(document).on('touchend','セレクタ名',function(){
#アコーディオン処理
});
});
</script>
「クリックイベント」では、「click」だったところが「タッチイベント」では「touchend」となります。
「touchend」は「タッチされた後、指を画面から話した時に発生」するイベントを取得して、反応します。
「タッチイベント」は、非タッチデバイス(普通のPC)では反応しませんので、動作しません。
かと言って、「クリックイベント」用と「タッチイベント」用の2種類の処理を記述するのは面倒な上に、タッチデバイスでも「クリックイベント」は認識しますので、2重動作する危険性があります。
タッチデバイスか非タッチデバイスの判別
柔軟な処理としては、タッチデバイスか非タッチデバイスかを判定して、それに応じたイベントを設定するのが望ましいです。
判定する方法は、下記のようなコードを利用します。
var clickEventType = (( window.ontouchstart!==null ) ? 'click':'touchend');
「ontouchstartプロパティ」の有無をみて、タッチデバイスか非タッチデバイスか判定することができます。
これを、先程のコードとあわせると、下記のようになります。
<script type="text/javascript">
$(function(){
var clickEventType = (( window.ontouchstart!==null ) ? 'click':'touchend');
$(document).on(clickEventType,'セレクタ名',function(){
#アコーディオン処理
});
});
</script>
スクロールとタッチイベントの衝突
先程のコードで動いてくれれば、良かったのですが残念ながら思ったとおりの動作はしません。
理由は、タッチデバイスでの「スクロール」にあります。
「スクロール」もタッチデバイス上では「タッチしてから動かし、離す」という動作をします。
これが「touchend」の実行条件になり、「タッチイベント」が動作してしまいます。
タッチデバイスでのスクロールの回避方法
いろいろと方法があるのですが、個人的に分かりやすかったものをご紹介します。
ずばり、「スクロール中は、イベントを実行しない!」と言うものです。
具体的なコードは下記のようになります。
<script type="text/javascript">
$(function(){
var $isScrolling = 0 ;
var $timeoutId ;
$(document).on( "scroll", function () {
$isScrolling = 1 ;
// スクロールを停止して200ms後に終了とする
clearTimeout( $timeoutId );
$timeoutId = setTimeout( function () {
$isScrolling = 0 ;
}, 200 );
});
});
var clickEventType = (( window.ontouchstart!==null ) ? 'click':'touchend');
$(document).on(clickEventType,'セレクタ名',function(){
//スクロールしていないときに、クリックorタッチイベントを実行する
if ($isScrolling === 0) {
#アコーディオン処理
}
});
</script>
このように、「スクロールイベント」を取得してフラグ処理を行い、スクロールしてる間は「タッチイベント」を実行しないとすることで、スクロールとタッチイベントの衝突を回避することができるようになります。
まとめ
1つのHTMLで、スマホとパソコンを同時に処理するレスポンシブ対応独特の問題点をご紹介しました。
「クリックイベント」で、何か動作がおかしいなぁと感じた時は「タッチイベント」を試してみると、うまく解決するかもしれません。
告知
2018年3月9日(金)に、社内セミナー「ALAKI ◯◯ Lab」を開催します。
今回は、広く外部の方も参加できる形式で開催します。
テーマは「非エンジニアでも使いこなせる正規表現の基礎」です。
「Connpass」で受付を行っておりますので、ご興味のある方は、是非ご参加ください。












