knowledge base

マークアップ/フロントエンドエンジニアのWEB制作における備忘録です。平日はWEB屋、休日は社会人劇団の主宰・劇作家をしています。

Android 2.3でスクロールを実装する

Android2.3デフォルトブラウザにはiframeに関連するバグだけでなく、他にもスクロールにまつわるバグがあります。

今回はoverflow:scrollにまつわる現象について、その解決方法をご紹介したいと思います。

要素からあふれた部分を表示するoverflowプロパティ

有名な話ですが、Android2.3でoverflow: hiddenは未対応です したがって要素からあふれた部分は問答無用で非表示になり、大きくユーザビリティを損なってしまいます。

スマートフォン表示時の構成を再考するのが抜本的な解決策ですが、たとえばモーダルウィンドウ内のように限られたスペース内でスクロールさせなければいけない場合も少なくはないでしょう。

そのようなときは、JavaScriptの力を借りれば辛うじて対応が可能です。

touchstart/touchmoveを利用する

幸いなことに、Android 2.3でもtouchイベントには対応しているため、これを利用します。

タッチしたときの位置と、スワイプ中の位置を常に取得することで、疑似的なスクロールを生み出します。

※ここではスクロールさせたい要素(本来ならばoverflow:scrollを指定する要素)に「overflowArea」というIDを付与しています。

var scroll_start_x = 0;
var scroll_start_y = 0;
$('#overflowArea').on({
   'touchstart': function(e) {
      scroll_start_x = e.originalEvent.touches[0].pageX;
      scroll_start_y = e.originalEvent.touches[0].pageY;
   },
   'touchmove': function(e) {
      var scroll_end_x = e.originalEvent.touches[0].pageX;
      var scroll_end_y = e.originalEvent.touches[0].pageY;
      $(this).scrollTop($(this).scrollTop() - (scroll_end_y - scroll_start_y));
      $(this).scrollLeft($(this).scrollLeft() - (scroll_end_x - scroll_start_x));
   }
});

これでスクロールは実装できるのですが、ところが上記のコードだけでは動きがどことなく固くなってしまいます。

どうやらtouchmoveイベントにはクセがあるため、その調整をする必要があります。

こちらの記事で解説されているとおり、連続的に発生すると思われているtouchmoveイベントはAndroidでは一回しか発生しないそうです

 

FFBlog Webサイトでスマホ・タブレットのスワイプ動作(touchmove)イベントを確実に取得するには | 株式会社KSK フレックス・ファームビジネスユニット

 

そこで、もともとのスワイプ動作を抑止する必要があるため、上記コードのtouchmove時の処理を次のように変更します。

var scroll_start_x = 0;
var scroll_start_y = 0;
$('#overflowArea').on({
   'touchstart': function(e) {
      scroll_start_x = e.originalEvent.touches[0].pageX;
      scroll_start_y = e.originalEvent.touches[0].pageY;
   },
   'touchmove': function(e) {
      e.preventDefault();
      var scroll_end_x = e.originalEvent.touches[0].pageX;
      var scroll_end_y = e.originalEvent.touches[0].pageY;
      $(this).scrollTop($(this).scrollTop() - (scroll_end_y - scroll_start_y));
      $(this).scrollLeft($(this).scrollLeft() - (scroll_end_x - scroll_start_x));
   }
});

このようにすることで、スムーズなスクロールが実装可能です。

ちなみにAndroid4からはoverflow:scrollに対応しているため、できればバージョンが4以下のときのみ上記の処理を実行するようにすると、なおよいかと思います。

Androidのユーザーエージェントは以下のとおりなので、ここからバージョンを取得します。

Mozilla/5.0 (Linux; Android 4.4.2; ・・・

Androidという文字列から8文字分取得し、比較演算子によるバージョン比較をしやすいように文字列を数値に変換します。

var ua = navigator.userAgent.toLowerCase(); 
if(ua.indexOf('android') != -1 ){
   var version = parseFloat(ua.slice(ua.indexOf('android')+8));
   if(version < 4){
       return true; 
   }
}

上記コードにおいてtrueを返している箇所に、さきほど紹介した疑似スクロールのコードを書くことで、デバイスのOSバージョンが4以下のときのみスクロールを実装できるようになります。

iScrollは使用しない

最後に余談ですが、iOS4以下で固定表示やスクロールを実装することで有名なiScrollというJavaScriptプラグインがあります。

Android2.3の実機で使用した際にブラウザがクラッシュしてしまったことがあるので、ご利用は自己責任でお願いいたします。