第10回 jQueryでiPhone風スライドパネルを作ろう

スマートフォン向けのWebサイトでは、「動き」を付けることがよくあります。たとえば、折り畳んでいたパネルをゆっくりと展開したり、ページ全体を左右にスライドさせて切り替えたりと、表示される途中の過程をあえて見せることで、ユーザーに気持ちのいい操作感を与えられます。こうした動きは、JavaScriptを使って実現できます。

 今回から数回にわたって、JavaScriptを使った動きの演出方法を紹介します。

jQueryを使う

 JavaScript開発でいまや欠かせないのがJavaScriptフレームワークです。中でも「jQuery」は非常に人気があり、多くの開発者に利用されています。iPhone/Androidでも利用できますので、本連載でもjQueryを使って動きを表現してみましょう。

 まず、jQueryの最新版のファイルをダウンロードします。


 ダウンロードしたファイルを適当なフォルダ(ここでは「js」としました)にコピーして、HTMLのhead要素内で次のように参照します。ファイル名はバージョン番号などを省いて「jquery.js」に変更しました。

<script type="text/javascript" src="js/jquery.js"></script>

 これでjQueryを利用する準備が整いました。さっそく簡単なサンプルでjQueryの動きを試してみましょう。新しいHTMLファイルを作成し、body要素内に次のようなdiv要素を記述します。

<div id="content">
<p>この文字が徐々に消えます</p>
</div>

 body要素の最後に次のようなscript要素を用意し、jQueryのスクリプトを記述します。

<script type="text/javascript">
$('#content').fadeOut();
</script>

 このHTMLをブラウザーで表示すると、テキストの色が次第に薄くなっていき、真っ白のページに変わります。

 jQueryでは、対象の要素に対して「メソッド」または「イベント」と呼ばれる動作を記述することで、プログラムを作ります。対象の要素は、$('')の中にCSSのセレクターで指定し、$('.class1')とすると「class属性がclass1の要素」になります。ここでは、$('#content')という記述によって「id属性がcontentの要素」を指定しています。

 セレクターで特定した要素に対し、サンプルではfadeOut()というメソッドを指定しています。fadeOut()メソッドはその名の通り「フェードアウトする」という動作を表していて、スタイルシートのopacityプロパティの値を徐々に変更して透明度を上げ、最後にdisplayプロパティの値をnoneにして非表示にします。こうした動作をJavaScriptだけで記述するのはかなり骨が折れますが、jQueryならわずか1行で実現できるわけです。



サンプルを実行するとテキストが次第にフェードアウトしていく

 さらに、fadeOut()メソッドに以下のようにパラメータを与えると、フェードアウトの速度を変更できます。

<script type="text/javascript">
$('#content').fadeOut('slow');
</script>

 jQueryにはこのほかにもfadeIn(フェードインする)、slideIn/slideOut(スライドイン、スライドアウト)など、さまざまなメソッドが用意されていて、いろいろな効果を簡単に与えられます。jQueryについてさらに詳しく知りたい場合は、以下の連載を参考にしてください。

・Web制作の現場で使えるjQuery UIデザイン入門
http://ascii.jp/elem/000/000/438/438206/

左右にスライドするパネルを作る

 jQueryを使ってスマートフォンサイトで活用できる実用的なスクリプトを作成します。最初に作るのは、iPhoneでおなじみの「左右にスライドするパネル」です。

 iPhoneの設定画面で項目を選ぶと、画面が左方向にスライドして、代わりに次の画面が右から表示されます。このとき、画面の上部には左向きの矢印ボタンが表示され、矢印ボタンをタップすると逆には右方向にスライドして元の画面に戻ります。こうしたスライドの動きによって、直感的で分かりやすいUIを実現しています。

iPhoneの「設定」画面。設定項目を選ぶと左にスクロールし、設定画面が表示される。設定画面では矢印ボタンをタップすると逆方向にスクロールして元の画面に戻る

目次部分のHTMLを作成する

 今回は以下のような目次のパネルと、個別記事のパネルをjQueryを使って左右にスライドさせて切り替えます。


左の目次のパネルと右のような記事のパネルをスライドで切り替える

 まず、目次部分のHTMLを用意します。

<div id="index" class="iPhoneBody panel active">
  <div class="iPhoneHead">
    <h1>スライドパネルを作る</h1>
  </div>
  <h2 class="iPhoneListTitle">実践!iPhone&Androidサイト制作ガイド</h2>
  <ul class="iPhoneULIndex">
  <li><a href="#vol09">第9回   CSS+jQueryでクロスデバイスサイトを作ろう</a></li>
  <li><a href="#vol08">第8回   JavaScriptで振り分けてスマホサイト完成!</a></li>
  <li><a href="#vol07">第7回   HTML5/CSS3で作るスマートフォンサイトの基本</a></li>
...
  </ul>  
</div>

 ul/li要素で記事の見出しをマークアップし、各パネルへのリンクをページ内リンクで設定しています。最初のdiv要素のid属性「index」は、目次パネルであることを表し、記事パネルから戻るときに利用します。

 次に、目次パネルにスタイルを適用します。今回は筆者が作成したDreamweaverの拡張機能「iPhone site extension for Dreamweaver CS4/5」のCSSを流用し、iPhoneの標準UIに近いデザインに仕上げました。該当部分のCSSを以下に示します。各CSSのプロパティについては、本連載の第7回を参考にしてください。

.iPhoneBody {
  background-color: #c5ccd3;
}
.iPhoneHead {
  height: 36px;
  padding: 8px 3px 0;
  border-top: 1px solid #cdd5df;
  border-bottom: 1px solid #2d3642;
  background-image: -webkit-gradient(linear, left top, left bottom, from(#b0bccd), to(#6d84a2));
  background-color: #b0bccd;
}
.iPhoneHead h1 {
  font-family: HiraKakuProN-W6;
  font-size: 18px;
  color: #fff;
  text-align: center;
  text-shadow: rgba(0, 0, 0, 0.6) 0 -1px 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.iPhoneListTitle {
  height: 20px;
  line-height: 20px;
  padding: 0px 10px;
  font-family: HiraKakuProN-W6;
  font-size: 14px;
  color: #fff;
  text-shadow: rgba(0, 0, 0, 0.6) 0 -1px 0;
  border-top: 1px solid #a5b1ba;
  border-bottom: 1px solid #989ea4;
  background-image: -webkit-gradient(linear, left top, left bottom, from(#909faa), to(#b8c1c8));
  background-color: #909faa;
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
}
.iPhoneULIndex li {
  border-bottom: solid 1px #d9d9d9;
  overflow: hidden;
  background-color: #fff;
}
.iPhoneULIndex a{
  text-decoration: none;
  color: black;
  -webkit-tap-highlight-color: rgba(2, 109, 236, 0.9);
  display: block;
  padding: 15px 0;
}

 これで以下のような目次ページが完成しました。

スライドパネルの目次部分が完成した

記事パネル部分を作成する

 続いて、目次からリンクしている記事パネルを作成します。記事のパネルは、先ほど作成した目次と同じHTML内につなげて記述します。非常に長いHTMLになりますが、コンテンツを一気に読み込むことでサーバーとの通信頻度を少なくし、パネル間の移動をスムーズにできます。

 記述するHTMLは次のとおりです。内容は自由で構いませんが、パネル全体をdiv要素で囲んで、目次と一致したid属性を付加しておきます。これで、ページ内リンクが機能するようになります。

...
<div id="vol09" class="iPhoneBody panel">
  <div class="iPhoneHead">
    <div class="btnBack" style="width: 3em">
      <div class="btnBackInner"> <a href="#index">戻る</a> </div>
    </div>
    <h1>CSS+jQueryでクロスデバイスサイトを作ろう</h1>
  </div>
  <div class="content">
  <p>WebサイトをiPhone/Androidに最適化するには、PCサイトとは別にスマートフォン専用サイトを用意するのがベストですが、コストや時間などの理由で難しい場合があります。そこで今回は、PC向けのWebサイト(HTML)はそのまま利用し、CSSとJavaScriptだけでレイアウトやデザインを変更する「クロスデバイスサイト」の作り方を説明します。題材は、筆者が制作した「iPhone/Android Webサイト制作出張セミナー」のWebサイトです。</p>
  </div>
  <div class="iPhoneButton"><a href="http://ascii.jp/elem/000/000/561/561127/">続きを読む</a></div>
</div>

<div id="vol08" class="iPhoneBody panel">   <div class="iPhoneHead">     <div class="btnBack" style="width: 3em">       <div class="btnBackInner"> <a href="#index">戻る</a> </div>     </div>     <h1>JavaScriptで振り分けてスマホサイト完成!</h1>   </div>   <div class="content">   <p>スマートフォンサイトの設計・デザイン、HTML5+CSS3による基本的なマークアップについて前回までに解説してきました。今回はページ内の要素にリンクを設定してスマートフォンサイトを仕上げます。</p> ...

 ここまでで以下のような状態になりました。この状態からCSSとJavaScriptでスライドパネルの演出を施していきます。

目次と記事が1ページに続いている状態になる

 目次、記事のすべてのパネルには「panel」というクラスが指定されています。このpanelクラスのCSSを以下のように設定して位置を調整します。

.panel {
  display: none;
  height: 100%;
  width: 100%;
  position: absolute;
}

 positionプロパティにabsoluteを設定して幅と高さに100%をするとパネルが画面いっぱいに表示されるので、すべてのパネルが以下のように重なった状態になります。

 この状態でdisplayプロパティをnoneにしてすべてのパネルをいったん非表示にし、目次パネルだけをdisplay:blockで表示状態に切り替えます。目次パネルには「active」というクラスを設定してあるので、以下のように記述します。

.active {
  display: block;
}

 これで、ページが読み込まれたときに目次パネルだけが表示されるようになりました。

スライドパネルのJavaScriptを作成する

 HTMLとCSSの用意ができたので、いよいよスライドのスクリプトを作成します。スクリプトは以下のようになります。

$(function() {
  var winWidth = window.innerWidth;
  
  /**
   * ページ内リンクのクリックイベント
   */
  $('a[href^=#]').click(function() {  
    if ($(this).attr('href') == '#index') {
        goIndex();
    } else {
      $('#index').animate({
        left: (winWidth * -1) + 'px'
      }, 500, function() { $(this).removeClass('active') });
      
      $($(this).attr('href')).css('left', winWidth).addClass('active').animate({
        left: 0
      }, 500);
      return false;
    }
  });
  /**
   * 戻る
   */
  function goIndex() {
    if ($('div.active').attr('id') == 'index') return false;
  
    $('div.active').animate({
      left: winWidth + 'px'
    }, 500, function() { $(this).removeClass('active'); });
    $('#index').css('left', (winWidth * -1) + 'px').addClass('active').animate({
      left: 0
    }, 500);
  }
});

 前に説明した通り、jQueryを使ったスクリプトでは対象の要素に続けてメソッドやイベントを記述していくのが基本です。まず、7行目に注目します。

$('a[href^=#]').click(function() {
...

 a[href=^#]は、a要素でかつhref属性が「#」から始まる要素、つまりページ内リンクを指定したリンク要素を表します。click()は「クリックされたとき」という意味のイベントですので、ページ内リンクがクリックされたときに{ }内のプログラムが実行されます。

 パネルを動かすプログラムの本体は、11行目からになります。

$('#index').animate({
    left: (winWidth * -1) + 'px'
}, 500, function() { $(this).removeClass('active') });
$($(this).attr('href')).css('left', winWidth).addClass('active').animate({
    left: 0
}, 500);

animate()は、任意のCSSプロパティの値を徐々に変化させて、さまざまなアニメーション効果を表現するメソッドです。ここでは、「id属性がindexの要素」=目次に対して、「leftプロパティを左方向に徐々に変更して左端までずらす」というアニメーションを設定しています。

 画面幅は、あらかじめスクリプトの2行目で取得しています。

var winWidth = window.innerWidth;

 window.innerWidthでは、スマートフォンの端末ごとの画面幅を取得できます。たとえば、iPhoneの画面幅は320pxなので、320×-1=-320pxまでずらすことになります。

 目次パネルのアニメーションが終わったら、removeClass('active') を実行します。class属性から「active」が取り除かれ、目次パネルが非表示になります。

 続いて、以下のプログラムを見ていきます。

$($(this).attr('href')).css('left', winWidth).addClass('active').animate({
    left: 0
}, 500);

 セレクター部分がやや複雑ですが、まずは $(this).attr('href') だけに注目してください。attr()は「属性を取得する」というメソッドで、ここではクリックされたリンクのhref属性(「#vol01」などの文字列)を取得します。前のプログラムを展開すると次のようになります。

$('#vol01').css('left...

 セレクターの対象が分かったので、各メソッドを確認していきましょう。css()メソッドは任意のCSSプロパティの値を変更します。ここでは「leftプロパティを画面の右端に」と指定し、記事パネルを右側に隠しておきます。

addClass()はclass属性を追加するメソッドで、「active」を追加するとdisplay: blockが適用されてパネルが画面に表示されます。最後に、animate()メソッドでleftプロパティを0に変更し、記事パネルを画面の左端に移動させます。

 以上、解説がかなり長くなりましたが、一連のプログラムが同時に実行されることで、以下のようになります。

  1. 目次で項目がタップされる
  2. 目次が徐々に画面左端に消えていく。 同時に記事パネルが右端から現れる
  3. 目次が左端に消えたあと表示が消え、代わりに記事パネルが表示される

 これで、パネルが左にスライドして切り替わったように見えるわけです。

 「戻る」ボタンをタップしたときは逆の動きをします。表示されている記事パネルを右方向に画面幅分だけスライドさせ、目次パネルを左端から表示させます。「戻る」のプログラムは、次のページで紹介するフリック操作で再利用できるように、goIndex()というファンクションにまとめています。

フリックでの移動

 前のページまでの解説でスライドパネルの機能が一通り完成しましたが、今度はスマートフォンならではの操作として、フリック操作でも戻れるようにします。次のようなスクリプトを追加します。

  /**
   * フリックでの戻る
   */
  document.addEventListener("touchstart", start, false);
  document.addEventListener("touchmove", move, false);
  document.addEventListener("touchend", end, false);
  var startX, endX;
  function start() {
    startX = event.touches[0].pageX;
  }
  
  function move(e) {
    endX = event.touches[0].pageX;
  }
  
  function end(e) {
    if (endX - startX > 100) {
      goIndex();
    }
  }

 先ほどclick()イベントを紹介しましたが、スマートフォンには特有のイベントとして「タッチした」「(タッチしたまま)指を動かした」「指を離した」というイベントが用意されています。

 本来は「フリックした」というイベントがあれば簡単なのですが、用意されていないので、複数のイベントを組み合わせて疑似的に「フリックイベント」を作ります。フリック操作を分解すると、次のようなイベントになります。

  • 画面をタッチする
  • そのまま指を右(または左)に動かす
  • 指を離す

 実際のプログラムを分解して見ていきましょう。

 タッチイベントが発生すると、タッチされた地点のX座標を記録します。

function start() {
    startX = event.touches[0].pageX;
}

 プログラムでは指が動くたびにX座標を記録し続けます。

function move(e) {
    endX = event.touches[0].pageX;
}

 指が画面から離れると、最後の位置と最初の位置を比較し、100px以上離れていると「フリックした」とみなします。

function end(e) {
    if (endX - startX > 100) {
        goIndex();
    }
}

 呼び出しているgoIndex()は自作のファンクション(関数)で、前に解説した「目次に戻る」という動作を定義しています。

/**
* 戻る
*/
function goIndex() {
    if ($('div.active').attr('id') == 'index') return false;
        $('div.active').animate({
            left: winWidth + 'px'
        }, 500, function() { $(this).removeClass('active'); });
    $('#index').css('left', (winWidth * -1) + 'px').addClass('active').animate({
        left: 0
    }, 500);
}

 なお、ここで「100px」としている数字は特に決まった数値ではありません。小さな値にすれば敏感に反応するようになり、大きな数字にすれば反応しづらくなります。実際に試しながら最適な数値にチューニングしたり、ユーザーが自由に設定できるようにしたりするとよいでしょう。

 今回紹介したサンプルコードは以下からダウンロードできます。一覧と詳細ページに分かれているニュースやブログ、カタログなど、さまざまなサイトで活用できますので、ぜひ組み込んで試してみてください。

今回作成したサンプルファイル
デモを見る
ダウンロードする(ZIPファイル)

Comments